RangeNode.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import Node, { addNodeClass } from '../core/Node.js';
  2. import { getValueType } from '../core/NodeUtils.js';
  3. import { buffer } from '../accessors/BufferNode.js';
  4. import { instancedBufferAttribute } from '../accessors/BufferAttributeNode.js';
  5. import { instanceIndex } from '../core/IndexNode.js';
  6. import { nodeProxy, float } from '../shadernode/ShaderNode.js';
  7. import { Vector4, MathUtils, InstancedBufferAttribute } from 'three';
  8. let min = null;
  9. let max = null;
  10. class RangeNode extends Node {
  11. constructor( minNode = float(), maxNode = float() ) {
  12. super();
  13. this.minNode = minNode;
  14. this.maxNode = maxNode;
  15. }
  16. getVectorLength( builder ) {
  17. const minLength = builder.getTypeLength( getValueType( this.minNode.value ) );
  18. const maxLength = builder.getTypeLength( getValueType( this.maxNode.value ) );
  19. return minLength > maxLength ? minLength : maxLength;
  20. }
  21. getNodeType( builder ) {
  22. return builder.object.count > 1 ? builder.getTypeFromLength( this.getVectorLength( builder ) ) : 'float';
  23. }
  24. setup( builder ) {
  25. const object = builder.object;
  26. let output = null;
  27. if ( object.count > 1 ) {
  28. const minValue = this.minNode.value;
  29. const maxValue = this.maxNode.value;
  30. const minLength = builder.getTypeLength( getValueType( minValue ) );
  31. const maxLength = builder.getTypeLength( getValueType( maxValue ) );
  32. min = min || new Vector4();
  33. max = max || new Vector4();
  34. min.setScalar( 0 );
  35. max.setScalar( 0 );
  36. if ( minLength === 1 ) min.setScalar( minValue );
  37. else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b );
  38. else min.set( minValue.x, minValue.y, minValue.z || 0, minValue.w || 0 );
  39. if ( maxLength === 1 ) max.setScalar( maxValue );
  40. else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b );
  41. else max.set( maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0 );
  42. const stride = 4;
  43. const length = stride * object.count;
  44. const array = new Float32Array( length );
  45. for ( let i = 0; i < length; i ++ ) {
  46. const index = i % stride;
  47. const minElementValue = min.getComponent( index );
  48. const maxElementValue = max.getComponent( index );
  49. array[ i ] = MathUtils.lerp( minElementValue, maxElementValue, Math.random() );
  50. }
  51. const nodeType = this.getNodeType( builder );
  52. if ( object.count <= 4096 ) {
  53. output = buffer( array, 'vec4', object.count ).element( instanceIndex ).convert( nodeType );
  54. } else {
  55. // TODO: Improve anonymous buffer attribute creation removing this part
  56. const bufferAttribute = new InstancedBufferAttribute( array, 4 );
  57. builder.geometry.setAttribute( '__range' + this.id, bufferAttribute );
  58. output = instancedBufferAttribute( bufferAttribute ).convert( nodeType );
  59. }
  60. } else {
  61. output = float( 0 );
  62. }
  63. return output;
  64. }
  65. }
  66. export default RangeNode;
  67. export const range = nodeProxy( RangeNode );
  68. addNodeClass( 'RangeNode', RangeNode );