2020-09-17 23:09:45 +08:00
|
|
|
|
/**
|
|
|
|
|
* ------------------------------------------------------------------------------------------
|
|
|
|
|
* 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/
|
|
|
|
|
*------------------------------------------------------------------------------------------
|
|
|
|
|
*/
|
2020-09-17 16:16:02 +08:00
|
|
|
|
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) {
|
2020-09-17 23:09:45 +08:00
|
|
|
|
#ifdef USE_COLOR
|
|
|
|
|
vec3 thickness = vColor * thicknessColor;
|
|
|
|
|
#else
|
|
|
|
|
vec3 thickness = thicknessColor;
|
|
|
|
|
#endif
|
2020-09-17 16:16:02 +08:00
|
|
|
|
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 <lights_fragment_begin>',
|
|
|
|
|
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;
|