浏览代码

Nodes: Sheen (#24389)

* Nodes: add support for sheen

* add sheen nodes example
sunag 3 年之前
父节点
当前提交
927a477606

+ 1 - 0
examples/files.json

@@ -228,6 +228,7 @@
 		"webgl_water_flowmap"
 	],
 	"webgl / nodes": [
+		"webgl_loader_gltf_sheen_nodes",
 		"webgl_materials_instance_uniform_nodes",
 		"webgl_materials_physical_clearcoat_nodes",
 		"webgl_materials_standard_nodes",

+ 6 - 0
examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js

@@ -16,6 +16,9 @@ export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
 		this.clearcoatRoughnessNode = null;
 		this.clearcoatNormalNode = null;
 
+		this.sheenNode = null;
+		this.sheenRoughnessNode = null;
+
 		this.sheen = 0;
 		this.clearcoat = 0;
 		this.iridescence = 0;
@@ -33,6 +36,9 @@ export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
 		this.clearcoatRoughnessNode = source.clearcoatRoughnessNode;
 		this.clearcoatNormalNode = source.clearcoatNormalNode;
 
+		this.sheenNode = source.sheenNode;
+		this.sheenRoughnessNode = source.sheenRoughnessNode;
+
 		return super.copy( source );
 
 	}

+ 50 - 10
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -158,6 +158,24 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 			}
 
+			if ( material.sheenNode && material.sheenNode.isNode ) {
+
+				this.addSlot( 'fragment', new SlotNode( material.sheenNode, 'SHEEN', 'vec3' ) );
+
+				if ( material.sheenRoughnessNode && material.sheenRoughnessNode.isNode ) {
+
+					this.addSlot( 'fragment', new SlotNode( material.sheenRoughnessNode, 'SHEEN_ROUGHNESS', 'float' ) );
+
+				}
+
+				material.defines.USE_SHEEN = '';
+
+			} else {
+
+				delete material.defines.USE_SHEEN;
+
+			}
+
 		}
 
 		if ( material.iridescenceNode && material.iridescenceNode.isNode ) {
@@ -458,6 +476,8 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 		const clearcoatNode = this.getSlot( 'fragment', 'CLEARCOAT' );
 		const clearcoatRoughnessNode = this.getSlot( 'fragment', 'CLEARCOAT_ROUGHNESS' );
 		const clearcoatNormalNode = this.getSlot( 'fragment', 'CLEARCOAT_NORMAL' );
+		const sheenNode = this.getSlot( 'fragment', 'SHEEN' );
+		const sheenRoughnessNode = this.getSlot( 'fragment', 'SHEEN_ROUGHNESS' );
 		const iridescenceNode = this.getSlot( 'fragment', 'IRIDESCENCE' );
 		const iridescenceIORNode = this.getSlot( 'fragment', 'IRIDESCENCE_IOR' );
 		const iridescenceThicknessNode = this.getSlot( 'fragment', 'IRIDESCENCE_THICKNESS' );
@@ -533,26 +553,46 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 				`${clearcoatNode.code}\n\tmaterial.clearcoat = ${clearcoatNode.result};`
 			);
 
-		}
+			if ( clearcoatRoughnessNode !== undefined ) {
 
-		if ( clearcoatRoughnessNode !== undefined ) {
+				this.addCodeAfterSnippet(
+					'fragment',
+					'material.clearcoatRoughness = clearcoatRoughness;',
+					`${clearcoatRoughnessNode.code}\n\tmaterial.clearcoatRoughness = ${clearcoatRoughnessNode.result};`
+				);
 
-			this.addCodeAfterSnippet(
-				'fragment',
-				'material.clearcoatRoughness = clearcoatRoughness;',
-				`${clearcoatRoughnessNode.code}\n\tmaterial.clearcoatRoughness = ${clearcoatRoughnessNode.result};`
-			);
+			}
+
+			if ( clearcoatNormalNode !== undefined ) {
+
+				this.addCodeAfterSnippet(
+					'fragment',
+					'vec3 clearcoatNormal = geometryNormal;',
+					`${clearcoatNormalNode.code}\n\tclearcoatNormal = ${clearcoatNormalNode.result};`
+				);
+
+			}
 
 		}
 
-		if ( clearcoatNormalNode !== undefined ) {
+		if ( sheenNode !== undefined ) {
 
 			this.addCodeAfterSnippet(
 				'fragment',
-				'vec3 clearcoatNormal = geometryNormal;',
-				`${clearcoatNormalNode.code}\n\tclearcoatNormal = ${clearcoatNormalNode.result};`
+				'material.sheenColor = sheenColor;',
+				`${sheenNode.code}\n\tmaterial.sheenColor = ${sheenNode.result};`
 			);
 
+			if ( sheenRoughnessNode !== undefined ) {
+
+				this.replaceCode(
+					'fragment',
+					'material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );',
+					`${sheenRoughnessNode.code}\n\tmaterial.sheenRoughness = clamp( ${sheenRoughnessNode.result}, 0.07, 1.0 );`
+				);
+
+			}
+
 		}
 
 		if ( iridescenceNode !== undefined ) {

二进制
examples/screenshots/webgl_loader_gltf_sheen_nodes.jpg


+ 140 - 0
examples/webgl_loader_gltf_sheen_nodes.html

@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - GLTFloader + Sheen + Nodes</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+		<style>
+			body {
+				background: #bbbbbb;
+			}
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader + <a href="https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_sheen" target="_blank" rel="noopener">KHR_materials_sheen</a> + Nodes<br />
+			Sheen Chair from <a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/SheenChair" target="_blank" rel="noopener">glTF-Sample-Models</a>
+		</div>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three-nodes/": "./jsm/nodes/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import { NodeMaterial, color, uv, mix, mul, checker } from 'three-nodes/Nodes.js';
+
+			import { nodeFrame } from './jsm/renderers/webgl/nodes/WebGLNodes.js';
+
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+			import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
+			import { RoomEnvironment } from './jsm/environments/RoomEnvironment.js';
+
+			let camera, scene, renderer, controls;
+
+			init();
+			animate();
+
+			function init() {
+
+				const container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 20 );
+				camera.position.set( - 0.75, 0.7, 1.25 );
+
+				scene = new THREE.Scene();
+
+				// model
+
+				new GLTFLoader()
+					.setPath( 'models/gltf/' )
+					.load( 'SheenChair.glb', function ( gltf ) {
+
+						scene.add( gltf.scene );
+
+						const object = gltf.scene.getObjectByName( 'SheenChair_fabric' );
+
+						// Convert to NodeMaterial
+						const material = NodeMaterial.fromMaterial( object.material );
+
+						const checkerNode = checker( mul( uv(), 5 ) );
+
+						material.sheenNode = mix( color( 0x00ffff ), color( 0xffff00 ), checkerNode );
+						material.sheenRoughnessNode = checkerNode;
+
+						object.material = material;
+
+					} );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				renderer.toneMappingExposure = 1;
+				renderer.outputEncoding = THREE.sRGBEncoding;
+				container.appendChild( renderer.domElement );
+
+				const environment = new RoomEnvironment();
+				const pmremGenerator = new THREE.PMREMGenerator( renderer );
+
+				scene.background = new THREE.Color( 0xbbbbbb );
+				scene.environment = pmremGenerator.fromScene( environment ).texture;
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.enableDamping = true;
+				controls.minDistance = 1;
+				controls.maxDistance = 10;
+				controls.target.set( 0, 0.35, 0 );
+				controls.update();
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				nodeFrame.update();
+
+				controls.update(); // required if damping enabled
+
+				render();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>