Pārlūkot izejas kodu

clean up PMREMGEnerator, incorporate global encodings.glsl. Add into the THREE namespace, move into examples.

Ben Houston 9 gadi atpakaļ
vecāks
revīzija
49f49beada

+ 67 - 0
examples/js/loaders/HDRCubeMapLoader.js

@@ -0,0 +1,67 @@
+/**
+ * @author Prashant Sharma / spidersharma03
+ */
+
+THREE.HDRCubeMapLoader = function (manager) {
+    this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+    // override in sub classes
+    this.hdrLoader = new THREE.RGBELoader();
+}
+
+THREE.HDRCubeMapLoader.prototype.load = function(urls, onLoad, onProgress, onError) {
+    var texture = new THREE.CubeTexture( [] );
+    texture.encoding = THREE.RGBE;
+    var scope = this.hdrLoader;
+
+    var loaded = 0;
+
+     function loadHDRData(i, onLoad, onProgress, onError) {
+        var loader = new THREE.XHRLoader( this.manager );
+        loader.setResponseType( 'arraybuffer' );
+
+        loader.load( urls[i], function ( buffer ) {
+                loaded++;
+
+                var texData = scope._parser( buffer );
+
+                if ( ! texData ) return;
+
+                if ( undefined !== texData.image ) {
+                        texture[i].images = texData.image;
+                }
+                else if ( undefined !== texData.data ) {
+                        var dataTexture = new THREE.DataTexture(texData.data, texData.width, texData.height);
+                        dataTexture.format = texData.format;
+                        dataTexture.type = texData.type;
+                        dataTexture.minFilter = THREE.LinearFilter;
+                        dataTexture.magFilter = THREE.LinearFilter;
+                        dataTexture.generateMipmaps = false;
+                        texture.images[i] = dataTexture;
+                }
+
+                if(loaded === 6) {
+                        texture.needsUpdate = true;
+
+                        if ( undefined !== texData.format ) {
+
+                                texture.format = texData.format;
+
+                        }
+                        if ( undefined !== texData.type ) {
+
+                                texture.type = texData.type;
+
+                        }
+                        texture.minFilter = THREE.LinearFilter;
+                        texture.magFilter = THREE.LinearFilter;
+                        texture.generateMipmaps = false;
+                        if ( onLoad ) onLoad( texture );
+                }
+        }, onProgress, onError );
+    }
+
+    for(var i=0; i<urls.length; i++) {
+        loadHDRData(i, onLoad, onProgress, onError);
+    }
+    return texture;
+};

+ 223 - 0
examples/js/pmrem/PMREMGenerator.js

@@ -0,0 +1,223 @@
+/**
+ * @author Prashant Sharma / spidersharma03
+ * @author Ben Houston / bhouston, https://clara.io
+ */
+
+ THREE.PMREMGenerator = function( cubeTexture ) {
+
+	if ( cubeTexture instanceof THREE.CubeTexture ) {
+
+		if ( cubeTexture.images[ 0 ] === undefined )
+		  console.error( "CubeTexture Not Initialized" );
+      if(cubeTexture.images[ 0 ] instanceof THREE.DataTexture) {
+          this.resolution = cubeTexture.images[ 0 ].image.width;
+      }
+      else {
+          this.resolution = cubeTexture.images[ 0 ].width;
+      }
+
+	}
+	else if ( cubeTexture instanceof THREE.WebGLRenderTargetCube ) {
+		if ( cubeTexture === undefined ) console.error( "Render Target Not Initialized" );
+		this.resolution = cubeTexture.width;
+	}
+	else {
+		console.error( "Wrong Input to PMREMGenerator" );
+	}
+
+	this.sourceTexture = cubeTexture;
+
+  // encoded formats do not interpolate well, thus turn off interpolation for them
+  var textureFilter = ( sourceTexture.encoding === THREE.Linear ) ? THREE.LinearFilter : THREE.NearestFilter;
+  this.sourceTexture.minFilter = this.sourceTexture.magFilter = textureFilter;
+
+	this.cubeLods = [];
+
+	var size = this.resolution;
+  var params = { format: THREE.RGBAFormat, magFilter: textureFilter, minFilter: textureFilter };
+
+	this.numLods = Math.log2( size ) - 2;
+  for ( var i = 0; i < this.numLods; i ++ ) {
+		var renderTarget = new THREE.WebGLRenderTargetCube( size, size, params );
+		renderTarget.texture.generateMipmaps = false;
+    renderTarget.encoding = this.sourceTexture.encoding;
+		this.cubeLods.push( renderTarget );
+		size = Math.max( 16, size / 2 );
+	}
+
+	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0.0, 1000 );
+
+  this.shader = this.getShader();
+	this.planeMesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2, 0 ), this.shader );
+	this.planeMesh.material.side = THREE.DoubleSide;
+	this.scene = new THREE.Scene();
+	this.scene.add( this.planeMesh );
+	this.scene.add( this.camera );
+
+	this.shader.uniforms[ "sourceTexture" ].value = this.sourceTexture;
+	this.shader.uniforms[ "encoding" ].value = this.sourceTexture.encoding;
+};
+
+THREE.PMREMGenerator.prototype = {
+
+	constructor : PMREMGenerator,
+
+	update: function( renderer ) {
+
+		this.shader.uniforms[ "sourceTexture" ].value = this.sourceTexture;
+		for ( var i = 0; i < this.numLods; i ++ ) {
+
+			var r = i / ( this.numLods - 1 );
+			this.shader.uniforms[ "roughness" ].value = r * 0.9;
+			var size = this.cubeLods[ i ].width;
+			this.shader.uniforms[ "mapSize" ].value = size;
+			this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] );
+			if ( i < 5 )
+			this.shader.uniforms[ "sourceTexture" ].value = this.cubeLods[ i ];
+
+		}
+
+	},
+
+	renderToCubeMapTarget: function( renderer, renderTarget ) {
+
+		for ( var i = 0; i < 6; i ++ ) {
+		  this.renderToCubeMapTargetFace( renderer, renderTarget, i )
+    }
+
+	},
+
+	renderToCubeMapTargetFace: function( renderer, renderTarget, faceIndex ) {
+
+		renderTarget.texture.generateMipmaps = false;
+		renderTarget.activeCubeFace = faceIndex;
+		this.shader.uniforms[ "faceIndex" ].value = faceIndex;
+		renderer.render( this.scene, this.camera, renderTarget, true );
+
+	},
+
+  getShader: function() {
+
+    return new THREE.ShaderMaterial( {
+
+      uniforms: {
+        "faceIndex": { type: 'i', value: 0 },
+        "roughness": { type: 'f', value: 0.5 },
+        "mapSize": { type: 'f', value: 0.5 },
+        "sourceTexture": { type: 't', value: null },
+        "encoding": { type: 'i', value: 3002},
+        "testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
+      },
+
+      vertexShader:
+        "varying vec2 vUv;\n\
+        void main() {\n\
+           vUv = uv;\n\
+           gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+        }",
+
+      fragmentShader:
+        "varying vec2 vUv;\n\
+        uniform int faceIndex;\n\
+        uniform float roughness;\n\
+        uniform samplerCube sourceTexture;\n\
+        uniform float mapSize;\n\
+        uniform vec3 testColor;\n\
+        uniform int encoding;\n\
+        \n\
+        float rnd(vec2 uv) {\n\
+           return fract(sin(dot(uv, vec2(12.9898, 78.233) * 2.0)) * 43758.5453);\n\
+        }\n\
+        float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\
+           float a = ggxRoughness + 0.0001;\n\
+           a *= a;\n\
+           return ( 2.0 / a - 2.0 );\n\
+        }\n\
+        const float PI = 3.14159265358979;\n\
+        vec3 ImportanceSamplePhong(vec2 uv, mat3 vecSpace, float specPow) {\n\
+           float phi = uv.y * 2.0 * PI;\n\
+           float cosTheta = pow(1.0 - uv.x, 1.0 / (specPow + 1.0));\n\
+           float sinTheta = sqrt(1.0 - cosTheta * cosTheta);\n\
+           vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);\n\
+           return vecSpace * sampleDir;\n\
+        }\n\
+        vec3 ImportanceSampleGGX( vec2 uv, mat3 vecSpace, float Roughness )\n\
+        {\n\
+               float a = Roughness * Roughness;\n\
+               float Phi = 2.0 * PI * uv.x;\n\
+               float CosTheta = sqrt( (1.0 - uv.y) / ( 1.0 + (a*a - 1.0) * uv.y ) );\n\
+               float SinTheta = sqrt( 1.0 - CosTheta * CosTheta );\n\
+               return vecSpace * vec3(SinTheta * cos( Phi ), SinTheta * sin( Phi ), CosTheta);\n\
+        }\n\
+        mat3 matrixFromVector(vec3 n) {\n\
+           float a = 1.0 / (1.0 + n.z);\n\
+           float b = -n.x * n.y * a;\n\
+           vec3 b1 = vec3(1.0 - n.x * n.x * a, b, -n.x);\n\
+           vec3 b2 = vec3(b, 1.0 - n.y * n.y * a, -n.y);\n\
+           return mat3(b1, b2, n);\n\
+        }\n\
+        \n\
+        vec4 testColorMap() {\n\
+           vec4 color;\n\
+           if(faceIndex == 0)\n\
+               color = vec4(1.0,0.0,0.0,1.0);\n\
+           else if(faceIndex == 1)\n\
+               color = vec4(0.0,1.0,0.0,1.0);\n\
+           else if(faceIndex == 2)\n\
+               color = vec4(0.0,0.0,1.0,1.0);\n\
+           else if(faceIndex == 3)\n\
+               color = vec4(1.0,1.0,0.0,1.0);\n\
+           else if(faceIndex == 4)\n\
+               color = vec4(0.0,1.0,1.0,1.0);\n\
+           else\n\
+               color = vec4(1.0,0.0,1.0,1.0);\n\
+           return color;\n\
+        }",
+  			THREE.ShaderChunk[ "encodings" ],
+        "void main() {\n\
+           vec3 sampleDirection;\n\
+           vec2 uv = vUv*2.0 - 1.0;\n\
+           float offset = -1.0/mapSize;\n\
+           const float a = -1.0;\n\
+           const float b = 1.0;\n\
+           float c = -1.0 + offset;\n\
+           float d = 1.0 - offset;\n\
+           float bminusa = b - a;\n\
+           uv.x = (uv.x - a)/bminusa * d - (uv.x - b)/bminusa * c;\n\
+           uv.y = (uv.y - a)/bminusa * d - (uv.y - b)/bminusa * c;\n\
+           if (faceIndex==0) {\n\
+               sampleDirection = vec3(1.0, -uv.y, -uv.x);\n\
+           }\n\
+           else if (faceIndex==1) {\n\
+               sampleDirection = vec3(-1.0, -uv.y, uv.x);\n\
+           } else if (faceIndex==2) {\n\
+               sampleDirection = vec3(uv.x, 1.0, uv.y);\n\
+           } else if (faceIndex==3) {\n\
+               sampleDirection = vec3(uv.x, -1.0, -uv.y);\n\
+           } else if (faceIndex==4) {\n\
+               sampleDirection = vec3(uv.x, -uv.y, 1.0);\n\
+           } else {\n\
+               sampleDirection = vec3(-uv.x, -uv.y, -1.0);\n\
+           }\n\
+           mat3 vecSpace = matrixFromVector(normalize(sampleDirection));\n\
+           vec3 rgbColor = vec3(0.0);\n\
+           const int NumSamples = 1024;\n\
+           vec3 vect;\n\
+           float weight = 0.0;\n\
+           for(int i=0; i<NumSamples; i++) {\n\
+               float sini = sin(float(i));\n\
+               float cosi = cos(float(i));\n\
+               float rand = rnd(vec2(sini, cosi));\n\
+               vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), rand), vecSpace, roughness);\n\
+               float dotProd = dot(vect, normalize(sampleDirection));\n\
+               weight += dotProd;\n\
+               vec3 color = texelDecode(textureCube(sourceTexture, vect), encoding).rgb;\n\
+               rgbColor.rgb += color;\n\
+           }\n\
+           rgbColor /= float(NumSamples);\n\
+           gl_FragColor = texelEncode( rgbColor, encoding );\n\
+        }"
+      }
+    );
+  }
+};

+ 158 - 0
examples/js/pmrem/PMREM_CubeUVPacker.js

@@ -0,0 +1,158 @@
+/**
+ * @author Prashant Sharma / spidersharma03
+ */
+
+var vertexShaderPMREMCubeUV = "precision highp float;\
+                   varying vec2 vUv;\
+                   void main() {\
+                        vUv = uv;\
+                        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\
+                   }";
+
+var fragmentShaderPMREMCubeUV = "precision highp float;\
+    varying vec2 vUv;\
+    uniform samplerCube cubeTexture;\
+    uniform float mapSize;\
+    uniform vec3 testColor;\
+    uniform int faceIndex;\
+    \
+    const float PI = 3.14159265358979;\
+    vec4 sampleCubeMap(float phi, float theta) {\
+        float sinTheta = sin(theta);\
+        float cosTheta = cos(theta);\
+        vec3 sampleDir = vec3(cos(phi) * sinTheta, cosTheta, sin(phi) * sinTheta);\
+        vec4 color = textureCube(cubeTexture, sampleDir);\
+        return color * vec4(testColor, 1.0);\
+    }\
+    void main() {\
+        vec3 sampleDirection;\
+        vec2 uv = vUv;\
+        uv = uv * 2.0 - 1.0;\
+        uv.y *= -1.0;\
+        if(faceIndex == 0) {\
+            sampleDirection = normalize(vec3(1.0, uv.y, -uv.x));\
+        }\
+        else if(faceIndex == 1) {\
+            sampleDirection = normalize(vec3(uv.x, 1.0, uv.y));\
+        }\
+        else if(faceIndex == 2) {\
+            sampleDirection = normalize(vec3(uv.x, uv.y, 1.0));\
+        }\
+        else if(faceIndex == 3) {\
+            sampleDirection = normalize(vec3(-1.0, uv.y, uv.x));\
+        }\
+        else if(faceIndex == 4) {\
+            sampleDirection = normalize(vec3(uv.x, -1.0, -uv.y));\
+        }\
+        else {\
+            sampleDirection = normalize(vec3(-uv.x, uv.y, -1.0));\
+        }\
+        vec4 color = textureCube(cubeTexture, (sampleDirection));\
+        gl_FragColor = color * vec4(testColor, 1.0);\
+    }\
+";
+var uniformsPMREMCubeUV = {
+	"faceIndex": { type: 'i', value: 0 },
+	"mapSize": { type: 'f', value: 0 },
+	"cubeTexture": { type: 't', value: null },
+	"testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
+};
+
+var testColor = [];
+testColor.push( new THREE.Vector3( 1, 0, 0 ) );
+testColor.push( new THREE.Vector3( 0, 1, 0 ) );
+testColor.push( new THREE.Vector3( 0, 0, 1 ) );
+testColor.push( new THREE.Vector3( 1, 1, 0 ) );
+testColor.push( new THREE.Vector3( 0, 1, 1 ) );
+testColor.push( new THREE.Vector3( 1, 0, 1 ) );
+testColor.push( new THREE.Vector3( 1, 1, 1 ) );
+testColor.push( new THREE.Vector3( 0.5, 1, 0.5 ) );
+
+var PMREM_CubeUVPacker = function( cubeTextureLods, numLods ) {
+
+	this.cubeLods = cubeTextureLods;
+	this.numLods = numLods;
+	var size = cubeTextureLods[ 0 ].width * 4;
+
+	this.CubeUVRenderTarget = new THREE.WebGLRenderTarget( size, size,
+	{ format: THREE.RGBAFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );
+	this.CubeUVRenderTarget.texture.generateMipmaps = false;
+                this.CubeUVRenderTarget.mapping = THREE.CubeUVReflectionMapping;
+	this.camera = new THREE.OrthographicCamera( - size * 0.5, size * 0.5, - size * 0.5, size * 0.5, 0.0, 1000 );
+                this.CubeUVRenderTarget.encoding = this.cubeLods[0].encoding;
+
+	this.scene = new THREE.Scene();
+	this.scene.add( this.camera );
+
+	this.objects = [];
+	var xOffset = 0;
+	var faceOffsets = [];
+	faceOffsets.push( new THREE.Vector2( 0, 0 ) );
+	faceOffsets.push( new THREE.Vector2( 1, 0 ) );
+	faceOffsets.push( new THREE.Vector2( 2, 0 ) );
+	faceOffsets.push( new THREE.Vector2( 0, 1 ) );
+	faceOffsets.push( new THREE.Vector2( 1, 1 ) );
+	faceOffsets.push( new THREE.Vector2( 2, 1 ) );
+	var yOffset = 0;
+	var textureResolution = size;
+	size = cubeTextureLods[ 0 ].width;
+
+	var offset2 = 0;
+	var c = 4.0;
+	this.numLods = Math.log2( cubeTextureLods[ 0 ].width ) - 2;
+	for ( var i = 0; i < this.numLods; i ++ ) {
+
+		var offset1 = ( textureResolution - textureResolution / c ) * 0.5;
+		if ( size > 16 )
+		c *= 2;
+		var nMips = size > 16 ? 6 : 1;
+		var mipOffsetX = 0;
+		var mipOffsetY = 0;
+		var mipSize = size;
+		for ( var j = 0; j < nMips; j ++ ) {
+
+			// Mip Maps
+			for ( var k = 0; k < 6; k ++ ) {
+
+				// 6 Cube Faces
+				var material = new THREE.ShaderMaterial();
+				material.vertexShader = vertexShaderPMREMCubeUV;
+				material.fragmentShader = fragmentShaderPMREMCubeUV;
+				material.uniforms = THREE.UniformsUtils.clone( uniformsPMREMCubeUV );
+				material.uniforms[ "cubeTexture" ].value = this.cubeLods[ i ];
+				material.uniforms[ "faceIndex" ].value = k;
+				material.uniforms[ "mapSize" ].value = mipSize;
+				var color = material.uniforms[ "testColor" ].value;
+				//color.copy(testColor[j]);
+				var planeMesh = new THREE.Mesh(
+				new THREE.PlaneGeometry( mipSize, mipSize, 0 ),
+				material );
+				planeMesh.position.x = faceOffsets[ k ].x * mipSize - offset1 + mipOffsetX;
+				planeMesh.position.y = faceOffsets[ k ].y * mipSize - offset1 + offset2 + mipOffsetY;
+				planeMesh.material.side = THREE.DoubleSide;
+				this.scene.add( planeMesh );
+				this.objects.push( planeMesh );
+
+			}
+			mipOffsetY += 1.75 * mipSize;
+			mipOffsetX += 1.25 * mipSize;
+			mipSize /= 2;
+
+		}
+		offset2 += 2 * size;
+		if ( size > 16 )
+		size /= 2;
+
+	}
+
+};
+
+PMREM_CubeUVPacker.prototype = {
+	constructor : PMREM_CubeUVPacker,
+
+	update: function( renderer ) {
+
+		renderer.render( this.scene, this.camera, this.CubeUVRenderTarget, true );
+
+	}
+};