Spaces:
Running
Running
| /** | |
| * @author sunag / http://www.sunag.com.br/ | |
| */ | |
| import { TempNode } from '../core/TempNode.js'; | |
| import { ConstNode } from '../core/ConstNode.js'; | |
| import { StructNode } from '../core/StructNode.js'; | |
| import { FunctionNode } from '../core/FunctionNode.js'; | |
| import { ReflectNode } from '../accessors/ReflectNode.js'; | |
| import { FloatNode } from '../inputs/FloatNode.js'; | |
| import { BlinnExponentToRoughnessNode } from '../bsdfs/BlinnExponentToRoughnessNode.js'; | |
| function TextureCubeUVNode( uv, textureSize, blinnExponentToRoughness ) { | |
| TempNode.call( this, 'TextureCubeUVData' ); // TextureCubeUVData is type as StructNode | |
| this.uv = uv || new ReflectNode( ReflectNode.VECTOR ); | |
| this.textureSize = textureSize || new FloatNode( 1024 ); | |
| this.blinnExponentToRoughness = blinnExponentToRoughness || new BlinnExponentToRoughnessNode(); | |
| } | |
| TextureCubeUVNode.Nodes = ( function () { | |
| var TextureCubeUVData = new StructNode( [ | |
| "struct TextureCubeUVData {", | |
| " vec2 uv_10;", | |
| " vec2 uv_20;", | |
| " float t;", | |
| "}" | |
| ].join( "\n" ) ); | |
| var getFaceFromDirection = new FunctionNode( [ | |
| "int getFaceFromDirection(vec3 direction) {", | |
| " vec3 absDirection = abs(direction);", | |
| " int face = -1;", | |
| " if( absDirection.x > absDirection.z ) {", | |
| " if(absDirection.x > absDirection.y )", | |
| " face = direction.x > 0.0 ? 0 : 3;", | |
| " else", | |
| " face = direction.y > 0.0 ? 1 : 4;", | |
| " }", | |
| " else {", | |
| " if(absDirection.z > absDirection.y )", | |
| " face = direction.z > 0.0 ? 2 : 5;", | |
| " else", | |
| " face = direction.y > 0.0 ? 1 : 4;", | |
| " }", | |
| " return face;", | |
| "}" | |
| ].join( "\n" ) ); | |
| var cubeUV_maxLods1 = new ConstNode( "#define cubeUV_maxLods1 ( log2( cubeUV_textureSize * 0.25 ) - 1.0 )" ); | |
| var cubeUV_rangeClamp = new ConstNode( "#define cubeUV_rangeClamp ( exp2( ( 6.0 - 1.0 ) * 2.0 ) )" ); | |
| var MipLevelInfo = new FunctionNode( [ | |
| "vec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness, in float cubeUV_textureSize ) {", | |
| " float scale = exp2(cubeUV_maxLods1 - roughnessLevel);", | |
| " float dxRoughness = dFdx(roughness);", | |
| " float dyRoughness = dFdy(roughness);", | |
| " vec3 dx = dFdx( vec * scale * dxRoughness );", | |
| " vec3 dy = dFdy( vec * scale * dyRoughness );", | |
| " float d = max( dot( dx, dx ), dot( dy, dy ) );", | |
| // Clamp the value to the max mip level counts. hard coded to 6 mips" | |
| " d = clamp(d, 1.0, cubeUV_rangeClamp);", | |
| " float mipLevel = 0.5 * log2(d);", | |
| " return vec2(floor(mipLevel), fract(mipLevel));", | |
| "}" | |
| ].join( "\n" ), [ cubeUV_maxLods1, cubeUV_rangeClamp ], { derivatives: true } ); | |
| var cubeUV_maxLods2 = new ConstNode( "#define cubeUV_maxLods2 ( log2( cubeUV_textureSize * 0.25 ) - 2.0 )" ); | |
| var cubeUV_rcpTextureSize = new ConstNode( "#define cubeUV_rcpTextureSize ( 1.0 / cubeUV_textureSize )" ); | |
| var getCubeUV = new FunctionNode( [ | |
| "vec2 getCubeUV( vec3 direction, float roughnessLevel, float mipLevel, in float cubeUV_textureSize ) {", | |
| " mipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;", | |
| " float a = 16.0 * cubeUV_rcpTextureSize;", | |
| "", | |
| " vec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );", | |
| " vec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;", | |
| // float powScale = exp2(roughnessLevel + mipLevel);" | |
| " float powScale = exp2_packed.x * exp2_packed.y;", | |
| // float scale = 1.0 / exp2(roughnessLevel + 2.0 + mipLevel);" | |
| " float scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;", | |
| // float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel);" | |
| " float mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;", | |
| "", | |
| " bool bRes = mipLevel == 0.0;", | |
| " scale = bRes && (scale < a) ? a : scale;", | |
| "", | |
| " vec3 r;", | |
| " vec2 offset;", | |
| " int face = getFaceFromDirection(direction);", | |
| "", | |
| " float rcpPowScale = 1.0 / powScale;", | |
| "", | |
| " if( face == 0) {", | |
| " r = vec3(direction.x, -direction.z, direction.y);", | |
| " offset = vec2(0.0+mipOffset,0.75 * rcpPowScale);", | |
| " offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;", | |
| " }", | |
| " else if( face == 1) {", | |
| " r = vec3(direction.y, direction.x, direction.z);", | |
| " offset = vec2(scale+mipOffset, 0.75 * rcpPowScale);", | |
| " offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;", | |
| " }", | |
| " else if( face == 2) {", | |
| " r = vec3(direction.z, direction.x, direction.y);", | |
| " offset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);", | |
| " offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;", | |
| " }", | |
| " else if( face == 3) {", | |
| " r = vec3(direction.x, direction.z, direction.y);", | |
| " offset = vec2(0.0+mipOffset,0.5 * rcpPowScale);", | |
| " offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;", | |
| " }", | |
| " else if( face == 4) {", | |
| " r = vec3(direction.y, direction.x, -direction.z);", | |
| " offset = vec2(scale+mipOffset, 0.5 * rcpPowScale);", | |
| " offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;", | |
| " }", | |
| " else {", | |
| " r = vec3(direction.z, -direction.x, direction.y);", | |
| " offset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);", | |
| " offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;", | |
| " }", | |
| " r = normalize(r);", | |
| " float texelOffset = 0.5 * cubeUV_rcpTextureSize;", | |
| " vec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;", | |
| " vec2 base = offset + vec2( texelOffset );", | |
| " return base + s * ( scale - 2.0 * texelOffset );", | |
| "}" | |
| ].join( "\n" ), [ cubeUV_maxLods2, cubeUV_rcpTextureSize, getFaceFromDirection ] ); | |
| var cubeUV_maxLods3 = new ConstNode( "#define cubeUV_maxLods3 ( log2( cubeUV_textureSize * 0.25 ) - 3.0 )" ); | |
| var textureCubeUV = new FunctionNode( [ | |
| "TextureCubeUVData textureCubeUV( vec3 reflectedDirection, float roughness, in float cubeUV_textureSize ) {", | |
| " float roughnessVal = roughness * cubeUV_maxLods3;", | |
| " float r1 = floor(roughnessVal);", | |
| " float r2 = r1 + 1.0;", | |
| " float t = fract(roughnessVal);", | |
| " vec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness, cubeUV_textureSize);", | |
| " float s = mipInfo.y;", | |
| " float level0 = mipInfo.x;", | |
| " float level1 = level0 + 1.0;", | |
| " level1 = level1 > 5.0 ? 5.0 : level1;", | |
| "", | |
| // round to nearest mipmap if we are not interpolating." | |
| " level0 += min( floor( s + 0.5 ), 5.0 );", | |
| "", | |
| // Tri linear interpolation." | |
| " vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0, cubeUV_textureSize);", | |
| " vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, cubeUV_textureSize);", | |
| "", | |
| " return TextureCubeUVData(uv_10, uv_20, t);", | |
| "}" | |
| ].join( "\n" ), [ TextureCubeUVData, cubeUV_maxLods3, MipLevelInfo, getCubeUV ] ); | |
| return { | |
| TextureCubeUVData: TextureCubeUVData, | |
| textureCubeUV: textureCubeUV | |
| }; | |
| } )(); | |
| TextureCubeUVNode.prototype = Object.create( TempNode.prototype ); | |
| TextureCubeUVNode.prototype.constructor = TextureCubeUVNode; | |
| TextureCubeUVNode.prototype.nodeType = "TextureCubeUV"; | |
| TextureCubeUVNode.prototype.generate = function ( builder, output ) { | |
| if ( builder.isShader( 'fragment' ) ) { | |
| var textureCubeUV = builder.include( TextureCubeUVNode.Nodes.textureCubeUV ); | |
| return builder.format( textureCubeUV + '( ' + this.uv.build( builder, 'v3' ) + ', ' + | |
| this.blinnExponentToRoughness.build( builder, 'f' ) + ', ' + | |
| this.textureSize.build( builder, 'f' ) + ' )', this.getType( builder ), output ); | |
| } else { | |
| console.warn( "THREE.TextureCubeUVNode is not compatible with " + builder.shader + " shader." ); | |
| return builder.format( 'vec4( 0.0 )', this.getType( builder ), output ); | |
| } | |
| }; | |
| TextureCubeUVNode.prototype.toJSON = function ( meta ) { | |
| var data = this.getJSONNode( meta ); | |
| if ( ! data ) { | |
| data = this.createJSONNode( meta ); | |
| data.uv = this.uv.toJSON( meta ).uuid; | |
| data.textureSize = this.textureSize.toJSON( meta ).uuid; | |
| data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid; | |
| } | |
| return data; | |
| }; | |
| export { TextureCubeUVNode }; | |