/** * ------------------------------------------------------------------------------------------ * Subsurface Scattering shader * Based on three/examples/jsm/shaders/SubsurfaceScatteringShader.js * 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/ *------------------------------------------------------------------------------------------ */ import { Color, ShaderChunk, ShaderLib, UniformsUtils, } from 'three'; function replaceAll(string, find, replace) { return string.split(find).join(replace); } const meshphongFragHead = ShaderChunk.meshphong_frag.slice(0, ShaderChunk.meshphong_frag.indexOf('void main() {')); const meshphongFragBody = ShaderChunk.meshphong_frag.slice(ShaderChunk.meshphong_frag.indexOf('void main() {')); const SubsurfaceScatteringShader = { uniforms: UniformsUtils.merge([ ShaderLib.phong.uniforms, { thicknessColor: { value: new Color(0x668597) }, 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} `, fragmentShader: ` #define USE_UV #define SUBSURFACE ${meshphongFragHead} 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 GeometricContext geometry, inout ReflectedLight reflectedLight) { #ifdef USE_COLOR vec3 thickness = vColor * thicknessColor; #else vec3 thickness = thicknessColor; #endif vec3 scatteringHalf = normalize(directLight.direction + (geometry.normal * thicknessDistortion)); float scatteringDot = pow(saturate(dot(geometry.viewDir, -scatteringHalf)), thicknessPower) * thicknessScale; vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness; reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color; } ` + meshphongFragBody.replace( '#include ', replaceAll( ShaderChunk.lights_fragment_begin, 'RE_Direct( directLight, geometry, material, reflectedLight );', ` RE_Direct( directLight, geometry, material, reflectedLight ); #if defined( SUBSURFACE ) && defined( USE_UV ) RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight); #endif ` ) ), }; export default SubsurfaceScatteringShader;