提交 c2b8ba5b 编写于 作者: M Mr.doob

Merge pull request #8237 from bhouston/pmrem4

HDR EnvMap example with high quality, flexible PMREM Generator.
......@@ -119,6 +119,7 @@ var files = {
"webgl_materials_cubemap_refraction",
"webgl_materials_displacementmap",
"webgl_materials_envmaps",
"webgl_materials_envmaps_hdr",
"webgl_materials_grass",
"webgl_materials_lightmap",
"webgl_materials_nodes",
......
/**
* @author Ben Houston / http://clara.io / bhouston
* @author Prashant Sharma / spidersharma03
*/
THREE.Encodings = function() {
if( THREE.toHalf === undefined ) throw new Error("THREE.Encodings is required for HDRCubeMapLoader when loading half data.");
}
THREE.Encodings.RGBEByteToRGBFloat = function( sourceArray, sourceOffset, destArray, destOffset ) {
var e = sourceArray[sourceOffset+3];
var scale = Math.pow(2.0, e - 128.0) / 255.0;
destArray[destOffset+0] = sourceArray[sourceOffset+0] * scale;
destArray[destOffset+1] = sourceArray[sourceOffset+1] * scale;
destArray[destOffset+2] = sourceArray[sourceOffset+2] * scale;
}
THREE.Encodings.RGBEByteToRGBHalf = function( sourceArray, sourceOffset, destArray, destOffset ) {
var e = sourceArray[sourceOffset+3];
var scale = Math.pow(2.0, e - 128.0) / 255.0;
destArray[destOffset+0] = THREE.toHalf( sourceArray[sourceOffset+0] * scale );
destArray[destOffset+1] = THREE.toHalf( sourceArray[sourceOffset+1] * scale );
destArray[destOffset+2] = THREE.toHalf( sourceArray[sourceOffset+2] * scale );
}
/**
* Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
*/
THREE.toHalf = (function() {
var floatView = new Float32Array(1);
var int32View = new Int32Array(floatView.buffer);
/* This method is faster than the OpenEXR implementation (very often
* used, eg. in Ogre), with the additional benefit of rounding, inspired
* by James Tursa?s half-precision code. */
return function toHalf(val) {
floatView[0] = val;
var x = int32View[0];
var bits = (x >> 16) & 0x8000; /* Get the sign */
var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
var e = (x >> 23) & 0xff; /* Using int is faster here */
/* If zero, or denormal, or exponent underflows too much for a denormal
* half, return signed zero. */
if (e < 103) {
return bits;
}
/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
if (e > 142) {
bits |= 0x7c00;
/* If exponent was 0xff and one mantissa bit was set, it means NaN,
* not Inf, so make sure we set one mantissa bit too. */
bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
return bits;
}
/* If exponent underflows but not too much, return a denormal */
if (e < 113) {
m |= 0x0800;
/* Extra rounding may overflow and set mantissa to 0 and exponent
* to 1, which is OK. */
bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
return bits;
}
bits |= ((e - 112) << 10) | (m >> 1);
/* Extra rounding. An overflow will set mantissa to 0 and increment
* the exponent, which is OK. */
bits += m & 1;
return bits;
};
}());
/**
* @author Prashant Sharma / spidersharma03
* @author Ben Houston / http://clara.io / bhouston
*/
THREE.HDRCubeMapLoader = function (manager) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
// override in sub classes
this.hdrLoader = new THREE.RGBELoader();
if( THREE.Encodings === undefined ) throw new Error( "HDRCubeMapLoader requires THREE.Encodings" );
}
THREE.HDRCubeMapLoader.prototype.load = function(type, urls, onLoad, onProgress, onError) {
var texture = new THREE.CubeTexture( [] );
texture.type = type;
texture.encoding = (type === THREE.UnsignedByteType) ? THREE.RGBEEncoding : THREE.LinearEncoding;
texture.format = (type === THREE.UnsignedByteType ) ? THREE.RGBAFormat : THREE.RGBFormat;
texture.minFilter = (texture.encoding === THREE.RGBEEncoding ) ? THREE.NearestFilter : THREE.LinearFilter;
texture.magFilter = (texture.encoding === THREE.RGBEEncoding ) ? THREE.NearestFilter : THREE.LinearFilter;
texture.generateMipmaps = (texture.encoding !== THREE.RGBEEncoding );
texture.anisotropy = 0;
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(type === THREE.FloatType) {
var numElements = ( texData.data.length / 4 )*3;
var floatdata = new Float32Array( numElements );
for( var j=0; j<numElements; j++) {
THREE.Encodings.RGBEByteToRGBFloat( texData.data, j*4, floatdata, j*3 );
}
texData.data = floatdata;
}
else if(type === THREE.HalfFloatType) {
var numElements = ( texData.data.length / 4 )*3;
var halfdata = new Uint16Array( numElements );
for( var j=0; j<numElements; j++) {
THREE.Encodings.RGBEByteToRGBHalf( texData.data, j*4, halfdata, j*3 );
}
texData.data = halfdata;
}
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 = texture.format;
dataTexture.type = texture.type;
dataTexture.encoding = texture.encoding;
dataTexture.minFilter = texture.minFilter;
dataTexture.magFilter = texture.magFilter;
dataTexture.generateMipmaps = texture.generateMipmaps;
texture.images[i] = dataTexture;
}
if(loaded === 6) {
texture.needsUpdate = true;
if ( onLoad ) onLoad( texture );
}
}, onProgress, onError );
}
for(var i=0; i<urls.length; i++) {
loadHDRData(i, onLoad, onProgress, onError);
}
return texture;
};
/**
* @author Prashant Sharma / spidersharma03
* @author Ben Houston / bhouston, https://clara.io
*/
THREE.PMREMCubeUVPacker = 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, type: cubeTextureLods[ 0 ].texture.type } );
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.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 = this.getShader();
material.uniforms[ "envMap" ].value = this.cubeLods[ i ];
material.envMap = 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;
}
};
THREE.PMREMCubeUVPacker.prototype = {
constructor : THREE.PMREMCubeUVPacker,
update: function( renderer ) {
var gammaInput = renderer.gammaInput;
var gammaOutput = renderer.gammaOutput;
renderer.gammaInput = false;
renderer.gammaOutput = false;
renderer.render( this.scene, this.camera, this.CubeUVRenderTarget, true );
renderer.gammaInput = renderer.gammaInput;
renderer.gammaOutput = renderer.gammaOutput;
},
getShader: function() {
var shaderMaterial = new THREE.ShaderMaterial( {
uniforms: {
"faceIndex": { type: 'i', value: 0 },
"mapSize": { type: 'f', value: 0 },
"envMap": { type: 't', value: null },
"testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
},
vertexShader:
"precision highp float;\
varying vec2 vUv;\
void main() {\
vUv = uv;\
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\
}",
fragmentShader:
"precision highp float;\
varying vec2 vUv;\
uniform samplerCube envMap;\
uniform float mapSize;\
uniform vec3 testColor;\
uniform int faceIndex;\
\
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 = envMapTexelToLinear( textureCube( envMap, sampleDirection ) );\
gl_FragColor = linearToOutputTexel( color * vec4(testColor, 1.0) );\
}",
blending: THREE.CustomBlending,
blendSrc: THREE.OneFactor,
blendDst: THREE.ZeroFactor,
blendSrcAlpha: THREE.OneFactor,
blendDstAlpha: THREE.ZeroFactor,
blendEquation: THREE.AddEquation
});
return shaderMaterial;
}
};
/**
* @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;
this.cubeLods = [];
var size = this.resolution;
var params = { format: this.sourceTexture.format, magFilter: this.sourceTexture.magFilter, minFilter: this.sourceTexture.minFilter, type: this.sourceTexture.type };
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 = this.sourceTexture.generateMipmaps;
renderTarget.texture.anisotropy = this.sourceTexture.anisotropy;
renderTarget.texture.encoding = this.sourceTexture.encoding;
renderTarget.texture.minFilter = this.sourceTexture.minFilter;
renderTarget.texture.magFilter = this.sourceTexture.magFilter;
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[ "envMap" ].value = this.sourceTexture;
this.shader.envMap = this.sourceTexture;
};
THREE.PMREMGenerator.prototype = {
constructor : THREE.PMREMGenerator,
update: function( renderer ) {
this.shader.uniforms[ "envMap" ].value = this.sourceTexture;
this.shader.envMap = this.sourceTexture;
var gammaInput = renderer.gammaInput;
var gammaOutput = renderer.gammaOutput;
renderer.gammaInput = false;
renderer.gammaOutput = false;
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[ "envMap" ].value = this.cubeLods[ i ];
}
renderer.gammaInput = renderer.gammaInput;
renderer.gammaOutput = renderer.gammaOutput;
},
renderToCubeMapTarget: function( renderer, renderTarget ) {
for ( var i = 0; i < 6; i ++ ) {
this.renderToCubeMapTargetFace( renderer, renderTarget, i )
}
},
renderToCubeMapTargetFace: function( renderer, renderTarget, faceIndex ) {
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 },
"envMap": { type: 't', value: null },
"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 envMap;\n\
uniform float mapSize;\n\
uniform vec3 testColor;\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(float Roughness) {\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\
color *= ( 1.0 - Roughness );\n\
return color;\n\
}\n\
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 = envMapTexelToLinear(textureCube(envMap,vect)).rgb;\n\
rgbColor.rgb += color;\n\
}\n\
rgbColor /= float(NumSamples);\n\
//rgbColor = testColorMap( roughness ).rgb;\n\
gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\
}",
blending: THREE.CustomBlending,
blendSrc: THREE.OneFactor,
blendDst: THREE.ZeroFactor,
blendSrcAlpha: THREE.OneFactor,
blendDstAlpha: THREE.ZeroFactor,
blendEquation: THREE.AddEquation
}
);
}
};
<!DOCTYPE html>
<html lang="en">
<head>
<title>threejs webgl - materials</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
color: #fff;
font-family:Monospace;
font-size:13px;
text-align:center;
background-color: #000;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info"><a href="http://threejs.org" target="_blank">threejs</a> - High dynamic range (RGBE) Image-based Lighting (IBL) using run-time generated pre-filtered roughness mipmaps (PMREM)<br/>
Created by Prashant Sharma and <a href="http://clara.io/" target="_blank">Ben Houston</a>.</div>
<script src="../build/three.min.js"></script>
<script src="../examples/js/controls/OrbitControls.js"></script>
<script src="../src/loaders/BinaryTextureLoader.js"></script>
<script src="../examples/js/loaders/RGBELoader.js"></script>
<script src="../examples/js/loaders/HDRCubeMapLoader.js"></script>
<script src="../examples/js/Detector.js"></script>
<script src="../examples/js/libs/stats.min.js"></script>
<script src="../examples/js/Half.js"></script>
<script src="../examples/js/Encodings.js"></script>
<script src="../examples/js/pmrem/PMREMGenerator.js"></script>
<script src="../examples/js/pmrem/PMREMCubeUVPacker.js"></script>
<script src="../examples/js/libs/dat.gui.min.js"></script>
<script src="../examples/js/postprocessing/EffectComposer.js"></script>
<script src="../examples/js/postprocessing/RenderPass.js"></script>
<script src="../examples/js/postprocessing/MaskPass.js"></script>
<script src="../examples/js/postprocessing/ShaderPass.js"></script>
<script src="../examples/js/shaders/CopyShader.js"></script>
<script src="../examples/js/shaders/FXAAShader.js"></script>
<script src="../examples/js/postprocessing/BloomPass.js"></script>
<script src="../examples/js/shaders/ConvolutionShader.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var params = {
projection: 'normal',
roughness: 1.0,
bumpScale: 0.3,
background: false,
};
var camera, scene, renderer, controls, objects = [];
var hdrCubeMap;
var composer;
var standardMaterial;
var loader = new THREE.FontLoader();
loader.load( '../examples/fonts/gentilis_regular.typeface.js', function ( font ) {
init( font );
animate();
} );
function init( font ) {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set( 0.0, 40, 40 * 3.5 );
scene = new THREE.Scene();
// Materials
var hdrpath = "../examples/textures/cube/hdrPisa/";
var hdrformat = '.hdr';
var hdrurls = [
hdrpath + 'px' + hdrformat, hdrpath + 'nx' + hdrformat,
hdrpath + 'py' + hdrformat, hdrpath + 'ny' + hdrformat,
hdrpath + 'pz' + hdrformat, hdrpath + 'nz' + hdrformat
];
renderer = new THREE.WebGLRenderer( { alpha: false, antialias: false } );
var roughnessTexture = THREE.ImageUtils.loadTexture( "../examples/textures/roughness_map.jpg" );
roughnessTexture.wrapS = THREE.RepeatWrapping;
roughnessTexture.wrapT = THREE.RepeatWrapping;
roughnessTexture.repeat.set( 9, 2 );
var hdrType = THREE.UnsignedByteType;
/* if ( renderer.extensions.get( 'OES_texture_half_float' ) && renderer.extensions.get( 'OES_texture_half_float_linear' ) ) {
hdrType = THREE.HalfFloatType;
}
else if ( renderer.extensions.get( 'OES_texture_float' ) && renderer.extensions.get( 'OES_texture_float_linear' ) ) {
hdrType = THREE.FloatType;
}*/
var hdrCubeMap = new THREE.HDRCubeMapLoader().load( hdrType, hdrurls, function ( hdrCubeMap ) {
var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
pmremGenerator.update(renderer);
var pmremCubeUVPacker = new THREE.PMREMCubeUVPacker(pmremGenerator.cubeLods);
pmremCubeUVPacker.update(renderer);
standardMaterial = new THREE.MeshStandardMaterial( {
map: null,
roughnessMap: roughnessTexture,
bumpScale: -0.05,
bumpMap: roughnessTexture,
color: 0xffffff,
metalness: 0.9,
roughness: 1.0,
envMap: pmremCubeUVPacker.CubeUVRenderTarget,
shading: THREE.SmoothShading
});
var geometry = new THREE.TorusKnotGeometry( 18, 8, 150, 20 );;
var torusMesh1 = new THREE.Mesh( geometry, standardMaterial );
torusMesh1.position.x = 0.0;
scene.add( torusMesh1 );
objects.push( torusMesh1 );
var floorMaterial = new THREE.MeshStandardMaterial( {
map: null,
roughnessMap: null,
color: 0xffffff,
metalness: 0.0,
roughness: 0.0,
envMap: pmremCubeUVPacker.CubeUVRenderTarget,
shading: THREE.SmoothShading
});
var planeGeometry = new THREE.PlaneBufferGeometry( 200, 200 );
var planeMesh1 = new THREE.Mesh( planeGeometry, floorMaterial );
planeMesh1.position.y = -50;
planeMesh1.rotation.x = -Math.PI * 0.5;
scene.add( planeMesh1 );
} );
// Lights
scene.add( new THREE.AmbientLight( 0x222222 ) );
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 10, 100, 10 );
spotLight.angle = Math.PI/10;
spotLight.penumbra = 0.2
scene.add( spotLight );
renderer.setClearColor( 0x0a0a0a, 0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.gammaInput = true;
renderer.gammaOutput = true;
composer = new THREE.EffectComposer(renderer);
composer.setSize(window.innerWidth, window.innerHeight);
var renderScene = new THREE.RenderPass(scene, camera);
composer.addPass(renderScene);
var copyPass = new THREE.ShaderPass(THREE.CopyShader);
copyPass.renderToScreen = true;
composer.addPass(copyPass);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
controls = new THREE.OrbitControls( camera );
controls.target.set( 0, 0, 0 );
controls.update();
window.addEventListener( 'resize', onWindowResize, false );
var gui = new dat.GUI();
gui.add( params, 'roughness', 0, 1 );
gui.add( params, 'bumpScale', -1, 1 );
gui.open();
}
function onWindowResize() {
var width = window.innerWidth;
var height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
composer.setSize( width, height );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
if(standardMaterial !== undefined) {
standardMaterial.roughness = params.roughness;
standardMaterial.bumpScale = -0.05 * params.bumpScale;
}
var timer = Date.now() * 0.00025;
camera.lookAt( scene.position );
for ( var i = 0, l = objects.length; i < l; i ++ ) {
var object = objects[ i ];
object.rotation.y += 0.005;
}
composer.render();
}
</script>
</body>
</html>
......@@ -219,6 +219,8 @@ THREE.EquirectangularReflectionMapping = 303;
THREE.EquirectangularRefractionMapping = 304;
THREE.SphericalReflectionMapping = 305;
THREE.CubeUVReflectionMapping = 306;
THREE.CubeUVRefractionMapping = 307;
// Wrapping modes
......
......@@ -148,3 +148,7 @@ vec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in Ge
float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {
return ( 2.0 / square( ggxRoughness + 0.0001 ) - 2.0 );
}
float BlinnExponentToGGXRoughness( const in float blinnExponent ) {
return sqrt( 2.0 / ( blinnExponent + 2.0 ) );
}
#ifdef ENVMAP_TYPE_CUBE_UV
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;
}
vec2 MipLevelInfo( vec3 vec, float textureSize, float roughnessLevel, float roughness ) {
float s = log2(textureSize*0.25) - 1.0;
float scale = pow(2.0, s - 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
float rangeClamp = pow(2.0, (6.0 - 1.0) * 2.0);
d = clamp(d, 1.0, rangeClamp);
float mipLevel = 0.5 * log2(d);
return vec2(floor(mipLevel), fract(mipLevel));
}
vec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel, float textureSize) {
float maxLods = log2(textureSize*0.25) - 2.0;
mipLevel = roughnessLevel > maxLods - 3.0 ? 0.0 : mipLevel;
float a = 16.0/textureSize;
float powScale = pow(2.0,roughnessLevel + mipLevel);
float scale = 1.0/pow(2.0,roughnessLevel + 2.0 + mipLevel);
float mipOffset = 0.75*(1.0 - 1.0/pow(2.0, mipLevel))/pow(2.0,roughnessLevel);
bool bRes = mipLevel == 0.0;
scale = bRes && (scale < a) ? a : scale;
vec3 r;
vec2 offset;
int face = getFaceFromDirection(direction);
if( face == 0) {
r = vec3(direction.x, -direction.z, direction.y);
offset = vec2(0.0+mipOffset,0.75/powScale);
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/powScale);
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/powScale);
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/powScale);
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/powScale);
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/powScale);
offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;
}
r = normalize(r);
float texelOffset = 0.5/textureSize;
float s1 = (r.y/abs(r.x) + 1.0)*0.5;
float s2 = (r.z/abs(r.x) + 1.0)*0.5;
vec2 uv = offset + vec2(s1*scale, s2*scale);
float min_x = offset.x + texelOffset; float max_x = offset.x + scale - texelOffset;
float min_y = offset.y + texelOffset;
float max_y = offset.y + scale - texelOffset;
float delx = max_x - min_x;
float dely = max_y - min_y;
uv.x = min_x + s1*delx;
uv.y = min_y + s2*dely;
return uv;
}
vec3 convertRGBEToRGB(vec4 rgbe) {
float d = pow(2.0, rgbe.w*256.0 - 128.0);
return vec3(rgbe) * d;
}
vec3 tonemap(vec3 RGB) {
float LogAvgLum = 0.08;//0.08
float key = 1.0;
float Ywhite = 1e3;
Ywhite *= Ywhite;
float sat = 1.0;
float Ylum = dot(RGB ,vec3(0.2126, 0.7152, 0.0722));
float Y = key/LogAvgLum * Ylum ;
float Yd = Y * ( 1.0 + Y/Ywhite)/( 1.0 + Y) ;
return Yd * pow(RGB/Ylum ,vec3(sat, sat, sat));
}
vec4 textureCubeUV(vec3 reflectedDirection, float roughness, float textureSize) {
float maxLods = log2(textureSize*0.25) - 3.0;
float roughnessVal = roughness*maxLods;
float r1 = floor(roughnessVal);
float r2 = r1 + 1.0;
float t = fract(roughnessVal);
vec2 mipInfo = MipLevelInfo(reflectedDirection, textureSize, r1, roughness);
float s = mipInfo.y;
float level0 = mipInfo.x;
float level1 = level0 + 1.0;
level1 = level1 > 5.0 ? 5.0 : level1;
// Tri linear interpolation.
vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0, textureSize);
vec2 uv_11 = getCubeUV(reflectedDirection, r1, level1, textureSize);
vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, textureSize);
vec2 uv_21 = getCubeUV(reflectedDirection, r2, level1, textureSize);
vec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));
vec4 color11 = envMapTexelToLinear(texture2D(envMap, uv_11));
vec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));
vec4 color21 = envMapTexelToLinear(texture2D(envMap, uv_21));
vec4 c1 = mix(color10 , color11, s);
vec4 c2 = mix(color20 , color21, s);
vec4 c3 = mix(c1 , c2, t);
return vec4(c3.rgb, 1.0);
}
#endif
......@@ -19,12 +19,13 @@ vec4 LinearTosRGB( in vec4 value ) {
}
vec4 RGBEToLinear( in vec4 value ) {
return vec4( value.xyz * exp2( value.w*256.0 - 128.0 ), 1.0 );
return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );
}
vec4 LinearToRGBE( in vec4 value ) {
float maxComponent = max(max(value.r, value.g), value.b );
float fExp = ceil( log2(maxComponent) );
return vec4( value.rgb / exp2(fExp), (fExp + 128.0) / 255.0 );
float maxComponent = max( max( value.r, value.g ), value.b );
float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );
return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );
// return vec4( value.brg, ( 3.0 + 128.0 ) / 256.0 );
}
// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
......@@ -33,7 +34,7 @@ vec4 RGBMToLinear( in vec4 value, in float maxRange ) {
}
vec4 LinearToRGBM( in vec4 value, in float maxRange ) {
float maxRGB = max( value.x, max( value.g, value.b ) );
float M = maxRGB / maxRange;
float M = clamp( maxRGB / maxRange, 0.0, 1.0 );
M = ceil( M * 255.0 ) / 255.0;
return vec4( value.rgb / ( M * maxRange ), M );
}
......
......@@ -179,6 +179,11 @@
#endif
#elif defined( ENVMAP_TYPE_CUBE_UV )
vec3 queryVec = flipNormal * vec3( flipEnvMap * worldNormal.x, worldNormal.yz );
vec4 envMapColor = textureCubeUV(queryVec, 1.0, 1024.0);
#else
vec3 envMapColor = vec3( 0.0 );
......@@ -245,6 +250,11 @@
#endif
#elif defined( ENVMAP_TYPE_CUBE_UV )
vec3 queryReflectVec = flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz );
vec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent), 1024.0);
#elif defined( ENVMAP_TYPE_EQUIREC )
vec2 sampleUV;
......
......@@ -101,12 +101,12 @@ IncidentLight directLight;
#endif
// #if defined( USE_ENVMAP ) && defined( STANDARD )
#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )
// TODO, replace 8 with the real maxMIPLevel
// irradiance += getLightProbeIndirectIrradiance( /*lightProbe,*/ geometry, 8 ); // comment out until seams are fixed
irradiance += getLightProbeIndirectIrradiance( /*lightProbe,*/ geometry, 8 );
// #endif
#endif
RE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );
......
......@@ -29,6 +29,7 @@ varying vec3 vViewPosition;
#include <fog_pars_fragment>
#include <bsdfs>
#include <ambient_pars>
#include <cube_uv_reflection_fragment>
#include <lights_pars>
#include <lights_standard_pars_fragment>
#include <shadowmap_pars_fragment>
......
......@@ -51,7 +51,7 @@ THREE.WebGLProgram = ( function () {
extensions = extensions || {};
var chunks = [
( extensions.derivatives || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '',
......@@ -279,6 +279,11 @@ THREE.WebGLProgram = ( function () {
envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
break;
case THREE.CubeUVReflectionMapping:
case THREE.CubeUVRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
break;
case THREE.EquirectangularReflectionMapping:
case THREE.EquirectangularRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
......
......@@ -70,18 +70,17 @@ THREE.WebGLPrograms = function ( renderer, capabilities ) {
function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
var encoding;
if( ! map ) {
encoding = THREE.LinearEncoding;
}
else if( map instanceof THREE.Texture ) {
else if( map instanceof THREE.Texture || map instanceof THREE.CubeTexture ) {
encoding = map.encoding;
}
else if( map instanceof THREE.WebGLRenderTarget ) {
else if( map instanceof THREE.WebGLRenderTarget || map instanceof THREE.THREE.WebGLRenderTargetCube ) {
encoding = map.texture.encoding;
......@@ -129,6 +128,8 @@ THREE.WebGLPrograms = function ( renderer, capabilities ) {
envMap: !! material.envMap,
envMapMode: material.envMap && material.envMap.mapping,
envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
envMapCubeUV: (!!material.envMap) && ((material.envMap.mapping === THREE.CubeUVReflectionMapping) ||
(material.envMap.mapping === THREE.CubeUVRefractionMapping)),
lightMap: !! material.lightMap,
aoMap: !! material.aoMap,
emissiveMap: !! material.emissiveMap,
......
......@@ -132,6 +132,7 @@
"src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl",
"src/renderers/shaders/ShaderChunk/color_vertex.glsl",
"src/renderers/shaders/ShaderChunk/common.glsl",
"src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl",
"src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl",
"src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl",
"src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册