WebGLNodeBuilder.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. import NodeBuilder from '../../nodes/core/NodeBuilder.js';
  2. import NodeSlot from '../../nodes/core/NodeSlot.js';
  3. import GLSLNodeParser from '../../nodes/parsers/GLSLNodeParser.js';
  4. import WebGLPhysicalContextNode from './WebGLPhysicalContextNode.js';
  5. import { ShaderChunk, LinearEncoding, RGBAFormat, UnsignedByteType, sRGBEncoding } from 'three';
  6. const shaderStages = [ 'vertex', 'fragment' ];
  7. function getIncludeSnippet( name ) {
  8. return `#include <${name}>`;
  9. }
  10. function getShaderStageProperty( shaderStage ) {
  11. return `${shaderStage}Shader`;
  12. }
  13. class WebGLNodeBuilder extends NodeBuilder {
  14. constructor( object, renderer, shader ) {
  15. super( object, renderer, new GLSLNodeParser() );
  16. this.shader = shader;
  17. this._parseObject();
  18. }
  19. _parseObject() {
  20. const material = this.material;
  21. // parse inputs
  22. if ( material.colorNode && material.colorNode.isNode ) {
  23. this.addSlot( 'fragment', new NodeSlot( material.colorNode, 'COLOR', 'vec4' ) );
  24. }
  25. if ( material.opacityNode && material.opacityNode.isNode ) {
  26. this.addSlot( 'fragment', new NodeSlot( material.opacityNode, 'OPACITY', 'float' ) );
  27. }
  28. if ( material.normalNode && material.normalNode.isNode ) {
  29. this.addSlot( 'fragment', new NodeSlot( material.normalNode, 'NORMAL', 'vec3' ) );
  30. }
  31. if ( material.emissiveNode && material.emissiveNode.isNode ) {
  32. this.addSlot( 'fragment', new NodeSlot( material.emissiveNode, 'EMISSIVE', 'vec3' ) );
  33. }
  34. if ( material.metalnessNode && material.metalnessNode.isNode ) {
  35. this.addSlot( 'fragment', new NodeSlot( material.metalnessNode, 'METALNESS', 'float' ) );
  36. }
  37. if ( material.roughnessNode && material.roughnessNode.isNode ) {
  38. this.addSlot( 'fragment', new NodeSlot( material.roughnessNode, 'ROUGHNESS', 'float' ) );
  39. }
  40. if ( material.clearcoatNode && material.clearcoatNode.isNode ) {
  41. this.addSlot( 'fragment', new NodeSlot( material.clearcoatNode, 'CLEARCOAT', 'float' ) );
  42. }
  43. if ( material.clearcoatRoughnessNode && material.clearcoatRoughnessNode.isNode ) {
  44. this.addSlot( 'fragment', new NodeSlot( material.clearcoatRoughnessNode, 'CLEARCOAT_ROUGHNESS', 'float' ) );
  45. }
  46. if ( material.envNode && material.envNode.isNode ) {
  47. const envRadianceNode = new WebGLPhysicalContextNode( WebGLPhysicalContextNode.RADIANCE, material.envNode );
  48. const envIrradianceNode = new WebGLPhysicalContextNode( WebGLPhysicalContextNode.IRRADIANCE, material.envNode );
  49. this.addSlot( 'fragment', new NodeSlot( envRadianceNode, 'RADIANCE', 'vec3' ) );
  50. this.addSlot( 'fragment', new NodeSlot( envIrradianceNode, 'IRRADIANCE', 'vec3' ) );
  51. }
  52. if ( material.sizeNode && material.sizeNode.isNode ) {
  53. this.addSlot( 'vertex', new NodeSlot( material.sizeNode, 'SIZE', 'float' ) );
  54. }
  55. if ( material.positionNode && material.positionNode.isNode ) {
  56. this.addSlot( 'vertex', new NodeSlot( material.positionNode, 'POSITION', 'vec3' ) );
  57. }
  58. }
  59. getTexture( textureProperty, uvSnippet, biasSnippet = null ) {
  60. if ( biasSnippet !== null ) {
  61. return `texture2D( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
  62. } else {
  63. return `texture2D( ${textureProperty}, ${uvSnippet} )`;
  64. }
  65. }
  66. getCubeTexture( textureProperty, uvSnippet, biasSnippet = null ) {
  67. const textureCube = 'textureCubeLodEXT'; // textureCubeLodEXT textureLod
  68. if ( biasSnippet !== null ) {
  69. return `${textureCube}( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
  70. } else {
  71. return `${textureCube}( ${textureProperty}, ${uvSnippet} )`;
  72. }
  73. }
  74. getUniforms( shaderStage ) {
  75. const uniforms = this.uniforms[ shaderStage ];
  76. let snippet = '';
  77. for ( const uniform of uniforms ) {
  78. if ( uniform.type === 'texture' ) {
  79. snippet += `uniform sampler2D ${uniform.name}; `;
  80. } else if ( uniform.type === 'cubeTexture' ) {
  81. snippet += `uniform samplerCube ${uniform.name}; `;
  82. } else {
  83. const vectorType = this.getVectorType( uniform.type );
  84. snippet += `uniform ${vectorType} ${uniform.name}; `;
  85. }
  86. }
  87. return snippet;
  88. }
  89. getAttributes( shaderStage ) {
  90. let snippet = '';
  91. if ( shaderStage === 'vertex' ) {
  92. const attributes = this.attributes;
  93. for ( let index = 0; index < attributes.length; index ++ ) {
  94. const attribute = attributes[ index ];
  95. // ignore common attributes to prevent redefinitions
  96. if ( attribute.name === 'uv' || attribute.name === 'position' || attribute.name === 'normal' )
  97. continue;
  98. snippet += `attribute ${attribute.type} ${attribute.name}; `;
  99. }
  100. }
  101. return snippet;
  102. }
  103. getVarys( shaderStage ) {
  104. let snippet = '';
  105. const varys = this.varys;
  106. for ( let index = 0; index < varys.length; index ++ ) {
  107. const vary = varys[ index ];
  108. snippet += `varying ${vary.type} ${vary.name}; `;
  109. }
  110. return snippet;
  111. }
  112. addCodeAfterSnippet( shaderStage, snippet, code ) {
  113. const shaderProperty = getShaderStageProperty( shaderStage );
  114. let source = this.shader[ shaderProperty ];
  115. const index = source.indexOf( snippet );
  116. if ( index !== - 1 ) {
  117. const start = source.substring( 0, index + snippet.length );
  118. const end = source.substring( index + snippet.length );
  119. source = `${start}\n${code}\n${end}`;
  120. }
  121. this.shader[ shaderProperty ] = source;
  122. }
  123. addCodeAfterInclude( shaderStage, includeName, code ) {
  124. const includeSnippet = getIncludeSnippet( includeName );
  125. this.addCodeAfterSnippet( shaderStage, includeSnippet, code );
  126. }
  127. replaceCode( shaderStage, source, target ) {
  128. const shaderProperty = getShaderStageProperty( shaderStage );
  129. this.shader[ shaderProperty ] = this.shader[ shaderProperty ].replaceAll( source, target );
  130. }
  131. parseInclude( shaderStage, ...includes ) {
  132. for ( const name of includes ) {
  133. const includeSnippet = getIncludeSnippet( name );
  134. const code = ShaderChunk[ name ];
  135. this.replaceCode( shaderStage, includeSnippet, code );
  136. }
  137. }
  138. getTextureEncodingFromMap( map ) {
  139. const isWebGL2 = this.renderer.capabilities.isWebGL2;
  140. if ( isWebGL2 && map && map.isTexture && map.format === RGBAFormat && map.type === UnsignedByteType && map.encoding === sRGBEncoding ) {
  141. return LinearEncoding; // disable inline decode for sRGB textures in WebGL 2
  142. }
  143. return super.getTextureEncodingFromMap( map );
  144. }
  145. build() {
  146. super.build();
  147. this._addSnippets();
  148. this._buildShader();
  149. return this;
  150. }
  151. _addSnippets() {
  152. this.parseInclude( 'fragment', 'lights_physical_fragment' );
  153. this.addCodeAfterInclude( 'fragment', 'normal_fragment_begin',
  154. `#ifdef NODE_NORMAL
  155. NODE_CODE_NORMAL
  156. normal = NODE_NORMAL;
  157. #endif` );
  158. this.addCodeAfterInclude( 'fragment', 'color_fragment',
  159. `#ifdef NODE_COLOR
  160. NODE_CODE_COLOR
  161. diffuseColor = NODE_COLOR;
  162. #endif` );
  163. this.addCodeAfterInclude( 'fragment', 'alphamap_fragment',
  164. `#ifdef NODE_OPACITY
  165. NODE_CODE_OPACITY
  166. diffuseColor.a *= NODE_OPACITY;
  167. #endif` );
  168. this.addCodeAfterInclude( 'fragment', 'emissivemap_fragment',
  169. `#ifdef NODE_EMISSIVE
  170. NODE_CODE_EMISSIVE
  171. totalEmissiveRadiance = NODE_EMISSIVE;
  172. #endif` );
  173. this.addCodeAfterInclude( 'fragment', 'roughnessmap_fragment',
  174. `#ifdef NODE_ROUGHNESS
  175. NODE_CODE_ROUGHNESS
  176. roughnessFactor = NODE_ROUGHNESS;
  177. #endif` );
  178. this.addCodeAfterInclude( 'fragment', 'metalnessmap_fragment',
  179. `#ifdef NODE_METALNESS
  180. NODE_CODE_METALNESS
  181. metalnessFactor = NODE_METALNESS;
  182. #endif` );
  183. this.addCodeAfterSnippet( 'fragment', 'material.clearcoatRoughness = clearcoatRoughness;',
  184. `#ifdef NODE_CLEARCOAT
  185. NODE_CODE_CLEARCOAT
  186. material.clearcoat = NODE_CLEARCOAT;
  187. #endif
  188. #ifdef NODE_CLEARCOAT_ROUGHNESS
  189. NODE_CODE_CLEARCOAT_ROUGHNESS
  190. material.clearcoatRoughness = NODE_CLEARCOAT_ROUGHNESS;
  191. #endif` );
  192. this.addCodeAfterInclude( 'fragment', 'lights_fragment_begin',
  193. `#ifdef NODE_RADIANCE
  194. NODE_CODE_RADIANCE
  195. radiance += NODE_RADIANCE;
  196. NODE_CODE_IRRADIANCE
  197. iblIrradiance += PI * NODE_IRRADIANCE;
  198. #endif` );
  199. this.addCodeAfterInclude( 'vertex', 'begin_vertex',
  200. `#ifdef NODE_POSITION
  201. NODE_CODE_POSITION
  202. transformed = NODE_POSITION;
  203. #endif` );
  204. this.addCodeAfterSnippet( 'vertex', 'gl_PointSize = size;',
  205. `#ifdef NODE_SIZE
  206. NODE_CODE_SIZE
  207. gl_PointSize = NODE_SIZE;
  208. #endif` );
  209. for ( const shaderStage of shaderStages ) {
  210. this.addCodeAfterSnippet( shaderStage, 'main() {',
  211. `#ifdef NODE_CODE
  212. NODE_CODE
  213. #endif` );
  214. }
  215. }
  216. _buildShader() {
  217. for ( const shaderStage of shaderStages ) {
  218. // uniforms
  219. for ( const uniform of this.uniforms[ shaderStage ] ) {
  220. this.shader.uniforms[ uniform.name ] = uniform;
  221. }
  222. // code
  223. const shaderProperty = getShaderStageProperty( shaderStage );
  224. const nodeCode = this[ shaderProperty ];
  225. this.shader[ shaderProperty ] = nodeCode + this.shader[ shaderProperty ];
  226. }
  227. }
  228. }
  229. export { WebGLNodeBuilder };