SubsurfaceScatteringShader.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import {
  2. Color,
  3. ShaderChunk,
  4. ShaderLib,
  5. UniformsUtils
  6. } from 'three';
  7. /**
  8. * ------------------------------------------------------------------------------------------
  9. * Subsurface Scattering shader
  10. * Based on GDC 2011 – Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look
  11. * https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/
  12. *------------------------------------------------------------------------------------------
  13. */
  14. function replaceAll( string, find, replace ) {
  15. return string.split( find ).join( replace );
  16. }
  17. const meshphong_frag_head = ShaderChunk[ 'meshphong_frag' ].slice( 0, ShaderChunk[ 'meshphong_frag' ].indexOf( 'void main() {' ) );
  18. const meshphong_frag_body = ShaderChunk[ 'meshphong_frag' ].slice( ShaderChunk[ 'meshphong_frag' ].indexOf( 'void main() {' ) );
  19. const SubsurfaceScatteringShader = {
  20. name: 'SubsurfaceScatteringShader',
  21. uniforms: UniformsUtils.merge( [
  22. ShaderLib[ 'phong' ].uniforms,
  23. {
  24. 'thicknessMap': { value: null },
  25. 'thicknessColor': { value: new Color( 0xffffff ) },
  26. 'thicknessDistortion': { value: 0.1 },
  27. 'thicknessAmbient': { value: 0.0 },
  28. 'thicknessAttenuation': { value: 0.1 },
  29. 'thicknessPower': { value: 2.0 },
  30. 'thicknessScale': { value: 10.0 }
  31. }
  32. ] ),
  33. vertexShader: [
  34. '#define USE_UV',
  35. ShaderChunk[ 'meshphong_vert' ],
  36. ].join( '\n' ),
  37. fragmentShader: [
  38. '#define USE_UV',
  39. '#define SUBSURFACE',
  40. meshphong_frag_head,
  41. 'uniform sampler2D thicknessMap;',
  42. 'uniform float thicknessPower;',
  43. 'uniform float thicknessScale;',
  44. 'uniform float thicknessDistortion;',
  45. 'uniform float thicknessAmbient;',
  46. 'uniform float thicknessAttenuation;',
  47. 'uniform vec3 thicknessColor;',
  48. '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) {',
  49. ' vec3 thickness = thicknessColor * texture2D(thicknessMap, uv).r;',
  50. ' vec3 scatteringHalf = normalize(directLight.direction + (geometryNormal * thicknessDistortion));',
  51. ' float scatteringDot = pow(saturate(dot(geometryViewDir, -scatteringHalf)), thicknessPower) * thicknessScale;',
  52. ' vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness;',
  53. ' reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color;',
  54. '}',
  55. meshphong_frag_body.replace( '#include <lights_fragment_begin>',
  56. replaceAll(
  57. ShaderChunk[ 'lights_fragment_begin' ],
  58. 'RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );',
  59. [
  60. 'RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );',
  61. '#if defined( SUBSURFACE ) && defined( USE_UV )',
  62. ' RE_Direct_Scattering(directLight, vUv, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, reflectedLight);',
  63. '#endif',
  64. ].join( '\n' )
  65. ),
  66. ),
  67. ].join( '\n' ),
  68. };
  69. export { SubsurfaceScatteringShader };