未验证 提交 3492536c 编写于 作者: M Michael Herzog 提交者: GitHub

Merge pull request #18161 from sunag/dev-nodematerial-prem

NodeMaterial: PREM Update
......@@ -54,7 +54,7 @@ ReflectNode.prototype.generate = function ( builder, output ) {
case ReflectNode.VECTOR:
var viewNormalNode = builder.context.viewNormal || new NormalNode();
var viewNormalNode = builder.context.viewNormal || new NormalNode( NormalNode.VIEW );
var roughnessNode = builder.context.roughness;
var viewNormal = viewNormalNode.build( builder, 'v3' );
......@@ -63,7 +63,7 @@ ReflectNode.prototype.generate = function ( builder, output ) {
var method = `reflect( -normalize( ${viewPosition} ), ${viewNormal} )`;
if ( viewNormalNode && roughness ) {
if ( roughness ) {
// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
method = `normalize( mix( ${method}, ${viewNormal}, ${roughness} * ${roughness} ) )`;
......
......@@ -10,26 +10,24 @@ import { ReflectNode } from '../accessors/ReflectNode.js';
import { NormalNode } from '../accessors/NormalNode.js';
import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
function TextureCubeNode( value, textureSize, uv, bias ) {
function TextureCubeNode( value, uv, bias ) {
TempNode.call( this, 'v4' );
this.value = value;
textureSize = textureSize || new FloatNode( 1024 );
this.radianceCache = { uv: new TextureCubeUVNode(
this.radianceNode = new TextureCubeUVNode(
this.value,
uv || new ReflectNode( ReflectNode.VECTOR ),
textureSize,
// bias should be replaced in builder.context in build process
bias
) };
);
this.irradianceCache = { uv: new TextureCubeUVNode(
this.irradianceNode = new TextureCubeUVNode(
this.value,
new NormalNode( NormalNode.WORLD ),
textureSize,
new FloatNode( 1 ).setReadonly( true )
) };
);
}
......@@ -37,45 +35,6 @@ TextureCubeNode.prototype = Object.create( TempNode.prototype );
TextureCubeNode.prototype.constructor = TextureCubeNode;
TextureCubeNode.prototype.nodeType = "TextureCube";
TextureCubeNode.prototype.generateTextureCubeUV = function ( builder, cache ) {
var uv_10 = cache.uv.build( builder ) + '.uv_10',
uv_20 = cache.uv.build( builder ) + '.uv_20',
t = cache.uv.build( builder ) + '.t';
var color10 = 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_10 + ' )',
color20 = 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_20 + ' )';
// 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 };
var outputType = this.getType( builder );
builder.addContext( context );
cache.colorSpace10 = cache.colorSpace10 || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
cache.colorSpace10.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
cache.colorSpace10.input.parse( color10 );
color10 = cache.colorSpace10.build( builder, outputType );
cache.colorSpace20 = cache.colorSpace20 || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
cache.colorSpace20.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
cache.colorSpace20.input.parse( color20 );
color20 = cache.colorSpace20.build( builder, outputType );
// end custom context
builder.removeContext();
return 'mix( ' + color10 + ', ' + color20 + ', ' + t + ' ).rgb';
};
TextureCubeNode.prototype.generate = function ( builder, output ) {
if ( builder.isShader( 'fragment' ) ) {
......@@ -88,10 +47,9 @@ TextureCubeNode.prototype.generate = function ( builder, output ) {
}
var cache = builder.slot === 'irradiance' ? this.irradianceCache : this.radianceCache;
var result = this.generateTextureCubeUV( builder, cache );
var scopeNode = builder.slot === 'irradiance' ? this.irradianceNode : this.radianceNode;
return builder.format( 'vec4( ' + result + ', 1.0 )', this.getType( builder ), output );
return scopeNode.build( builder, output );
} else {
......
......@@ -6,157 +6,159 @@ 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 { ReflectNode } from '../accessors/ReflectNode.js';
import { FloatNode } from '../inputs/FloatNode.js';
import { OperatorNode } from '../math/OperatorNode.js';
import { MathNode } from '../math/MathNode.js';
import { CondNode } from '../math/CondNode.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 +167,92 @@ 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' );
var f = bilinearCubeUV.build( builder ) + '.f';
// 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 +272,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;
}
......
<!DOCTYPE html>
<html lang="en">
<head>
<title>threejs webgl - node material - hdr environment mapping</title>
<title>threejs webgl - materials - hdr environment mapping</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;
}
a { color: #00f }
#info {
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
</style>
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="container"></div>
<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - High dynamic range (RGBE) Image-based Lighting (IBL)<br />using run-time generated pre-filtered roughness mipmaps (PMREM)<br/>
Created by Prashant Sharma and <a href="http://clara.io/" target="_blank" rel="noopener">Ben Houston</a>.</div>
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - High dynamic range (RGBE) Image-based Lighting (IBL)<br />using run-time generated pre-filtered roughness mipmaps (PMREM)<br/>
Created by Prashant Sharma and <a href="http://clara.io/" target="_blank" rel="noopener">Ben Houston</a>.
</div>
<script type="module">
......@@ -41,6 +24,7 @@
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
import { MeshStandardNodeMaterial } from './jsm/nodes/Nodes.js';
var params = {
......@@ -50,18 +34,53 @@
exposure: 1.0,
nodes: true,
animate: true,
debug: false,
debug: false
};
var container, stats;
var camera, scene, renderer, controls;
var torusMesh, torusMeshNode, planeMesh;
var ldrCubeRenderTarget, hdrCubeRenderTarget, rgbmCubeRenderTarget;
var generatedCubeRenderTarget, ldrCubeRenderTarget, hdrCubeRenderTarget, rgbmCubeRenderTarget;
var ldrCubeMap, hdrCubeMap, rgbmCubeMap;
init();
animate();
function getEnvScene() {
var envScene = new THREE.Scene();
var geometry = new THREE.BoxBufferGeometry();
geometry.deleteAttribute('uv');
var roomMaterial = new THREE.MeshStandardMaterial({metalness: 0, side: THREE.BackSide});
var room = new THREE.Mesh(geometry, roomMaterial);
room.scale.setScalar(10);
envScene.add(room);
var mainLight = new THREE.PointLight(0xffffff, 50, 0, 2);
envScene.add(mainLight);
var lightMaterial = new THREE.MeshLambertMaterial( { color: 0x000000, emissive: 0xffffff, emissiveIntensity: 10 } );
var light1 = new THREE.Mesh(geometry, lightMaterial);
light1.position.set(-5, 2, 0);
light1.scale.set(0.1, 1, 1);
envScene.add(light1);
var light2 = new THREE.Mesh(geometry, lightMaterial);
light2.position.set(0, 5, 0);
light2.scale.set(1, 0.1, 1);
envScene.add(light2);
var light2 = new THREE.Mesh(geometry, lightMaterial);
light2.position.set(2, 1, 5);
light2.scale.set(1.5, 2, 0.1);
envScene.add(light2);
return envScene;
}
function init() {
container = document.createElement( 'div' );
......@@ -74,6 +93,7 @@
scene.background = new THREE.Color( 0x000000 );
renderer = new THREE.WebGLRenderer();
renderer.physicallyCorrectLights = true;
renderer.toneMapping = THREE.LinearToneMapping;
//
......@@ -97,7 +117,10 @@
torusMeshNode = new THREE.Mesh( geometry, material );
scene.add( torusMeshNode );
planeMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 200, 200 ), new THREE.MeshBasicMaterial() );
var geometry = new THREE.PlaneBufferGeometry( 200, 200 );
var material = new THREE.MeshBasicMaterial();
planeMesh = new THREE.Mesh( geometry, material );
planeMesh.position.y = - 50;
planeMesh.rotation.x = - Math.PI * 0.5;
scene.add( planeMesh );
......@@ -109,6 +132,9 @@
}
var envScene = getEnvScene();
generatedCubeRenderTarget = pmremGenerator.fromScene( envScene, 0.04 );
var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
hdrCubeMap = new HDRCubeTextureLoader()
.setPath( './textures/cube/pisaHDR/' )
......@@ -153,7 +179,7 @@
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//renderer.toneMapping = THREE.ReinhardToneMapping;
//renderer.toneMapping = ReinhardToneMapping;
renderer.outputEncoding = THREE.sRGBEncoding;
stats = new Stats();
......@@ -167,7 +193,7 @@
var gui = new GUI();
gui.add( params, 'envMap', [ 'LDR', 'HDR', 'RGBM16' ] );
gui.add( params, 'envMap', [ 'Generated', 'LDR', 'HDR', 'RGBM16' ] );
gui.add( params, 'roughness', 0, 1, 0.01 );
gui.add( params, 'metalness', 0, 1, 0.01 );
gui.add( params, 'exposure', 0, 2, 0.01 );
......@@ -202,19 +228,23 @@
function render() {
torusMesh.visible = ! params.nodes;
torusMeshNode.visible = params.nodes;
torusMesh.material.roughness = params.roughness;
torusMesh.material.metalness = params.metalness;
torusMeshNode.material.roughness = params.roughness;
torusMeshNode.material.metalness = params.metalness;
torusMesh.visible = ! params.nodes;
torusMeshNode.visible = params.nodes;
var renderTarget, cubeMap;
switch ( params.envMap ) {
case 'Generated':
renderTarget = generatedCubeRenderTarget;
cubeMap = generatedCubeRenderTarget.texture;
break;
case 'LDR':
renderTarget = ldrCubeRenderTarget;
cubeMap = ldrCubeMap;
......
......@@ -51,7 +51,6 @@
} from './jsm/nodes/Nodes.js';
var params = {
textureSize: 1024,
roughness: 0.0,
metalness: 0.0,
exposure: 1.0,
......@@ -62,16 +61,14 @@
var container, stats;
var camera, scene, renderer, controls;
var nodeMaterial, nodeTexture, nodeTextureSize, nodeTextureIntensity, torusMesh, planeMesh;
var nodeMaterial, nodeTexture, nodeTextureIntensity, torusMesh, planeMesh;
var hdrCubeRenderTarget;
var hdrCubeMap;
init();
animate();
function generate( textureSize ) {
nodeTextureSize.value = textureSize;
function generate() {
var pmremGenerator = new PMREMGenerator( renderer );
hdrCubeRenderTarget = pmremGenerator.fromCubemap( hdrCubeMap );
......@@ -112,10 +109,9 @@
nodeMaterial.visible = false;
nodeTexture = new TextureNode();
nodeTextureSize = new FloatNode( 1024 );
nodeTextureIntensity = new FloatNode( 1 );
nodeMaterial.environment = new OperatorNode( new TextureCubeNode( nodeTexture, nodeTextureSize ), nodeTextureIntensity, OperatorNode.MUL );
nodeMaterial.environment = new OperatorNode( new TextureCubeNode( nodeTexture ), nodeTextureIntensity, OperatorNode.MUL );
torusMesh = new THREE.Mesh( geometry, nodeMaterial );
scene.add( torusMesh );
......@@ -131,7 +127,7 @@
.setDataType( THREE.UnsignedByteType )
.load( hdrUrls, function () {
generate( params.textureSize );
generate();
nodeMaterial.visible = true;
......@@ -155,7 +151,6 @@
var gui = new GUI();
gui.add( params, 'textureSize', [ 128, 256, 512, 1024, 2048, 4096 ] );
gui.add( params, 'roughness', 0, 1, 0.01 );
gui.add( params, 'metalness', 0, 1, 0.01 );
gui.add( params, 'exposure', 0, 2, 0.01 );
......@@ -195,12 +190,6 @@
nodeTextureIntensity.value = params.intensity;
if ( nodeTextureSize.value !== params.textureSize ) {
generate( params.textureSize );
}
if ( params.animate ) {
torusMesh.rotation.y += 0.005;
......
......@@ -98,35 +98,6 @@ vec3 bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {
#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;
}
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;
}
float roughnessToMip(float roughness) {
float mip = 0.0;
if (roughness >= r1) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册