1
+ //reference: https://www.shadertoy.com/view/ldcGWH
2
+ //In Unity3D editor, add 3D Object/Quad to Main Camera, then bind material with shader to the quad. Set quad position at (x=0 ; y=0; z=0.4;). Play.
3
+
4
+ Shader "Subsurface Scattering"
5
+ {
6
+ Properties
7
+ {
8
+ density ("Density" ,Range (0.0 ,2.0 )) = 0.4
9
+ ss_power( "Power" ,Range (0.0 ,10.0 )) = 3.0
10
+ ss_scattering( "Scattering" ,Range (0.0 ,2.0 )) = 0.4
11
+ ss_offset( "Offset" ,Range (0.0 ,2.0 )) = 0.5
12
+ ss_intensity( "Intensity" ,Range (0.0 ,5.0 )) = 1.0
13
+ ss_mix( "Mix" ,Range (0.0 ,2.0 )) = 1.0
14
+ ss_color( "SSS Color" ,Color ) = (0.85 , 0.05 , 0.2 , 0.0 )
15
+ surfaceThickness( "Thickness" ,Range (0.0 ,0.02 )) = 0.008
16
+ rimCol( "Rim Color" ,Color ) = (1.0 , 1.0 , 1.0 , 1.0 )
17
+ rimPow( "Rim Power" ,Range (0.0 ,5.0 )) = 2.5
18
+ rimAmount( "Rim Amount" ,Range (0.0 ,2.0 )) = 1.0
19
+ F( "Fresnel" ,Range (0.0 ,5.0 )) = 2.2
20
+ LP( "Light Position" ,Vector ) = (14.0 , 10.0 , 29.0 , 1.0 )
21
+ }
22
+ Subshader
23
+ {
24
+ Pass
25
+ {
26
+ CGPROGRAM
27
+ #pragma vertex vertex_shader
28
+ #pragma fragment pixel_shader
29
+ #pragma target 3.0
30
+
31
+ struct custom_type
32
+ {
33
+ float4 screen_vertex : SV_POSITION ;
34
+ float3 world_vertex : TEXCOORD1 ;
35
+ };
36
+
37
+ float density ;
38
+ float ss_power ;
39
+ float ss_scattering;
40
+ float ss_offset;
41
+ float ss_intensity;
42
+ float ss_mix;
43
+ float4 ss_color;
44
+ float surfaceThickness ;
45
+ float4 rimCol;
46
+ float rimPow;
47
+ float rimAmount;
48
+ float F;
49
+ float4 LP;
50
+
51
+ float hash (float2 co)
52
+ {
53
+ return frac (sin (dot (co.xy ,float2 (12.9898 ,78.233 ))) * 43758.5453 );
54
+ }
55
+
56
+ float map (float3 p)
57
+ {
58
+ return length (p)-1.0 ;
59
+ }
60
+
61
+ float3 set_normal (float3 p)
62
+ {
63
+ float3 x = float3 (0.001 ,0.00 ,0.00 );
64
+ float3 y = float3 (0.00 ,0.001 ,0.00 );
65
+ float3 z = float3 (0.00 ,0.00 ,0.001 );
66
+ return normalize (float3 (map (p+x)-map (p-x), map (p+y)-map (p-y), map (p+z)-map (p-z)));
67
+ }
68
+
69
+ float subsurface_scattering (float3 ro, float3 rd, float3 light, float3 n)
70
+ {
71
+ float len = 0.0 ;
72
+ const float samples = 12.0 ;
73
+ const float sqs = sqrt (samples);
74
+ for (float s = -samples / 2.0 ; s < samples / 2.0 ; s+= 1.0 )
75
+ {
76
+ float3 p = ro + (-n * surfaceThickness);
77
+ float3 ld = light;
78
+ ld.x += fmod (abs (s), sqs) * ss_scattering * sign (s);
79
+ ld.y += (s / sqs) * ss_scattering;
80
+ ld.x += hash (p.xy * s) * ss_scattering;
81
+ ld.y += hash (p.yx * s) * ss_scattering;
82
+ ld.z += hash (p.zx * s) * ss_scattering;
83
+ ld = normalize (ld);
84
+ float3 dir = ld;
85
+ for (int i = 0 ; i < 50 ; ++i)
86
+ {
87
+ float d = map (p);
88
+ if (d < 0.0 ) d = min (d, -0.0001 );
89
+ if (d >= 0.0 ) break ;
90
+ dir = normalize (ld);
91
+ p += abs (d * 0.5 ) * dir;
92
+ }
93
+ len += length (ro - p);
94
+ }
95
+ return len / samples;
96
+ }
97
+
98
+ float4 lighting (float3 ro, float3 rd)
99
+ {
100
+ float4 AmbientLight = float4 (0.0 ,0.0 ,0.0 ,0.0 );
101
+ float3 LightDirection = normalize ( LP.xyz );
102
+ float3 NormalDirection = set_normal (ro);
103
+ float Diffuse = saturate (dot (NormalDirection, LightDirection));
104
+ float3 Reflection = reflect (-LightDirection, NormalDirection);
105
+ float Rim = pow (saturate (1.0 - dot (Reflection, -rd)),rimPow);
106
+ float fresnel = Rim + F * (1.0 - Rim);
107
+ float4 color = AmbientLight + fresnel * rimCol * rimAmount * Diffuse;
108
+ float s = subsurface_scattering (ro, rd, LightDirection, NormalDirection);
109
+ s = pow (exp (ss_offset -s * density),ss_power);
110
+ float4 sscol = s * ss_color * ss_intensity;
111
+ sscol = lerp (sscol, ss_color, 1.0 - ss_mix);
112
+ return color+sscol;
113
+ }
114
+
115
+ float4 raymarch (float3 ro, float3 rd)
116
+ {
117
+ for (int i=0 ; i<128 ; i++)
118
+ {
119
+ float t = map (ro);
120
+ if (t < 0.001 ) return lighting (ro,rd);
121
+ ro+=t*rd;
122
+ }
123
+ return 0 ;
124
+ }
125
+
126
+ custom_type vertex_shader (float4 vertex : POSITION )
127
+ {
128
+ custom_type vs;
129
+ vs.screen_vertex = mul (UNITY_MATRIX_MVP , vertex);
130
+ vs.world_vertex = mul (_Object2World , vertex);
131
+ return vs;
132
+ }
133
+
134
+ float4 pixel_shader (custom_type ps ) : SV_TARGET
135
+ {
136
+ float3 worldPosition = ps.world_vertex;
137
+ float3 viewDirection = normalize (ps.world_vertex - _WorldSpaceCameraPos .xyz);
138
+ return raymarch (worldPosition,viewDirection);
139
+ }
140
+
141
+ ENDCG
142
+
143
+ }
144
+ }
145
+ }
0 commit comments