@openhps/core
Version:
Open Hybrid Positioning System - Core component
125 lines (118 loc) • 4.63 kB
JavaScript
import Node from '../core/Node.js';
import { getValueType } from '../core/NodeUtils.js';
import { buffer } from '../accessors/BufferNode.js';
import { instancedBufferAttribute } from '../accessors/BufferAttributeNode.js';
import { instanceIndex } from '../core/IndexNode.js';
import { nodeProxy, float } from '../tsl/TSLBase.js';
import { Vector4 } from '../../math/Vector4.js';
import { MathUtils } from '../../math/MathUtils.js';
import { InstancedBufferAttribute } from '../../core/InstancedBufferAttribute.js';
let min = null;
let max = null;
/**
* `RangeNode` generates random instanced attribute data in a defined range.
* An exemplary use case for this utility node is to generate random per-instance
* colors:
* ```js
* const material = new MeshBasicNodeMaterial();
* material.colorNode = range( new Color( 0x000000 ), new Color( 0xFFFFFF ) );
* const mesh = new InstancedMesh( geometry, material, count );
* ```
* @augments Node
*/
class RangeNode extends Node {
static get type() {
return 'RangeNode';
}
/**
* Constructs a new range node.
*
* @param {Node<any>} [minNode=float()] - A node defining the lower bound of the range.
* @param {Node<any>} [maxNode=float()] - A node defining the upper bound of the range.
*/
constructor(minNode = float(), maxNode = float()) {
super();
/**
* A node defining the lower bound of the range.
*
* @type {Node<any>}
* @default float()
*/
this.minNode = minNode;
/**
* A node defining the upper bound of the range.
*
* @type {Node<any>}
* @default float()
*/
this.maxNode = maxNode;
}
/**
* Returns the vector length which is computed based on the range definition.
*
* @param {NodeBuilder} builder - The current node builder.
* @return {number} The vector length.
*/
getVectorLength(builder) {
const minLength = builder.getTypeLength(getValueType(this.minNode.value));
const maxLength = builder.getTypeLength(getValueType(this.maxNode.value));
return minLength > maxLength ? minLength : maxLength;
}
/**
* This method is overwritten since the node type is inferred from range definition.
*
* @param {NodeBuilder} builder - The current node builder.
* @return {string} The node type.
*/
getNodeType(builder) {
return builder.object.count > 1 ? builder.getTypeFromLength(this.getVectorLength(builder)) : 'float';
}
setup(builder) {
const object = builder.object;
let output = null;
if (object.count > 1) {
const minValue = this.minNode.value;
const maxValue = this.maxNode.value;
const minLength = builder.getTypeLength(getValueType(minValue));
const maxLength = builder.getTypeLength(getValueType(maxValue));
min = min || new Vector4();
max = max || new Vector4();
min.setScalar(0);
max.setScalar(0);
if (minLength === 1) min.setScalar(minValue);else if (minValue.isColor) min.set(minValue.r, minValue.g, minValue.b, 1);else min.set(minValue.x, minValue.y, minValue.z || 0, minValue.w || 0);
if (maxLength === 1) max.setScalar(maxValue);else if (maxValue.isColor) max.set(maxValue.r, maxValue.g, maxValue.b, 1);else max.set(maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0);
const stride = 4;
const length = stride * object.count;
const array = new Float32Array(length);
for (let i = 0; i < length; i++) {
const index = i % stride;
const minElementValue = min.getComponent(index);
const maxElementValue = max.getComponent(index);
array[i] = MathUtils.lerp(minElementValue, maxElementValue, Math.random());
}
const nodeType = this.getNodeType(builder);
if (object.count <= 4096) {
output = buffer(array, 'vec4', object.count).element(instanceIndex).convert(nodeType);
} else {
// TODO: Improve anonymous buffer attribute creation removing this part
const bufferAttribute = new InstancedBufferAttribute(array, 4);
builder.geometry.setAttribute('__range' + this.id, bufferAttribute);
output = instancedBufferAttribute(bufferAttribute).convert(nodeType);
}
} else {
output = float(0);
}
return output;
}
}
export default RangeNode;
/**
* TSL function for creating a range node.
*
* @tsl
* @function
* @param {Node<any>} [minNode=float()] - A node defining the lower bound of the range.
* @param {Node<any>} [maxNode=float()] - A node defining the upper bound of the range.
* @returns {RangeNode}
*/
export const range = /*@__PURE__*/nodeProxy(RangeNode).setParameterLength(2);