Emmett Lalish 5 лет назад
Родитель
Сommit
ba2a320be2

+ 79 - 23
examples/js/pmrem/PMREMGenerator.js

@@ -22,6 +22,15 @@ THREE.PMREMGenerator = ( function () {
 	// geometric shadowing function.
 	const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
 	const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
+	const ENCODINGS = {
+		[ THREE.LinearEncoding ]: 0,
+		[ THREE.sRGBEncoding ]: 1,
+		[ THREE.RGBEEncoding ]: 2,
+		[ THREE.RGBM7Encoding ]: 3,
+		[ THREE.RGBM16Encoding ]: 4,
+		[ THREE.RGBDEncoding ]: 5,
+		[ THREE.GammaEncoding ]: 6
+	  };
 
 	var _flatCamera = new THREE.OrthographicCamera();
 	var _blurMaterial = getShader();
@@ -259,8 +268,8 @@ THREE.PMREMGenerator = ( function () {
 	  uniforms[ 'copyEquirectangular' ].value = true;
 	  uniforms[ 'texelSize' ].value.set(
 		  1.0 / equirectangular.image.width, 1.0 / equirectangular.image.height );
-	  uniforms[ 'inputEncoding' ].value = encodings[ equirectangular.encoding ];
-	  uniforms[ 'outputEncoding' ].value = encodings[ equirectangular.encoding ];
+	  uniforms[ 'inputEncoding' ].value = ENCODINGS[ equirectangular.encoding ];
+	  uniforms[ 'outputEncoding' ].value = ENCODINGS[ equirectangular.encoding ];
 
 	  this.renderer.setRenderTarget( cubeUVRenderTarget );
 	  this.renderer.setViewport( 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
@@ -392,8 +401,8 @@ THREE.PMREMGenerator = ( function () {
 		}
 		blurUniforms[ 'dTheta' ].value = radiansPerPixel;
 		blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn;
-		blurUniforms[ 'inputEncoding' ].value = encodings[ targetIn.texture.encoding ];
-		blurUniforms[ 'outputEncoding' ].value = encodings[ targetIn.texture.encoding ];
+		blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
+		blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ];
 
 		const outputSize = _sizeLods[ lodOut ];
 		const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize );
@@ -427,8 +436,8 @@ THREE.PMREMGenerator = ( function () {
 				'dTheta': { value: 0 },
 				'mipInt': { value: 0 },
 				'poleAxis': { value: poleAxis },
-				'inputEncoding': { value: encodings[ THREE.LinearEncoding ] },
-				'outputEncoding': { value: encodings[ THREE.LinearEncoding ] }
+				'inputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] },
+				'outputEncoding': { value: ENCODINGS[ THREE.LinearEncoding ] }
 			},
 
 			vertexShader: `
@@ -437,18 +446,20 @@ precision mediump int;
 attribute vec3 position;
 attribute vec2 uv;
 attribute float faceIndex;
-varying vec3 vOutputDirection;
-${getDirectionChunk}
+varying vec2 vUv;
+varying float vFaceIndex;
 void main() {
-    vOutputDirection = getDirection(uv, faceIndex);
+	vUv = uv;
+	vFaceIndex = faceIndex;
     gl_Position = vec4( position, 1.0 );
 }
-      `,
+      		`,
 
 			fragmentShader: `
 precision mediump float;
 precision mediump int;
-varying vec3 vOutputDirection;
+varying vec2 vUv;
+varying float vFaceIndex;
 uniform sampler2D envMap;
 uniform bool copyEquirectangular;
 uniform vec2 texelSize;
@@ -458,17 +469,62 @@ uniform bool latitudinal;
 uniform float dTheta;
 uniform float mipInt;
 uniform vec3 poleAxis;
-#define RECIPROCAL_PI 0.31830988618
-#define RECIPROCAL_PI2 0.15915494
-${texelIO} 
+uniform int inputEncoding;
+uniform int outputEncoding;
+
+#include <encodings_pars_fragment>
+
+vec4 inputTexelToLinear(vec4 value){
+    if(inputEncoding == 0){
+        return value;
+    }else if(inputEncoding == 1){
+        return sRGBToLinear(value);
+    }else if(inputEncoding == 2){
+        return RGBEToLinear(value);
+    }else if(inputEncoding == 3){
+        return RGBMToLinear(value, 7.0);
+    }else if(inputEncoding == 4){
+        return RGBMToLinear(value, 16.0);
+    }else if(inputEncoding == 5){
+        return RGBDToLinear(value, 256.0);
+    }else{
+        return GammaToLinear(value, 2.2);
+    }
+}
+
+vec4 linearToOutputTexel(vec4 value){
+    if(outputEncoding == 0){
+        return value;
+    }else if(outputEncoding == 1){
+        return LinearTosRGB(value);
+    }else if(outputEncoding == 2){
+        return LinearToRGBE(value);
+    }else if(outputEncoding == 3){
+        return LinearToRGBM(value, 7.0);
+    }else if(outputEncoding == 4){
+        return LinearToRGBM(value, 16.0);
+    }else if(outputEncoding == 5){
+        return LinearToRGBD(value, 256.0);
+    }else{
+        return LinearToGamma(value, 2.2);
+    }
+}
+
 vec4 envMapTexelToLinear(vec4 color) {
   return inputTexelToLinear(color);
 }
-${bilinearCubeUVChunk}
+
+#define ENVMAP_TYPE_CUBE_UV
+#include <cube_uv_reflection_fragment>
+
+#define RECIPROCAL_PI 0.31830988618
+#define RECIPROCAL_PI2 0.15915494
+
 void main() {
   gl_FragColor = vec4(0.0);
+  outputDirection = getDirection(vUv, vFaceIndex);
   if (copyEquirectangular) {
-    vec3 direction = normalize(vOutputDirection);
+    vec3 direction = normalize(outputDirection);
     vec2 uv;
     uv.y = asin(clamp(direction.y, -1.0, 1.0)) * RECIPROCAL_PI + 0.5;
     uv.x = atan(direction.z, direction.x) * RECIPROCAL_PI2 + 0.5;
@@ -491,16 +547,16 @@ void main() {
       for (int dir = -1; dir < 2; dir += 2) {
         if (i == 0 && dir == 1)
           continue;
-        vec3 axis = latitudinal ? poleAxis : cross(poleAxis, vOutputDirection);
+        vec3 axis = latitudinal ? poleAxis : cross(poleAxis, outputDirection);
         if (all(equal(axis, vec3(0.0))))
-          axis = cross(vec3(0.0, 1.0, 0.0), vOutputDirection);
+          axis = cross(vec3(0.0, 1.0, 0.0), outputDirection);
         axis = normalize(axis);
         float theta = dTheta * float(dir * i);
         float cosTheta = cos(theta);
         // Rodrigues' axis-angle rotation
-        vec3 sampleDirection = vOutputDirection * cosTheta 
-            + cross(axis, vOutputDirection) * sin(theta) 
-            + axis * dot(axis, vOutputDirection) * (1.0 - cosTheta);
+        vec3 sampleDirection = outputDirection * cosTheta 
+            + cross(axis, outputDirection) * sin(theta) 
+            + axis * dot(axis, outputDirection) * (1.0 - cosTheta);
         gl_FragColor.rgb +=
             weights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt);
       }
@@ -508,11 +564,11 @@ void main() {
   }
   gl_FragColor = linearToOutputTexel(gl_FragColor);
 }
-      `,
+     		`,
 
 			blending: THREE.NoBlending,
 			depthTest: false,
-	   depthWrite: false
+	   		depthWrite: false
 
 		} );
 

+ 166 - 115
src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js

@@ -1,130 +1,181 @@
 export default /* glsl */`
 #ifdef ENVMAP_TYPE_CUBE_UV
 
-#define cubeUV_textureSize (1024.0)
-
-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;
-}
-#define cubeUV_maxLods1  (log2(cubeUV_textureSize*0.25) - 1.0)
-#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))
-
-vec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {
-	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));
+#define cubeUV_maxMipLevel 8.0
+#define cubeUV_minMipLevel 4.0
+#define cubeUV_maxTileSize 256.0
+#define cubeUV_minTileSize 16.0
+
+// 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).
+
+vec3 getDirection(vec2 uv, float face) {
+    uv = 2.0 * uv - 1.0;
+    vec3 direction = vec3(uv, 1.0);
+    if (face == 0.0) {
+      direction = direction.zyx;
+      direction.z *= -1.0;
+    } else if (face == 1.0) {
+      direction = direction.xzy;
+      direction.z *= -1.0;
+    } else if (face == 3.0) {
+      direction = direction.zyx;
+      direction.x *= -1.0;
+    } else if (face == 4.0) {
+      direction = direction.xzy;
+      direction.y *= -1.0;
+    } else if (face == 5.0) {
+      direction.xz *= -1.0;
+    }
+    return direction;
 }
 
-#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)
-#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)
-
-vec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {
-	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 );
+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;
 }
 
-#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)
-
-vec4 textureCubeUV( sampler2D envMap, vec3 reflectedDirection, float roughness ) {
-	float roughnessVal = roughness* cubeUV_maxLods3;
-	float r1 = floor(roughnessVal);
-	float r2 = r1 + 1.0;
-	float t = fract(roughnessVal);
-	vec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);
-	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 );
+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);
+}
 
-	// Tri linear interpolation.
-	vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);
-	vec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));
+vec3 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;
+
+  vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;
+  uv.x += texelSize;
+  vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;
+  uv.y += texelSize;
+  vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;
+  uv.x -= texelSize;
+  vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;
+  vec3 tm = mix(tl, tr, f.x);
+  vec3 bm = mix(bl, br, f.x);
+  return mix(tm, bm, f.y);
+}
 
-	vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);
-	vec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));
+// These defines must match with PMREMGenerator
+
+#define r0 1.0
+#define v0 0.339
+#define m0 -2.0
+#define r1 0.8
+#define v1 0.276
+#define m1 -1.0
+#define r4 0.4
+#define v4 0.046
+#define m4 2.0
+#define r5 0.305
+#define v5 0.016
+#define m5 3.0
+#define r6 0.21
+#define v6 0.0038
+#define m6 4.0
+
+float roughnessToVariance(float roughness) {
+  float variance = 0.0;
+  if (roughness >= r1) {
+    variance = (r0 - roughness) * (v1 - v0) / (r0 - r1) + v0;
+  } else if (roughness >= r4) {
+    variance = (r1 - roughness) * (v4 - v1) / (r1 - r4) + v1;
+  } else if (roughness >= r5) {
+    variance = (r4 - roughness) * (v5 - v4) / (r4 - r5) + v4;
+  } else {
+    float roughness2 = roughness * roughness;
+    variance = 1.79 * roughness2 * roughness2;
+  }
+  return variance;
+}
 
-	vec4 result = mix(color10, color20, t);
+float varianceToRoughness(float variance) {
+  float roughness = 0.0;
+  if (variance >= v1) {
+    roughness = (v0 - variance) * (r1 - r0) / (v0 - v1) + r0;
+  } else if (variance >= v4) {
+    roughness = (v1 - variance) * (r4 - r1) / (v1 - v4) + r1;
+  } else if (variance >= v5) {
+    roughness = (v4 - variance) * (r5 - r4) / (v4 - v5) + r4;
+  } else {
+    roughness = pow(0.559 * variance, 0.25);// 0.559 = 1.0 / 1.79
+  }
+  return roughness;
+}
 
-	return vec4(result.rgb, 1.0);
+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;
 }
 
+vec4 textureCubeUV(sampler2D envMap, vec3 sampleDir, float roughness) {
+  float mip = clamp(roughnessToMip(roughness), m0, cubeUV_maxMipLevel);
+  float mipF = fract(mip);
+  float mipInt = floor(mip);
+
+  vec3 color0 = bilinearCubeUV(envMap, sampleDir, mipInt);
+  if (mipF == 0.0) {
+    return vec4(color0, 1.0);
+  } else {
+    vec3 color1 = bilinearCubeUV(envMap, sampleDir, mipInt + 1.0);
+    return vec4(mix(color0, color1, mipF), 1.0);
+  }
+}
 #endif
 `;