SubsurfaceScatteringShader.js 3.2 KB

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