|
@@ -6,157 +6,157 @@ 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 { FunctionCallNode } from '../core/FunctionCallNode.js';
|
|
|
+import { ExpressionNode } from '../core/ExpressionNode.js';
|
|
|
+import { FloatNode } from '../inputs/FloatNode.js';
|
|
|
+import { OperatorNode } from '../math/OperatorNode.js';
|
|
|
+import { MathNode } from '../math/MathNode.js';
|
|
|
+import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
|
|
|
|
|
|
-function TextureCubeUVNode( uv, textureSize, bias ) {
|
|
|
+function TextureCubeUVNode( value, uv, bias ) {
|
|
|
|
|
|
- TempNode.call( this, 'TextureCubeUVData' ); // TextureCubeUVData is type as StructNode
|
|
|
+ TempNode.call( this, 'v4' );
|
|
|
|
|
|
+ this.value = value,
|
|
|
this.uv = uv;
|
|
|
- this.textureSize = textureSize;
|
|
|
this.bias = bias;
|
|
|
|
|
|
}
|
|
|
|
|
|
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 ] );
|
|
|
+ var TextureCubeUVData = new StructNode(
|
|
|
+ `struct TextureCubeUVData {
|
|
|
+ vec4 tl;
|
|
|
+ vec4 tr;
|
|
|
+ vec4 br;
|
|
|
+ vec4 bl;
|
|
|
+ vec2 f;
|
|
|
+ }` );
|
|
|
+
|
|
|
+ var cubeUV_maxMipLevel = new ConstNode( `float cubeUV_maxMipLevel 8.0`, true );
|
|
|
+ var cubeUV_minMipLevel = new ConstNode( `float cubeUV_minMipLevel 4.0`, true );
|
|
|
+ var cubeUV_maxTileSize = new ConstNode( `float cubeUV_maxTileSize 256.0`, true );
|
|
|
+ var cubeUV_minTileSize = new ConstNode( `float cubeUV_minTileSize 16.0`, true );
|
|
|
+
|
|
|
+ // These shader functions convert between the UV coordinates of a single face of
|
|
|
+ // a cubemap, the 0-5 integer index of a cube face, and the direction vector for
|
|
|
+ // sampling a textureCube (not generally normalized).
|
|
|
+
|
|
|
+ var getFace = new FunctionNode(
|
|
|
+ `float getFace(vec3 direction) {
|
|
|
+ vec3 absDirection = abs(direction);
|
|
|
+ float face = -1.0;
|
|
|
+ if (absDirection.x > absDirection.z) {
|
|
|
+ if (absDirection.x > absDirection.y)
|
|
|
+ face = direction.x > 0.0 ? 0.0 : 3.0;
|
|
|
+ else
|
|
|
+ face = direction.y > 0.0 ? 1.0 : 4.0;
|
|
|
+ } else {
|
|
|
+ if (absDirection.z > absDirection.y)
|
|
|
+ face = direction.z > 0.0 ? 2.0 : 5.0;
|
|
|
+ else
|
|
|
+ face = direction.y > 0.0 ? 1.0 : 4.0;
|
|
|
+ }
|
|
|
+ return face;
|
|
|
+ }` );
|
|
|
+ getFace.useKeywords = false;
|
|
|
+
|
|
|
+ var getUV = new FunctionNode(
|
|
|
+ `vec2 getUV(vec3 direction, float face) {
|
|
|
+ vec2 uv;
|
|
|
+ if (face == 0.0) {
|
|
|
+ uv = vec2(-direction.z, direction.y) / abs(direction.x);
|
|
|
+ } else if (face == 1.0) {
|
|
|
+ uv = vec2(direction.x, -direction.z) / abs(direction.y);
|
|
|
+ } else if (face == 2.0) {
|
|
|
+ uv = direction.xy / abs(direction.z);
|
|
|
+ } else if (face == 3.0) {
|
|
|
+ uv = vec2(direction.z, direction.y) / abs(direction.x);
|
|
|
+ } else if (face == 4.0) {
|
|
|
+ uv = direction.xz / abs(direction.y);
|
|
|
+ } else {
|
|
|
+ uv = vec2(-direction.x, direction.y) / abs(direction.z);
|
|
|
+ }
|
|
|
+ return 0.5 * (uv + 1.0);
|
|
|
+ }` );
|
|
|
+ getUV.useKeywords = false;
|
|
|
+
|
|
|
+ var bilinearCubeUV = new FunctionNode(
|
|
|
+ `TextureCubeUVData bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {
|
|
|
+ float face = getFace(direction);
|
|
|
+ float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0);
|
|
|
+ mipInt = max(mipInt, cubeUV_minMipLevel);
|
|
|
+ float faceSize = exp2(mipInt);
|
|
|
+ float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize);
|
|
|
+ vec2 uv = getUV(direction, face) * (faceSize - 1.0);
|
|
|
+ vec2 f = fract(uv);
|
|
|
+ uv += 0.5 - f;
|
|
|
+ if (face > 2.0) {
|
|
|
+ uv.y += faceSize;
|
|
|
+ face -= 3.0;
|
|
|
+ }
|
|
|
+ uv.x += face * faceSize;
|
|
|
+ if(mipInt < cubeUV_maxMipLevel){
|
|
|
+ uv.y += 2.0 * cubeUV_maxTileSize;
|
|
|
+ }
|
|
|
+ uv.y += filterInt * 2.0 * cubeUV_minTileSize;
|
|
|
+ uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize);
|
|
|
+ uv *= texelSize;
|
|
|
+ vec4 tl = texture2D(envMap, uv);
|
|
|
+ uv.x += texelSize;
|
|
|
+ vec4 tr = texture2D(envMap, uv);
|
|
|
+ uv.y += texelSize;
|
|
|
+ vec4 br = texture2D(envMap, uv);
|
|
|
+ uv.x -= texelSize;
|
|
|
+ vec4 bl = texture2D(envMap, uv);
|
|
|
+
|
|
|
+ return TextureCubeUVData( tl, tr, br, bl, f );
|
|
|
+ }`, [ TextureCubeUVData, getFace, getUV, cubeUV_maxMipLevel, cubeUV_minMipLevel, cubeUV_maxTileSize, cubeUV_minTileSize ] );
|
|
|
+ bilinearCubeUV.useKeywords = false;
|
|
|
+
|
|
|
+ // These defines must match with PMREMGenerator
|
|
|
+
|
|
|
+ var r0 = new ConstNode( `float r0 1.0`, true );
|
|
|
+ var v0 = new ConstNode( `float v0 0.339`, true );
|
|
|
+ var m0 = new ConstNode( `float m0 -2.0`, true );
|
|
|
+ var r1 = new ConstNode( `float r1 0.8`, true );
|
|
|
+ var v1 = new ConstNode( `float v1 0.276`, true );
|
|
|
+ var m1 = new ConstNode( `float m1 -1.0`, true );
|
|
|
+ var r4 = new ConstNode( `float r4 0.4`, true );
|
|
|
+ var v4 = new ConstNode( `float v4 0.046`, true );
|
|
|
+ var m4 = new ConstNode( `float m4 2.0`, true );
|
|
|
+ var r5 = new ConstNode( `float r5 0.305`, true );
|
|
|
+ var v5 = new ConstNode( `float v5 0.016`, true );
|
|
|
+ var m5 = new ConstNode( `float m5 3.0`, true );
|
|
|
+ var r6 = new ConstNode( `float r6 0.21`, true );
|
|
|
+ var v6 = new ConstNode( `float v6 0.0038`, true );
|
|
|
+ var m6 = new ConstNode( `float m6 4.0`, true );
|
|
|
+
|
|
|
+ var defines = [ r0, v0, m0, r1, v1, m1, r4, v4, m4, r5, v5, m5, r6, v6, m6 ];
|
|
|
+
|
|
|
+ var roughnessToMip = new FunctionNode(
|
|
|
+ `float roughnessToMip(float roughness) {
|
|
|
+ float mip = 0.0;
|
|
|
+ if (roughness >= r1) {
|
|
|
+ mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0;
|
|
|
+ } else if (roughness >= r4) {
|
|
|
+ mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1;
|
|
|
+ } else if (roughness >= r5) {
|
|
|
+ mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4;
|
|
|
+ } else if (roughness >= r6) {
|
|
|
+ mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5;
|
|
|
+ } else {
|
|
|
+ mip = -2.0 * log2(1.16 * roughness);// 1.16 = 1.79^0.25
|
|
|
+ }
|
|
|
+ return mip;
|
|
|
+ }`, defines );
|
|
|
|
|
|
return {
|
|
|
- TextureCubeUVData: TextureCubeUVData,
|
|
|
- textureCubeUV: textureCubeUV
|
|
|
+ bilinearCubeUV: bilinearCubeUV,
|
|
|
+ roughnessToMip: roughnessToMip,
|
|
|
+ m0: m0,
|
|
|
+ cubeUV_maxMipLevel: cubeUV_maxMipLevel
|
|
|
};
|
|
|
|
|
|
} )();
|
|
@@ -165,17 +165,90 @@ TextureCubeUVNode.prototype = Object.create( TempNode.prototype );
|
|
|
TextureCubeUVNode.prototype.constructor = TextureCubeUVNode;
|
|
|
TextureCubeUVNode.prototype.nodeType = "TextureCubeUV";
|
|
|
|
|
|
+TextureCubeUVNode.prototype.bilinearCubeUV = function ( builder, texture, uv, mipInt ) {
|
|
|
+
|
|
|
+ var bilinearCubeUV = new FunctionCallNode( TextureCubeUVNode.Nodes.bilinearCubeUV, [ texture, uv, mipInt ] );
|
|
|
+
|
|
|
+ this.colorSpaceTL = this.colorSpaceTL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
|
|
|
+ this.colorSpaceTL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
|
|
|
+ this.colorSpaceTL.input.parse( bilinearCubeUV.build( builder ) + '.tl' );
|
|
|
+
|
|
|
+ this.colorSpaceTR = this.colorSpaceTR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
|
|
|
+ this.colorSpaceTR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
|
|
|
+ this.colorSpaceTR.input.parse( bilinearCubeUV.build( builder ) + '.tr' );
|
|
|
+
|
|
|
+ this.colorSpaceBL = this.colorSpaceBL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
|
|
|
+ this.colorSpaceBL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
|
|
|
+ this.colorSpaceBL.input.parse( bilinearCubeUV.build( builder ) + '.bl' );
|
|
|
+
|
|
|
+ this.colorSpaceBR = this.colorSpaceBR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
|
|
|
+ this.colorSpaceBR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
|
|
|
+ this.colorSpaceBR.input.parse( bilinearCubeUV.build( builder ) + '.br' );
|
|
|
+
|
|
|
+ // add a custom context for fix incompatibility with the core
|
|
|
+ // include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
|
|
|
+ // this should be removed in the future
|
|
|
+ // context.include =: is used to include or not functions if used FunctionNode
|
|
|
+ // context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
|
|
|
+ var context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
|
|
|
+
|
|
|
+ builder.addContext( context );
|
|
|
+
|
|
|
+ this.colorSpaceTLExp = new ExpressionNode( this.colorSpaceTL.build( builder, 'v4' ), 'v4' );
|
|
|
+ this.colorSpaceTRExp = new ExpressionNode( this.colorSpaceTR.build( builder, 'v4' ), 'v4' );
|
|
|
+ this.colorSpaceBLExp = new ExpressionNode( this.colorSpaceBL.build( builder, 'v4' ), 'v4' );
|
|
|
+ this.colorSpaceBRExp = new ExpressionNode( this.colorSpaceBR.build( builder, 'v4' ), 'v4' );
|
|
|
+
|
|
|
+ // end custom context
|
|
|
+
|
|
|
+ builder.removeContext();
|
|
|
+
|
|
|
+ // --
|
|
|
+
|
|
|
+ var output = new ExpressionNode( `mix( mix( cubeUV_TL, cubeUV_TR, cubeUV.f.x ), mix( cubeUV_BL, cubeUV_BR, cubeUV.f.x ), cubeUV.f.y )`, 'v4' );
|
|
|
+ output.keywords[ 'cubeUV_TL' ] = this.colorSpaceTLExp;
|
|
|
+ output.keywords[ 'cubeUV_TR' ] = this.colorSpaceTRExp;
|
|
|
+ output.keywords[ 'cubeUV_BL' ] = this.colorSpaceBLExp;
|
|
|
+ output.keywords[ 'cubeUV_BR' ] = this.colorSpaceBRExp;
|
|
|
+ output.keywords[ 'cubeUV' ] = bilinearCubeUV;
|
|
|
+
|
|
|
+ return output;
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
TextureCubeUVNode.prototype.generate = function ( builder, output ) {
|
|
|
|
|
|
if ( builder.isShader( 'fragment' ) ) {
|
|
|
|
|
|
- var textureCubeUV = builder.include( TextureCubeUVNode.Nodes.textureCubeUV );
|
|
|
+ var uv = this.uv;
|
|
|
+ var bias = this.bias || builder.context.roughness;
|
|
|
+
|
|
|
+ var mipV = new FunctionCallNode( TextureCubeUVNode.Nodes.roughnessToMip, [ bias ] );
|
|
|
+ var mip = new MathNode( mipV, TextureCubeUVNode.Nodes.m0, TextureCubeUVNode.Nodes.cubeUV_maxMipLevel, MathNode.CLAMP );
|
|
|
+ var mipInt = new MathNode( mip, MathNode.FLOOR );
|
|
|
+ var mipF = new MathNode( mip, MathNode.FRACT );
|
|
|
+
|
|
|
+ var color0 = this.bilinearCubeUV( builder, this.value, uv, mipInt );
|
|
|
+ var color1 = this.bilinearCubeUV( builder, this.value, uv, new OperatorNode(
|
|
|
+ mipInt,
|
|
|
+ new FloatNode( 1 ).setReadonly( true ),
|
|
|
+ OperatorNode.ADD
|
|
|
+ ) );
|
|
|
+
|
|
|
+ var color1Mix = new MathNode( color0, color1, mipF, MathNode.MIX );
|
|
|
|
|
|
- var biasNode = this.bias || builder.context.roughness;
|
|
|
+ /*
|
|
|
+ // TODO: Optimize this in the future
|
|
|
+ var cond = new CondNode(
|
|
|
+ mipF,
|
|
|
+ new FloatNode( 0 ).setReadonly( true ),
|
|
|
+ CondNode.EQUAL,
|
|
|
+ color0, // if
|
|
|
+ color1Mix // else
|
|
|
+ );
|
|
|
+ */
|
|
|
|
|
|
- return builder.format( textureCubeUV + '( ' + this.uv.build( builder, 'v3' ) + ', ' +
|
|
|
- biasNode.build( builder, 'f' ) + ', ' +
|
|
|
- this.textureSize.build( builder, 'f' ) + ' )', this.getType( builder ), output );
|
|
|
+ return builder.format( color1Mix.build( builder ), 'v4', output );
|
|
|
|
|
|
} else {
|
|
|
|
|
@@ -195,9 +268,9 @@ TextureCubeUVNode.prototype.toJSON = function ( meta ) {
|
|
|
|
|
|
data = this.createJSONNode( meta );
|
|
|
|
|
|
+ data.value = this.value.toJSON( meta ).uuid;
|
|
|
data.uv = this.uv.toJSON( meta ).uuid;
|
|
|
- data.textureSize = this.textureSize.toJSON( meta ).uuid;
|
|
|
- data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;
|
|
|
+ data.bias = this.bias.toJSON( meta ).uuid;
|
|
|
|
|
|
}
|
|
|
|