未验证 提交 5902347b 编写于 作者: M Mr.doob 提交者: GitHub

Merge pull request #17167 from sunag/dev-fix-nodes

NodeMaterial: Fix irradiance
......@@ -82,6 +82,7 @@ export { VelocityNode } from './utils/VelocityNode.js';
export { UVTransformNode } from './utils/UVTransformNode.js';
export { MaxMIPLevelNode } from './utils/MaxMIPLevelNode.js';
export { ColorSpaceNode } from './utils/ColorSpaceNode.js';
export { SubSlotNode } from './utils/SubSlotNode.js';
// effects
......
......@@ -449,6 +449,12 @@ NodeBuilder.prototype = {
},
require: function ( name ) {
this.requires[ name ] = true;
},
isDefined: function ( name ) {
return this.defines[ name ] !== undefined;
......
......@@ -153,7 +153,20 @@ StandardNode.prototype.build = function ( builder ) {
if ( this.shadow ) this.shadow.analyze( builder );
if ( this.emissive ) this.emissive.analyze( builder, { slot: 'emissive' } );
if ( this.environment ) this.environment.analyze( builder, { cache: 'env', context: contextEnvironment, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
if ( this.environment ) {
// isolate environment from others inputs ( see TextureNode, CubeTextureNode )
// environment.analyze will detect if there is a need of calculate irradiance
this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } );
if ( builder.requires.irradiance ) {
this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
}
}
// build code
......@@ -179,7 +192,21 @@ StandardNode.prototype.build = function ( builder ) {
var shadow = this.shadow ? this.shadow.flow( builder, 'c' ) : undefined;
var emissive = this.emissive ? this.emissive.flow( builder, 'c', { slot: 'emissive' } ) : undefined;
var environment = this.environment ? this.environment.flow( builder, 'c', { cache: 'env', context: contextEnvironment, slot: 'environment' } ) : undefined;
var environment;
if ( this.environment ) {
environment = {
radiance: this.environment.flow( builder, 'c', { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } )
};
if ( builder.requires.irradiance ) {
environment.irradiance = this.environment.flow( builder, 'c', { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
}
}
var clearCoatEnv = useClearCoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined;
......@@ -371,7 +398,13 @@ StandardNode.prototype.build = function ( builder ) {
if ( environment ) {
output.push( environment.code );
output.push( environment.radiance.code );
if ( builder.requires.irradiance ) {
output.push( environment.irradiance.code );
}
if ( clearCoatEnv ) {
......@@ -382,11 +415,11 @@ StandardNode.prototype.build = function ( builder ) {
}
output.push( "radiance += " + environment.result + ";" );
output.push( "radiance += " + environment.radiance.result + ";" );
if ( environment.extra.irradiance ) {
if ( builder.requires.irradiance ) {
output.push( "irradiance += PI * " + environment.extra.irradiance + ";" );
output.push( "irradiance += PI * " + environment.irradiance.result + ";" );
}
......
......@@ -79,12 +79,12 @@ TextureCubeNode.prototype.generate = function ( builder, output ) {
if ( builder.isShader( 'fragment' ) ) {
var radiance = this.generateTextureCubeUV( builder, this.radianceCache );
var irradiance = this.generateTextureCubeUV( builder, this.irradianceCache );
builder.require( 'irradiance' );
builder.context.extra.irradiance = irradiance;
var cache = builder.slot === 'irradiance' ? this.irradianceCache : this.radianceCache;
var result = this.generateTextureCubeUV( builder, cache );
return builder.format( 'vec4( ' + radiance + ', 1.0 )', this.getType( builder ), output );
return builder.format( 'vec4( ' + result + ', 1.0 )', this.getType( builder ), output );
} else {
......@@ -96,6 +96,16 @@ TextureCubeNode.prototype.generate = function ( builder, output ) {
};
TextureCubeNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.value = source.value;
return this;
};
TextureCubeNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......
import { TempNode } from '../core/TempNode';
import { NodeBuilder } from '../core/NodeBuilder';
export class SubSlots extends TempNode {
constructor(slots?: object);
slots: Node[];
generate(builder: NodeBuilder, output: string): string;
copy(source: SubSlots): this;
}
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
function SubSlotNode( slots ) {
TempNode.call( this );
this.slots = slots || {};
}
SubSlotNode.prototype = Object.create( TempNode.prototype );
SubSlotNode.prototype.constructor = SubSlotNode;
SubSlotNode.prototype.nodeType = "SubSlot";
SubSlotNode.prototype.getType = function ( builder, output ) {
return output;
};
SubSlotNode.prototype.generate = function ( builder, output ) {
if ( this.slots[ builder.slot ] ) {
return this.slots[ builder.slot ].build( builder, output )
}
return builder.format( '0.0', 'f', output );
};
SubSlotNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
for ( var prop in source.slots ) {
this.slots[ prop ] = source.slots[ prop ];
}
return this;
};
SubSlotNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.slots = {};
for ( var prop in this.slots ) {
var slot = this.slots[ prop ];
if ( slot ) {
data.slots[ prop ] = slot.toJSON( meta ).uuid;
}
}
}
return data;
};
export { SubSlotNode };
......@@ -46,6 +46,7 @@
import {
StandardNodeMaterial,
FloatNode,
OperatorNode,
TextureNode,
TextureCubeNode
} from './jsm/nodes/Nodes.js';
......@@ -55,13 +56,14 @@
roughness: 0.0,
metalness: 0.0,
exposure: 1.0,
intensity: 1.0,
animate: true,
debug: false
};
var container, stats;
var camera, scene, renderer, controls;
var nodeMaterial, nodeTexture, nodeTextureSize, torusMesh, planeMesh;
var nodeMaterial, nodeTexture, nodeTextureSize, nodeTextureIntensity, torusMesh, planeMesh;
var hdrCubeRenderTarget;
var hdrCubeMap;
......@@ -118,8 +120,9 @@
nodeTexture = new TextureNode();
nodeTextureSize = new FloatNode( 1024 );
nodeTextureIntensity = new FloatNode( 1 );
nodeMaterial.environment = new TextureCubeNode( nodeTexture, nodeTextureSize );
nodeMaterial.environment = new OperatorNode( new TextureCubeNode( nodeTexture, nodeTextureSize ), nodeTextureIntensity, OperatorNode.MUL );
torusMesh = new THREE.Mesh( geometry, nodeMaterial );
scene.add( torusMesh );
......@@ -164,6 +167,7 @@
gui.add( params, 'roughness', 0, 1, 0.01 );
gui.add( params, 'metalness', 0, 1, 0.01 );
gui.add( params, 'exposure', 0, 2, 0.01 );
gui.add( params, 'intensity', 0, 2, 0.01 );
gui.add( params, 'animate', true );
gui.add( params, 'debug', false );
gui.open();
......@@ -197,6 +201,8 @@
torusMesh.material.roughness.value = params.roughness;
torusMesh.material.metalness.value = params.metalness;
nodeTextureIntensity.value = params.intensity;
if ( nodeTextureSize.value !== params.textureSize ) {
generate( params.textureSize );
......
......@@ -20,14 +20,20 @@
import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { NodeMaterialLoader, NodeMaterialLoaderUtils } from './jsm/loaders/NodeMaterialLoader.js';
import { TeapotBufferGeometry } from './jsm/geometries/TeapotBufferGeometry.js';
import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js';
import { NodeMaterialLoader, NodeMaterialLoaderUtils } from './jsm/loaders/NodeMaterialLoader.js';
import * as Nodes from './jsm/nodes/Nodes.js';
var container = document.getElementById( 'container' );
var renderer, scene, camera, clock = new THREE.Clock(), fov = 50;
var renderer, scene, lightGroup, camera, clock = new THREE.Clock(), fov = 50;
var frame = new Nodes.NodeFrame();
var teapot, mesh;
var controls;
......@@ -84,6 +90,45 @@
}();
function generatePREM( cubeMap, textureSize ) {
textureSize = textureSize || 1024;
var pmremGenerator = new PMREMGenerator( cubeMap, undefined, textureSize / 4 );
pmremGenerator.update( renderer );
var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
pmremCubeUVPacker.update( renderer );
pmremGenerator.dispose();
pmremCubeUVPacker.dispose();
return pmremCubeUVPacker.CubeUVRenderTarget.texture;
}
var premTexture;
function getPREM( callback, textureSize ) {
if ( premTexture ) return callback( premTexture );
var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
var hdrCubeMap = new HDRCubeTextureLoader()
.setPath( './textures/cube/pisaHDR/' )
.setDataType( THREE.UnsignedByteType )
.load( hdrUrls, function () {
premTexture = generatePREM( hdrCubeMap, textureSize );
library[ premTexture.uuid ] = premTexture;
callback( premTexture );
} );
}
window.addEventListener( 'load', init );
function init() {
......@@ -107,15 +152,20 @@
controls.minDistance = 50;
controls.maxDistance = 200;
scene.add( new THREE.AmbientLight( 0x464646 ) );
lightGroup = new THREE.Group();
scene.add( lightGroup );
var light;
lightGroup.add( new THREE.AmbientLight( 0x464646 ) );
var light = new THREE.DirectionalLight( 0xffddcc, 1 );
light = new THREE.DirectionalLight( 0xffddcc, 1 );
light.position.set( 1, 0.75, 0.5 );
scene.add( light );
lightGroup.add( light );
var light = new THREE.DirectionalLight( 0xccccff, 1 );
light = new THREE.DirectionalLight( 0xccccff, 1 );
light.position.set( - 1, 0.75, - 0.5 );
scene.add( light );
lightGroup.add( light );
teapot = new TeapotBufferGeometry( 15, 18 );
......@@ -145,6 +195,7 @@
'basic / mesh-standard': 'mesh-standard',
'basic / standard': 'standard',
'basic / physical': 'physical',
'basic / prem': 'prem',
'basic / phong': 'phong',
'basic / layers': 'layers',
'basic / rim': 'rim',
......@@ -178,6 +229,7 @@
'node / position': 'node-position',
'node / normal': 'node-normal',
'node / reflect': 'node-reflect',
'misc / sub-slot': 'sub-slot',
'misc / smoke': 'smoke',
'misc / firefly': 'firefly',
'misc / reserved-keywords': 'reserved-keywords',
......@@ -238,6 +290,8 @@
move = false;
lightGroup.visible = true;
if ( mesh.material ) mesh.material.dispose();
if ( rtTexture ) {
......@@ -393,6 +447,193 @@
break;
case 'prem':
// MATERIAL
mtl = new Nodes.StandardNodeMaterial();
//mtl.color = // albedo (vec3)
//mtl.alpha = // opacity (float)
//mtl.roughness = // roughness (float)
//mtl.metalness = // metalness (float)
//mtl.normal = // normal (vec3)
//mtl.emissive = // emissive color (vec3)
//mtl.ambient = // ambient color (vec3)
//mtl.shadow = // shadowmap (vec3)
//mtl.light = // custom-light (vec3)
//mtl.ao = // ambient occlusion (float)
//mtl.environment = // reflection/refraction (vec3)
//mtl.position = // vertex local position (vec3)
var mask = new Nodes.SwitchNode( new Nodes.TextureNode( getTexture( "decalDiffuse" ) ), 'w' );
var intensity = new Nodes.FloatNode( 1 );
var normalScale = new Nodes.FloatNode( .3 );
var roughnessA = new Nodes.FloatNode( .5 );
var metalnessA = new Nodes.FloatNode( .5 );
var roughnessB = new Nodes.FloatNode( 0 );
var metalnessB = new Nodes.FloatNode( 1 );
var roughness = new Nodes.MathNode(
roughnessA,
roughnessB,
mask,
Nodes.MathNode.MIX
);
var metalness = new Nodes.MathNode(
metalnessA,
metalnessB,
mask,
Nodes.MathNode.MIX
);
var normalMask = new Nodes.OperatorNode(
new Nodes.MathNode( mask, Nodes.MathNode.INVERT ),
normalScale,
Nodes.OperatorNode.MUL
);
mtl.color = new Nodes.ColorNode( 0xEEEEEE );
mtl.roughness = roughness;
mtl.metalness = metalness;
mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
mtl.normal.scale = normalMask;
getPREM(function(texture) {
var envNode = new Nodes.TextureCubeNode( new Nodes.TextureNode( texture ) );
mtl.environment = new Nodes.OperatorNode( envNode, intensity, Nodes.OperatorNode.MUL );
mtl.needsUpdate = true;
});
// GUI
addGui( 'color', mtl.color.value.getHex(), function ( val ) {
mtl.color.value.setHex( val );
}, true );
addGui( 'intensity', intensity.value, function ( val ) {
intensity.value = val;
}, false, 0, 2 );
addGui( 'roughnessA', roughnessA.value, function ( val ) {
roughnessA.value = val;
}, false, 0, 1 );
addGui( 'metalnessA', metalnessA.value, function ( val ) {
metalnessA.value = val;
}, false, 0, 1 );
addGui( 'roughnessB', roughnessB.value, function ( val ) {
roughnessB.value = val;
}, false, 0, 1 );
addGui( 'metalnessB', metalnessB.value, function ( val ) {
metalnessB.value = val;
}, false, 0, 1 );
addGui( 'normalScale', normalScale.value, function ( val ) {
normalScale.value = val;
}, false, 0, 1 );
break;
case 'sub-slot':
// disable dynamic light
lightGroup.visible = false;
// MATERIAL
mtl = new Nodes.StandardNodeMaterial();
// NODES
var mask = new Nodes.SwitchNode( new Nodes.TextureNode( getTexture( "decalDiffuse" ) ), 'w' );
var normalScale = new Nodes.FloatNode( .3 );
var radiance = new Nodes.FloatNode( 1 );
var irradiance = new Nodes.FloatNode( 1 );
var roughness = new Nodes.FloatNode( .5 );
var metalness = new Nodes.FloatNode( .5 );
mtl.color = new Nodes.ColorNode( 0xEEEEEE );
mtl.roughness = roughness;
mtl.metalness = metalness;
mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
mtl.normal.scale = normalScale;
getPREM(function(texture) {
var envNode = new Nodes.TextureCubeNode( new Nodes.TextureNode( texture ) );
var subSlotNode = new Nodes.SubSlotNode();
subSlotNode.slots['radiance'] = new Nodes.OperatorNode( radiance, envNode, Nodes.OperatorNode.MUL );
subSlotNode.slots['irradiance'] = new Nodes.OperatorNode( irradiance, envNode, Nodes.OperatorNode.MUL );
mtl.environment = subSlotNode;
mtl.needsUpdate = true;
});
// GUI
addGui( 'radiance', radiance.value, function ( val ) {
radiance.value = val;
}, false, 0, 2 );
addGui( 'irradiance', irradiance.value, function ( val ) {
irradiance.value = val;
}, false, 0, 2 );
addGui( 'roughness', roughness.value, function ( val ) {
roughness.value = val;
}, false, 0, 1 );
addGui( 'metalness', metalness.value, function ( val ) {
metalness.value = val;
}, false, 0, 1 );
addGui( 'normalScale', normalScale.value, function ( val ) {
normalScale.value = val;
}, false, 0, 1 );
break;
case 'mesh-standard':
// MATERIAL
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册