SpriteNode.js 4.6 KB

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