import { Color, ShaderChunk, ShaderLib, UniformsUtils } from 'three'; /** * ------------------------------------------------------------------------------------------ * Subsurface Scattering shader * Based on GDC 2011 – Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look * https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/ *------------------------------------------------------------------------------------------ */ function replaceAll( string, find, replace ) { return string.split( find ).join( replace ); } const meshphong_frag_head = ShaderChunk[ 'meshphong_frag' ].slice( 0, ShaderChunk[ 'meshphong_frag' ].indexOf( 'void main() {' ) ); const meshphong_frag_body = ShaderChunk[ 'meshphong_frag' ].slice( ShaderChunk[ 'meshphong_frag' ].indexOf( 'void main() {' ) ); const SubsurfaceScatteringShader = { name: 'SubsurfaceScatteringShader', uniforms: UniformsUtils.merge( [ ShaderLib[ 'phong' ].uniforms, { 'thicknessMap': { value: null }, 'thicknessColor': { value: new Color( 0xffffff ) }, 'thicknessDistortion': { value: 0.1 }, 'thicknessAmbient': { value: 0.0 }, 'thicknessAttenuation': { value: 0.1 }, 'thicknessPower': { value: 2.0 }, 'thicknessScale': { value: 10.0 } } ] ), vertexShader: [ '#define USE_UV', ShaderChunk[ 'meshphong_vert' ], ].join( '\n' ), fragmentShader: [ '#define USE_UV', '#define SUBSURFACE', meshphong_frag_head, 'uniform sampler2D thicknessMap;', 'uniform float thicknessPower;', 'uniform float thicknessScale;', 'uniform float thicknessDistortion;', 'uniform float thicknessAmbient;', 'uniform float thicknessAttenuation;', 'uniform vec3 thicknessColor;', 'void RE_Direct_Scattering(const in IncidentLight directLight, const in vec2 uv, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, inout ReflectedLight reflectedLight) {', ' vec3 thickness = thicknessColor * texture2D(thicknessMap, uv).r;', ' vec3 scatteringHalf = normalize(directLight.direction + (geometryNormal * thicknessDistortion));', ' float scatteringDot = pow(saturate(dot(geometryViewDir, -scatteringHalf)), thicknessPower) * thicknessScale;', ' vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness;', ' reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color;', '}', meshphong_frag_body.replace( '#include ', replaceAll( ShaderChunk[ 'lights_fragment_begin' ], 'RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );', [ 'RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );', '#if defined( SUBSURFACE ) && defined( USE_UV )', ' RE_Direct_Scattering(directLight, vUv, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, reflectedLight);', '#endif', ].join( '\n' ) ), ), ].join( '\n' ), }; export { SubsurfaceScatteringShader };