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

Merge pull request #16971 from DanielSturk/sheen

MeshPhysicalMaterial: Added sheen
......@@ -185,6 +185,7 @@ var files = {
"webgl_materials_video",
"webgl_materials_video_webcam",
"webgl_materials_wireframe",
"webgl_materials_sheen",
"webgl_math_orientation_transform",
"webgl_mirror",
"webgl_modifier_simplifier",
......
......@@ -36,7 +36,8 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [
'ao',
'environment',
'mask',
'position'
'position',
'sheenColor'
] );
export { StandardNodeMaterial };
......@@ -169,16 +169,18 @@ StandardNode.prototype.build = function ( builder ) {
// 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' } );
this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } );
if ( builder.requires.irradiance ) {
this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
}
}
if ( this.sheenColor ) this.sheenColor.analyze( builder );
// build code
var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
......@@ -222,6 +224,8 @@ StandardNode.prototype.build = function ( builder ) {
var clearCoatEnv = useClearCoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearCoat', context: contextClearCoatEnvironment, slot: 'environment' } ) : undefined;
var sheenColor = this.sheenColor ? this.sheenColor.flow( builder, 'c' ) : undefined;
builder.requires.transparent = alpha !== undefined;
builder.addParsCode( [
......@@ -342,6 +346,12 @@ StandardNode.prototype.build = function ( builder ) {
}
if ( sheenColor ) {
output.push( 'material.sheenColor = ' + sheenColor.result + ';' );
}
if ( reflectivity ) {
output.push(
......@@ -515,6 +525,8 @@ StandardNode.prototype.copy = function ( source ) {
if ( source.environment ) this.environment = source.environment;
if ( source.sheenColor ) this.sheenColor = source.sheenColor;
return this;
};
......@@ -559,6 +571,8 @@ StandardNode.prototype.toJSON = function ( meta ) {
if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
if ( this.sheenColor ) data.sheenColor = this.sheenColor.toJSON( meta ).uuid;
}
return data;
......
<html lang="en">
<head>
<title>Sheen demo (material property)</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 {
color: #333;
}
</style>
</head>
<body>
<div id="info">Sheen demo by <a href="https://github.com/DanielSturk">DanielSturk</a></div>
<div id="container"></div>
<script src="js/libs/ammo.js"></script>
<script type="module">
import * as THREE from '../build/three.module.js';
import * as Nodes from './jsm/nodes/Nodes.js';
import Stats from './jsm/libs/stats.module.js';
import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { FBXLoader } from './jsm/loaders/FBXLoader.js';
// Graphics variables
var camera, controls, scene, renderer, stats;
var directionalLight;
var mesh, sphere, material, nodeMaterial;
var params = {
nodeMaterial: true,
color: new THREE.Color( 255, 0, 127 ),
sheenBRDF: true,
sheenColor: new THREE.Color( 10, 10, 10 ), // corresponds to .04 reflectance
roughness: .9,
exposure: 2,
};
// model
new FBXLoader().load( 'models/fbx/cloth.fbx', function ( loadedModel ) {
mesh = loadedModel.children[0];
init();
} );
function init( ) {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.2, 2000 );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xbfd1e5 );
mesh.scale.multiplyScalar( .5 );
scene.add( mesh );
//
material = new THREE.MeshPhysicalMaterial();
material.side = THREE.DoubleSide;
material.metalness = 0;
//
nodeMaterial = new Nodes.StandardNodeMaterial();
nodeMaterial.side = THREE.DoubleSide;
nodeMaterial.metalness = new Nodes.FloatNode( 0 );
nodeMaterial.roughness = new Nodes.FloatNode();
nodeMaterial.color = new Nodes.ColorNode( params.color.clone() );
//
sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry( 1, 100, 100 ),
material
);
scene.add(sphere);
camera.position.set( - 12, 7, 4 );
var container = document.getElementById( 'container' );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
container.appendChild( renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
controls.target.set( 0, 2, 0 );
controls.update();
directionalLight = new THREE.DirectionalLight( 0xffffff, .5 );
directionalLight.position.set( 0, 10, 0 );
directionalLight.castShadow = true;
directionalLight.add(
new THREE.Mesh(
new THREE.SphereBufferGeometry( .5 ),
new THREE.MeshBasicMaterial( { color: 0xffffff } )
)
);
scene.add( directionalLight );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize, false );
var gui = new GUI();
gui.add( params, 'nodeMaterial' );
gui.addColor( params, 'color' );
gui.add( params, 'sheenBRDF' );
gui.addColor( params, 'sheenColor' );
gui.add( params, 'roughness', 0, 1 );
gui.add( params, 'exposure', 0, 3 );
gui.open();
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
mesh.material = sphere.material = params.nodeMaterial
? nodeMaterial
: material;
//
material.sheenColor = params.sheenBRDF
? new THREE.Color().copy( params.sheenColor ).multiplyScalar( 1 / 255 )
: null;
material.color.copy( params.color ).multiplyScalar( 1 / 255 );
material.roughness = params.roughness;
material.needsUpdate = true;
//
nodeMaterial.sheenColor = params.sheenBRDF
? new Nodes.ColorNode( material.sheenColor )
: undefined;
nodeMaterial.color.value.copy( material.color );
nodeMaterial.roughness.value = params.roughness;
nodeMaterial.needsCompile = true;
//
renderer.toneMappingExposure = params.exposure;
renderer.render( scene, camera );
}
</script>
</body>
</html>
......@@ -4,17 +4,18 @@ import {
MeshStandardMaterialParameters,
MeshStandardMaterial,
} from './MeshStandardMaterial';
import { Color } from './../math/Color';
export interface MeshPhysicalMaterialParameters
extends MeshStandardMaterialParameters {
reflectivity?: number;
clearCoat?: number;
clearCoatRoughness?: number;
sheenColor?: Color;
clearCoatNormalScale?: Vector2;
clearCoatNormalMap?: Texture;
}
export class MeshPhysicalMaterial extends MeshStandardMaterial {
......@@ -26,6 +27,8 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial {
clearCoat: number;
clearCoatRoughness: number;
sheenColor: Color | null;
clearCoatNormalScale: Vector2;
clearCoatNormalMap: Texture | null;
......
import { Vector2 } from '../math/Vector2.js';
import { MeshStandardMaterial } from './MeshStandardMaterial.js';
import { Color } from '../math/Color.js';
/**
* @author WestLangley / http://github.com/WestLangley
......@@ -9,6 +10,8 @@ import { MeshStandardMaterial } from './MeshStandardMaterial.js';
* clearCoat: <float>
* clearCoatRoughness: <float>
*
* sheen: <Color>
*
* clearCoatNormalScale: <Vector2>,
* clearCoatNormalMap: new THREE.Texture( <Image> ),
* }
......@@ -27,6 +30,8 @@ function MeshPhysicalMaterial( parameters ) {
this.clearCoat = 0.0;
this.clearCoatRoughness = 0.0;
this.sheenColor = null; // null will disable sheen bsdf
this.clearCoatNormalScale = new Vector2( 1, 1 );
this.clearCoatNormalMap = null;
......@@ -50,6 +55,9 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
this.clearCoat = source.clearCoat;
this.clearCoatRoughness = source.clearCoatRoughness;
if ( source.sheenColor ) this.sheenColor = ( this.sheenColor || new Color() ).copy( source.sheenColor );
else this.sheenColor = null;
this.clearCoatNormalMap = source.clearCoatNormalMap;
this.clearCoatNormalScale.copy( source.clearCoatNormalScale );
......
......@@ -2271,6 +2271,7 @@ function WebGLRenderer( parameters ) {
uniforms.clearCoat.value = material.clearCoat;
uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
if ( material.sheenColor ) uniforms.sheenColor.value.copy( material.sheenColor );
if ( material.clearCoatNormalMap ) {
......
......@@ -336,4 +336,35 @@ float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {
float BlinnExponentToGGXRoughness( const in float blinnExponent ) {
return sqrt( 2.0 / ( blinnExponent + 2.0 ) );
}
#if defined( USE_SHEEN )
// https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L94
float D_Charlie(float roughness, float NoH) {
// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"
float invAlpha = 1.0 / roughness;
float cos2h = NoH * NoH;
float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);
}
// https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L136
float V_Neubelt(float NoV, float NoL) {
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
return saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));
}
vec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {
vec3 N = geometry.normal;
vec3 V = geometry.viewDir;
vec3 H = normalize( V + L );
float dotNH = saturate( dot( N, H ) );
return specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );
}
#endif
`;
......@@ -9,4 +9,7 @@ material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );
material.clearCoat = saturate( clearCoat ); // Burley clearcoat model
material.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );
#endif
#ifdef USE_SHEEN
material.sheenColor = sheenColor;
#endif
`;
......@@ -10,6 +10,10 @@ struct PhysicalMaterial {
float clearCoatRoughness;
#endif
#ifdef USE_SHEEN
vec3 sheenColor;
#endif
};
#define MAXIMUM_SPECULAR_COEFFICIENT 0.16
......@@ -98,10 +102,18 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
#endif
reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness );
#ifdef USE_SHEEN
reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_Sheen(
material.specularRoughness,
directLight.direction,
geometry,
material.sheenColor
);
#else
reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);
#endif
reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
}
void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {
......
......@@ -275,6 +275,7 @@ ShaderLib.physical = {
{
clearCoat: { value: 0 },
clearCoatRoughness: { value: 0 },
sheenColor: { value: new Color( 0x000000 ) },
clearCoatNormalScale: { value: new Vector2( 1, 1 ) },
clearCoatNormalMap: { value: null },
}
......
......@@ -12,6 +12,10 @@ uniform float opacity;
uniform float clearCoatRoughness;
#endif
#ifdef USE_SHEEN
uniform vec3 sheenColor;
#endif
varying vec3 vViewPosition;
#ifndef FLAT_SHADED
......
......@@ -515,6 +515,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters,
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
parameters.sheen ? '#define USE_SHEEN' : '',
parameters.vertexTangents ? '#define USE_TANGENT' : '',
parameters.vertexColors ? '#define USE_COLOR' : '',
parameters.vertexUvs ? '#define USE_UV' : '',
......
......@@ -37,7 +37,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering",
"sheen"
];
......@@ -162,6 +163,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
gradientMap: !! material.gradientMap,
sheen: !! material.sheenColor,
combine: material.combine,
vertexTangents: ( material.normalMap && material.vertexTangents ),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册