v2 / examples / sokol / 08_sdf / sdf.glsl
184 lines · 155 sloc · 4.92 KB · 22744ce49534014d3a754916deab11afb803fb66
Raw
1//------------------------------------------------------------------------------
2// Signed-distance-field raymarching shaders, see:
3// https://iquilezles.org/articles/mandelbulb
4// https://www.shadertoy.com/view/ltfSWn
5//------------------------------------------------------------------------------
6
7//--- vertex shader
8@vs vs
9uniform vs_params {
10 float aspect;
11 float time;
12};
13in vec4 position;
14
15out vec2 pos;
16out vec3 eye;
17out vec3 up;
18out vec3 right;
19out vec3 fwd;
20
21// compute eye position (orbit around center)
22vec3 eye_pos(float time, vec3 center) {
23 return center + vec3(sin(time * 0.05) * 3.0, sin(time * 0.1) * 2.0, cos(time * 0.05) * 3.0);
24}
25
26// a lookat function
27void lookat(vec3 eye, vec3 center, vec3 up, out vec3 out_fwd, out vec3 out_right, out vec3 out_up) {
28 out_fwd = normalize(center - eye);
29 out_right = normalize(cross(out_fwd, up));
30 out_up = cross(out_right, out_fwd);
31}
32
33void main() {
34 gl_Position = position;
35 pos.x = position.x * aspect;
36 pos.y = position.y;
37 const vec3 center = vec3(0.0, 0.0, 0.0);
38 const vec3 up_vec = vec3(0.0, 1.0, 0.0);
39 eye = eye_pos(time * 5, center);
40 lookat(eye, center, up_vec, fwd, right, up);
41}
42@end
43
44//--- fragment shader
45@fs fs
46in vec2 pos;
47in vec3 eye;
48in vec3 up;
49in vec3 right;
50in vec3 fwd;
51
52out vec4 frag_color;
53
54float sd_sphere(vec3 p, float s) {
55 return length(p) - s;
56}
57
58float sd_mandelbulb(vec3 p, out vec4 res_color) {
59 vec3 w = p;
60 float m = dot(w,w);
61
62 vec4 trap = vec4(abs(w),m);
63 float dz = 1.0;
64
65 for( int i=0; i<4; i++ ) {
66 float m2 = m*m;
67 float m4 = m2*m2;
68 dz = 8.0*sqrt(m4*m2*m)*dz + 1.0;
69
70 float x = w.x; float x2 = x*x; float x4 = x2*x2;
71 float y = w.y; float y2 = y*y; float y4 = y2*y2;
72 float z = w.z; float z2 = z*z; float z4 = z2*z2;
73
74 float k3 = x2 + z2;
75 float k2 = inversesqrt( k3*k3*k3*k3*k3*k3*k3 );
76 float k1 = x4 + y4 + z4 - 6.0*y2*z2 - 6.0*x2*y2 + 2.0*z2*x2;
77 float k4 = x2 - y2 + z2;
78
79 w.x = p.x + 64.0*x*y*z*(x2-z2)*k4*(x4-6.0*x2*z2+z4)*k1*k2;
80 w.y = p.y + -16.0*y2*k3*k4*k4 + k1*k1;
81 w.z = p.z + -8.0*y*k4*(x4*x4 - 28.0*x4*x2*z2 + 70.0*x4*z4 - 28.0*x2*z2*z4 + z4*z4)*k1*k2;
82
83 trap = min( trap, vec4(abs(w),m) );
84
85 m = dot(w,w);
86 if( m > 256.0 ) {
87 break;
88 }
89 }
90 res_color = vec4(m,trap.yzw);
91 return 0.25*log(m)*sqrt(m)/dz;
92}
93
94float d_scene(vec3 p, out vec4 res_color) {
95 float d = sd_sphere(p, 1.1);
96 if (d < 0.1) {
97 d = sd_mandelbulb(p, res_color);
98 }
99 else {
100 res_color = vec4(0.0);
101 }
102 return d;
103}
104
105// surface normal estimation
106vec3 surface_normal(vec3 p, float dp) {
107 const float eps = 0.001;
108 const vec2 d = vec2(eps, 0);
109 vec4 tra;
110 float x = d_scene(p + d.xyy, tra) - dp;
111 float y = d_scene(p + d.yxy, tra) - dp;
112 float z = d_scene(p + d.yyx, tra) - dp;
113 return normalize(vec3(x, y, z));
114}
115
116vec3 calc_color(vec3 ro, vec3 rd, float t, vec4 tra) {
117 const vec3 light1 = vec3( 0.577, 0.577, -0.577);
118 const vec3 light2 = vec3(-0.707, 0.000, 0.707);
119
120 vec3 pos = ro + rd * t;
121 vec3 nrm = surface_normal(pos, t);
122 vec3 hal = normalize(light1 - rd);
123 float occ = clamp(0.05 * log(tra.x), 0.0, 1.0);
124 float fac = clamp(1.0 + dot(rd, nrm), 0.0, 1.0);
125
126 // sun
127 float dif1 = clamp(dot( light1, nrm), 0.0, 1.0);
128 float spe1 = pow(clamp(dot(nrm, hal), 0.0, 1.0), 32.0 )*dif1*(0.04+0.96*pow(clamp(1.0-dot(hal,light1),0.0,1.0),5.0));
129 // bounce
130 float dif2 = clamp( 0.5 + 0.5*dot( light2, nrm ), 0.0, 1.0 )*occ;
131 // sky
132 float dif3 = (0.7+0.3*nrm.y)*(0.2+0.8*occ);
133
134 vec3 col = vec3(0.01);
135 col = mix(col, vec3(0.10,0.20,0.30), clamp(tra.y,0.0,1.0) );
136 col = mix(col, vec3(0.02,0.10,0.30), clamp(tra.z*tra.z,0.0,1.0) );
137 col = mix(col, vec3(0.30,0.10,0.02), clamp(pow(tra.w,6.0),0.0,1.0) );
138
139 vec3 lin = vec3(0.0);
140 lin += 7.0*vec3(1.50,1.10,0.70)*dif1;
141 lin += 4.0*vec3(0.25,0.20,0.15)*dif2;
142 lin += 1.5*vec3(0.10,0.20,0.30)*dif3;
143 lin += 2.5*vec3(0.35,0.30,0.25)*(0.05+0.95*occ); // ambient
144 lin += 4.0*fac*occ; // fake SSS
145 col *= lin;
146 col = pow( col, vec3(0.7,0.9,1.0)); // fake SSS
147 col += spe1*15.0;
148
149 // gamma
150 col = sqrt(col);
151
152 return col;
153}
154
155void main() {
156 const float epsilon = 0.001;
157 const float focal_length = 1.8;
158
159 vec3 ray_origin = eye + fwd * focal_length + right * pos.x + up * pos.y;
160 vec3 ray_direction = normalize(ray_origin - eye);
161
162 vec4 tra;
163 vec4 color = vec4(0.10,0.20,0.30,1.0);
164 float t = 0.0;
165 for (int i = 0; i < 96; i++) {
166 vec3 p = ray_origin + ray_direction * t;
167 float d = d_scene(p, tra);
168 if (d < epsilon) {
169 color.xyz = calc_color(p, ray_direction, d, tra);
170 break;
171 }
172 else {
173 color.xyz += vec3(0.003, 0.001, 0.0) * i;
174 }
175 if (t > 3) {
176 break;
177 }
178 t += d;
179 }
180 frag_color = color;
181}
182@end
183
184@program sdf vs fs
185