TextureCubeUVNode.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /**
  2. * @author sunag / http://www.sunag.com.br/
  3. */
  4. import { TempNode } from '../core/TempNode.js';
  5. import { ConstNode } from '../core/ConstNode.js';
  6. import { StructNode } from '../core/StructNode.js';
  7. import { FunctionNode } from '../core/FunctionNode.js';
  8. import { ReflectNode } from '../accessors/ReflectNode.js';
  9. import { FloatNode } from '../inputs/FloatNode.js';
  10. import { BlinnExponentToRoughnessNode } from '../bsdfs/BlinnExponentToRoughnessNode.js';
  11. function TextureCubeUVNode( coord, textureSize, blinnExponentToRoughness ) {
  12. TempNode.call( this, 'TextureCubeUVData' ); // TextureCubeUVData is type as StructNode
  13. this.coord = coord || new ReflectNode( ReflectNode.VECTOR );
  14. this.textureSize = textureSize || new FloatNode( 1024 );
  15. this.blinnExponentToRoughness = this.blinnExponentToRoughness || new BlinnExponentToRoughnessNode();
  16. };
  17. TextureCubeUVNode.Nodes = (function() {
  18. var TextureCubeUVData = new StructNode([
  19. "struct TextureCubeUVData {",
  20. " vec2 uv_10;",
  21. " vec2 uv_20;",
  22. " float t;",
  23. "}"
  24. ].join( "\n" ));
  25. var getFaceFromDirection = new FunctionNode( [
  26. "int getFaceFromDirection(vec3 direction) {",
  27. " vec3 absDirection = abs(direction);",
  28. " int face = -1;",
  29. " if( absDirection.x > absDirection.z ) {",
  30. " if(absDirection.x > absDirection.y )",
  31. " face = direction.x > 0.0 ? 0 : 3;",
  32. " else",
  33. " face = direction.y > 0.0 ? 1 : 4;",
  34. " }",
  35. " else {",
  36. " if(absDirection.z > absDirection.y )",
  37. " face = direction.z > 0.0 ? 2 : 5;",
  38. " else",
  39. " face = direction.y > 0.0 ? 1 : 4;",
  40. " }",
  41. " return face;",
  42. "}"
  43. ].join( "\n" ) );
  44. var cubeUV_maxLods1 = new ConstNode( "#define cubeUV_maxLods1 ( log2( cubeUV_textureSize * 0.25 ) - 1.0 )" );
  45. var cubeUV_rangeClamp = new ConstNode( "#define cubeUV_rangeClamp ( exp2( ( 6.0 - 1.0 ) * 2.0 ) )" );
  46. var MipLevelInfo = new FunctionNode( [
  47. "vec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness, in float cubeUV_textureSize ) {",
  48. " float scale = exp2(cubeUV_maxLods1 - roughnessLevel);",
  49. " float dxRoughness = dFdx(roughness);",
  50. " float dyRoughness = dFdy(roughness);",
  51. " vec3 dx = dFdx( vec * scale * dxRoughness );",
  52. " vec3 dy = dFdy( vec * scale * dyRoughness );",
  53. " float d = max( dot( dx, dx ), dot( dy, dy ) );",
  54. // Clamp the value to the max mip level counts. hard coded to 6 mips"
  55. " d = clamp(d, 1.0, cubeUV_rangeClamp);",
  56. " float mipLevel = 0.5 * log2(d);",
  57. " return vec2(floor(mipLevel), fract(mipLevel));",
  58. "}"
  59. ].join( "\n" ), [ cubeUV_maxLods1, cubeUV_rangeClamp ], { derivatives: true } );
  60. var cubeUV_maxLods2 = new ConstNode( "#define cubeUV_maxLods2 ( log2( cubeUV_textureSize * 0.25 ) - 2.0 )" );
  61. var cubeUV_rcpTextureSize = new ConstNode( "#define cubeUV_rcpTextureSize ( 1.0 / cubeUV_textureSize )" );
  62. var getCubeUV = new FunctionNode( [
  63. "vec2 getCubeUV( vec3 direction, float roughnessLevel, float mipLevel, in float cubeUV_textureSize ) {",
  64. " mipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;",
  65. " float a = 16.0 * cubeUV_rcpTextureSize;",
  66. "",
  67. " vec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );",
  68. " vec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;",
  69. // float powScale = exp2(roughnessLevel + mipLevel);"
  70. " float powScale = exp2_packed.x * exp2_packed.y;",
  71. // float scale = 1.0 / exp2(roughnessLevel + 2.0 + mipLevel);"
  72. " float scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;",
  73. // float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel);"
  74. " float mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;",
  75. "",
  76. " bool bRes = mipLevel == 0.0;",
  77. " scale = bRes && (scale < a) ? a : scale;",
  78. "",
  79. " vec3 r;",
  80. " vec2 offset;",
  81. " int face = getFaceFromDirection(direction);",
  82. "",
  83. " float rcpPowScale = 1.0 / powScale;",
  84. "",
  85. " if( face == 0) {",
  86. " r = vec3(direction.x, -direction.z, direction.y);",
  87. " offset = vec2(0.0+mipOffset,0.75 * rcpPowScale);",
  88. " offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
  89. " }",
  90. " else if( face == 1) {",
  91. " r = vec3(direction.y, direction.x, direction.z);",
  92. " offset = vec2(scale+mipOffset, 0.75 * rcpPowScale);",
  93. " offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
  94. " }",
  95. " else if( face == 2) {",
  96. " r = vec3(direction.z, direction.x, direction.y);",
  97. " offset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);",
  98. " offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
  99. " }",
  100. " else if( face == 3) {",
  101. " r = vec3(direction.x, direction.z, direction.y);",
  102. " offset = vec2(0.0+mipOffset,0.5 * rcpPowScale);",
  103. " offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
  104. " }",
  105. " else if( face == 4) {",
  106. " r = vec3(direction.y, direction.x, -direction.z);",
  107. " offset = vec2(scale+mipOffset, 0.5 * rcpPowScale);",
  108. " offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
  109. " }",
  110. " else {",
  111. " r = vec3(direction.z, -direction.x, direction.y);",
  112. " offset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);",
  113. " offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
  114. " }",
  115. " r = normalize(r);",
  116. " float texelOffset = 0.5 * cubeUV_rcpTextureSize;",
  117. " vec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;",
  118. " vec2 base = offset + vec2( texelOffset );",
  119. " return base + s * ( scale - 2.0 * texelOffset );",
  120. "}"
  121. ].join( "\n" ), [ cubeUV_maxLods2, cubeUV_rcpTextureSize, getFaceFromDirection ] );
  122. var cubeUV_maxLods3 = new ConstNode( "#define cubeUV_maxLods3 ( log2( cubeUV_textureSize * 0.25 ) - 3.0 )" );
  123. var textureCubeUV = new FunctionNode( [
  124. "TextureCubeUVData textureCubeUV( vec3 reflectedDirection, float roughness, in float cubeUV_textureSize ) {",
  125. " float roughnessVal = roughness * cubeUV_maxLods3;",
  126. " float r1 = floor(roughnessVal);",
  127. " float r2 = r1 + 1.0;",
  128. " float t = fract(roughnessVal);",
  129. " vec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness, cubeUV_textureSize);",
  130. " float s = mipInfo.y;",
  131. " float level0 = mipInfo.x;",
  132. " float level1 = level0 + 1.0;",
  133. " level1 = level1 > 5.0 ? 5.0 : level1;",
  134. "",
  135. // round to nearest mipmap if we are not interpolating."
  136. " level0 += min( floor( s + 0.5 ), 5.0 );",
  137. "",
  138. // Tri linear interpolation."
  139. " vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0, cubeUV_textureSize);",
  140. " vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, cubeUV_textureSize);",
  141. "",
  142. " return TextureCubeUVData(uv_10, uv_20, t);",
  143. "}"
  144. ].join( "\n" ), [ TextureCubeUVData, cubeUV_maxLods3, MipLevelInfo, getCubeUV ] );
  145. return {
  146. TextureCubeUVData: TextureCubeUVData,
  147. textureCubeUV: textureCubeUV
  148. };
  149. })();
  150. TextureCubeUVNode.prototype = Object.create( TempNode.prototype );
  151. TextureCubeUVNode.prototype.constructor = TextureCubeUVNode;
  152. TextureCubeUVNode.prototype.nodeType = "TextureCubeUV";
  153. TextureCubeUVNode.prototype.generate = function ( builder, output ) {
  154. if ( builder.isShader( 'fragment' ) ) {
  155. var textureCubeUV = builder.include( TextureCubeUVNode.Nodes.textureCubeUV );
  156. return builder.format( textureCubeUV + '( ' + this.coord.build( builder, 'v3' ) + ', ' +
  157. this.blinnExponentToRoughness.build( builder, 'fv1' ) + ', ' +
  158. this.textureSize.build( builder, 'fv1' ) + ' )', this.getType( builder ), output );
  159. } else {
  160. console.warn( "THREE.TextureCubeUVNode is not compatible with " + builder.shader + " shader." );
  161. return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
  162. }
  163. };
  164. TextureCubeUVNode.prototype.toJSON = function ( meta ) {
  165. var data = this.getJSONNode( meta );
  166. if ( ! data ) {
  167. data = this.createJSONNode( meta );
  168. data.coord = this.coord.toJSON( meta ).uuid;
  169. data.textureSize = this.textureSize.toJSON( meta ).uuid;
  170. data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;
  171. }
  172. return data;
  173. };
  174. export { TextureCubeUVNode };