SpriteNode.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import {
  2. UniformsLib,
  3. UniformsUtils
  4. } from '../../../../../build/three.module.js';
  5. import { Node } from '../../core/Node.js';
  6. import { ColorNode } from '../../inputs/ColorNode.js';
  7. class SpriteNode extends Node {
  8. constructor() {
  9. super();
  10. this.color = new ColorNode( 0xEEEEEE );
  11. this.spherical = true;
  12. }
  13. build( builder ) {
  14. let output;
  15. builder.define( 'SPRITE' );
  16. builder.requires.lights = false;
  17. builder.requires.transparent = this.alpha !== undefined;
  18. if ( builder.isShader( 'vertex' ) ) {
  19. const position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
  20. builder.mergeUniform( UniformsUtils.merge( [
  21. UniformsLib.fog
  22. ] ) );
  23. builder.addParsCode( /* glsl */`
  24. #include <fog_pars_vertex>
  25. #include <logdepthbuf_pars_vertex>
  26. #include <clipping_planes_pars_vertex>`
  27. );
  28. output = [
  29. '#include <clipping_planes_fragment>',
  30. '#include <begin_vertex>'
  31. ];
  32. if ( position ) {
  33. output.push(
  34. position.code,
  35. position.result ? 'transformed = ' + position.result + ';' : ''
  36. );
  37. }
  38. output.push(
  39. '#include <project_vertex>',
  40. '#include <fog_vertex>',
  41. 'mat4 modelViewMtx = modelViewMatrix;',
  42. 'mat4 modelMtx = modelMatrix;',
  43. // ignore position from modelMatrix (use vary position)
  44. 'modelMtx[3][0] = 0.0;',
  45. 'modelMtx[3][1] = 0.0;',
  46. 'modelMtx[3][2] = 0.0;'
  47. );
  48. if ( ! this.spherical ) {
  49. output.push(
  50. 'modelMtx[1][1] = 1.0;'
  51. );
  52. }
  53. output.push(
  54. // http://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
  55. // First colunm.
  56. 'modelViewMtx[0][0] = 1.0;',
  57. 'modelViewMtx[0][1] = 0.0;',
  58. 'modelViewMtx[0][2] = 0.0;'
  59. );
  60. if ( this.spherical ) {
  61. output.push(
  62. // Second colunm.
  63. 'modelViewMtx[1][0] = 0.0;',
  64. 'modelViewMtx[1][1] = 1.0;',
  65. 'modelViewMtx[1][2] = 0.0;'
  66. );
  67. }
  68. output.push(
  69. // Thrid colunm.
  70. 'modelViewMtx[2][0] = 0.0;',
  71. 'modelViewMtx[2][1] = 0.0;',
  72. 'modelViewMtx[2][2] = 1.0;',
  73. 'gl_Position = projectionMatrix * modelViewMtx * modelMtx * vec4( transformed, 1.0 );',
  74. '#include <logdepthbuf_vertex>',
  75. '#include <clipping_planes_vertex>',
  76. '#include <fog_vertex>'
  77. );
  78. } else {
  79. builder.addParsCode( /* glsl */`
  80. #include <fog_pars_fragment>
  81. #include <logdepthbuf_pars_fragment>
  82. #include <clipping_planes_pars_fragment>`
  83. );
  84. builder.addCode( /* glsl */`
  85. #include <clipping_planes_fragment>
  86. #include <logdepthbuf_fragment>`
  87. );
  88. // analyze all nodes to reuse generate codes
  89. if ( this.mask ) this.mask.analyze( builder );
  90. if ( this.alpha ) this.alpha.analyze( builder );
  91. this.color.analyze( builder, { slot: 'color' } );
  92. // build code
  93. const mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined,
  94. alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined,
  95. color = this.color.flow( builder, 'c', { slot: 'color' } );
  96. output = [];
  97. if ( mask ) {
  98. output.push(
  99. mask.code,
  100. 'if ( ! ' + mask.result + ' ) discard;'
  101. );
  102. }
  103. if ( alpha ) {
  104. output.push(
  105. alpha.code,
  106. '#ifdef ALPHATEST',
  107. 'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
  108. '#endif',
  109. color.code,
  110. 'gl_FragColor = vec4( ' + color.result + ', ' + alpha.result + ' );'
  111. );
  112. } else {
  113. output.push(
  114. color.code,
  115. 'gl_FragColor = vec4( ' + color.result + ', 1.0 );'
  116. );
  117. }
  118. output.push(
  119. '#include <tonemapping_fragment>',
  120. '#include <encodings_fragment>',
  121. '#include <fog_fragment>'
  122. );
  123. }
  124. return output.join( '\n' );
  125. }
  126. copy( source ) {
  127. super.copy( source );
  128. // vertex
  129. if ( source.position ) this.position = source.position;
  130. // fragment
  131. this.color = source.color;
  132. if ( source.spherical !== undefined ) this.spherical = source.spherical;
  133. if ( source.mask ) this.mask = source.mask;
  134. if ( source.alpha ) this.alpha = source.alpha;
  135. return this;
  136. }
  137. toJSON( meta ) {
  138. let data = this.getJSONNode( meta );
  139. if ( ! data ) {
  140. data = this.createJSONNode( meta );
  141. // vertex
  142. if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
  143. // fragment
  144. data.color = this.color.toJSON( meta ).uuid;
  145. if ( this.spherical === false ) data.spherical = false;
  146. if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
  147. if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
  148. }
  149. return data;
  150. }
  151. }
  152. SpriteNode.prototype.nodeType = 'Sprite';
  153. export { SpriteNode };