SpriteNodeMaterial.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import NodeMaterial from './NodeMaterial.js';
  2. import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js';
  3. import { materialRotation } from '../../nodes/accessors/MaterialNode.js';
  4. import { modelViewMatrix, modelWorldMatrix } from '../../nodes/accessors/ModelNode.js';
  5. import { positionGeometry } from '../../nodes/accessors/Position.js';
  6. import { rotate } from '../../nodes/utils/RotateNode.js';
  7. import { float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
  8. import { SpriteMaterial } from '../SpriteMaterial.js';
  9. import { reference } from '../../nodes/accessors/ReferenceBaseNode.js';
  10. const _defaultValues = /*@__PURE__*/ new SpriteMaterial();
  11. /**
  12. * Node material version of `SpriteMaterial`.
  13. *
  14. * @augments NodeMaterial
  15. */
  16. class SpriteNodeMaterial extends NodeMaterial {
  17. static get type() {
  18. return 'SpriteNodeMaterial';
  19. }
  20. /**
  21. * Constructs a new sprite node material.
  22. *
  23. * @param {?Object} parameters - The configuration parameter.
  24. */
  25. constructor( parameters ) {
  26. super();
  27. /**
  28. * This flag can be used for type testing.
  29. *
  30. * @type {boolean}
  31. * @readonly
  32. * @default true
  33. */
  34. this.isSpriteNodeMaterial = true;
  35. this._useSizeAttenuation = true;
  36. /**
  37. * This property makes it possible to define the position of the sprite with a
  38. * node. That can be useful when the material is used with instanced rendering
  39. * and node data are defined with an instanced attribute node:
  40. * ```js
  41. * const positionAttribute = new InstancedBufferAttribute( new Float32Array( positions ), 3 );
  42. * material.positionNode = instancedBufferAttribute( positionAttribute );
  43. * ```
  44. * Another possibility is to compute the instanced data with a compute shader:
  45. * ```js
  46. * const positionBuffer = instancedArray( particleCount, 'vec3' );
  47. * particleMaterial.positionNode = positionBuffer.toAttribute();
  48. * ```
  49. *
  50. * @type {?Node<vec2>}
  51. * @default null
  52. */
  53. this.positionNode = null;
  54. /**
  55. * The rotation of sprite materials is by default inferred from the `rotation`,
  56. * property. This node property allows to overwrite the default and define
  57. * the rotation with a node instead.
  58. *
  59. * If you don't want to overwrite the rotation but modify the existing
  60. * value instead, use {@link materialRotation}.
  61. *
  62. * @type {?Node<float>}
  63. * @default null
  64. */
  65. this.rotationNode = null;
  66. /**
  67. * This node property provides an additional way to scale sprites next to
  68. * `Object3D.scale`. The scale transformation based in `Object3D.scale`
  69. * is multiplied with the scale value of this node in the vertex shader.
  70. *
  71. * @type {?Node<vec2>}
  72. * @default null
  73. */
  74. this.scaleNode = null;
  75. /**
  76. * In Sprites, the transparent property is enabled by default.
  77. *
  78. * @type {boolean}
  79. * @default true
  80. */
  81. this.transparent = true;
  82. this.setDefaultValues( _defaultValues );
  83. this.setValues( parameters );
  84. }
  85. /**
  86. * Setups the position node in view space. This method implements
  87. * the sprite specific vertex shader.
  88. *
  89. * @param {NodeBuilder} builder - The current node builder.
  90. * @return {Node<vec3>} The position in view space.
  91. */
  92. setupPositionView( builder ) {
  93. const { object, camera } = builder;
  94. const sizeAttenuation = this.sizeAttenuation;
  95. const { positionNode, rotationNode, scaleNode } = this;
  96. const mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) );
  97. let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() );
  98. if ( scaleNode !== null ) {
  99. scale = scale.mul( float( scaleNode ) );
  100. }
  101. if ( sizeAttenuation === false ) {
  102. if ( camera.isPerspectiveCamera ) {
  103. scale = scale.mul( mvPosition.z.negate() );
  104. } else {
  105. const orthoScale = float( 2.0 ).div( cameraProjectionMatrix.element( 1 ).element( 1 ) );
  106. scale = scale.mul( orthoScale.mul( 2 ) );
  107. }
  108. }
  109. let alignedPosition = positionGeometry.xy;
  110. if ( object.center && object.center.isVector2 === true ) {
  111. const center = reference( 'center', 'vec2', object );
  112. alignedPosition = alignedPosition.sub( center.sub( 0.5 ) );
  113. }
  114. alignedPosition = alignedPosition.mul( scale );
  115. const rotation = float( rotationNode || materialRotation );
  116. const rotatedPosition = rotate( alignedPosition, rotation );
  117. return vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw );
  118. }
  119. copy( source ) {
  120. this.positionNode = source.positionNode;
  121. this.rotationNode = source.rotationNode;
  122. this.scaleNode = source.scaleNode;
  123. return super.copy( source );
  124. }
  125. /**
  126. * Whether to use size attenuation or not.
  127. *
  128. * @type {boolean}
  129. * @default true
  130. */
  131. get sizeAttenuation() {
  132. return this._useSizeAttenuation;
  133. }
  134. set sizeAttenuation( value ) {
  135. if ( this._useSizeAttenuation !== value ) {
  136. this._useSizeAttenuation = value;
  137. this.needsUpdate = true;
  138. }
  139. }
  140. }
  141. export default SpriteNodeMaterial;
粤ICP备19079148号