wall noise and arbitrary render resolution option
[raydungeon] / sdr / raydungeon.p.glsl
1 uniform float aspect;
2 uniform mat4 matrix;
3 uniform mat3 dirmatrix;
4
5 #define DIST_THRES      1e-3
6 #define MAX_ITER        128
7 #define MAX_STEP        0.5
8
9 vec3 raymarch(inout vec3 p, in vec3 dir, out float depth);
10 vec3 shade(in vec3 p, in vec3 dir, in float dist, in float total_dist);
11 vec3 backdrop(in vec3 dir);
12 float eval_sdf(in vec3 p);
13 vec3 eval_grad(in vec3 p, float dist);
14 vec3 primray(in vec2 uv, out vec3 org);
15
16 float boxdist(in vec3 p, in vec3 b);
17 float sphdist(in vec3 p, in vec3 sp, in float srad);
18
19 float fbm(vec3 v, int noct);
20 float snoise(vec3 v);
21
22 float eval_sdf_gen(in vec3 p);
23
24
25 void main()
26 {
27         vec2 uv = gl_TexCoord[0].st;
28         vec3 rorg;
29         vec3 rdir = primray(uv, rorg);
30         float depth;
31
32         gl_FragColor.rgb = raymarch(rorg, rdir, depth);
33         gl_FragColor.a = 1.0;
34
35         vec4 projp = gl_ProjectionMatrix * vec4(0.0, 0.0, -depth, 1.0);
36         float zval = projp.z / projp.w;
37
38         gl_FragDepth = zval;
39 }
40
41 vec3 raymarch(inout vec3 p, in vec3 dir, out float depth)
42 {
43         float d, total_d = 0.0;
44
45         for(int i=0; i<MAX_ITER; i++) {
46                 if((d = eval_sdf(p)) <= DIST_THRES) {
47                         depth = total_d;
48                         return shade(p, dir, d, total_d);
49                 }
50
51                 d = min(d, MAX_STEP);
52
53                 p = p + dir * d;
54                 total_d += d;
55         }
56
57         depth = -gl_DepthRange.far;
58         return backdrop(dir);
59 }
60
61 vec3 shade(in vec3 p, in vec3 dir, in float dist, in float total_dist)
62 {
63     const vec3 kd = vec3(1.0, 0.3, 0.1);
64     const vec3 ks = vec3(0.7, 0.7, 0.7);
65     const vec3 ldir = normalize(vec3(-1.0, 1.0, -1.5));
66     const vec3 vdir = vec3(0.0, 0.0, -1.0);
67
68     vec3 diffuse = vec3(0.0, 0.0, 0.0);
69     vec3 specular = vec3(0.0, 0.0, 0.0);
70     
71     vec3 n = eval_grad(p, dist);
72         return n * 0.5 + 0.5;
73     vec3 hdir = normalize(ldir + vdir);
74
75     float ndotl = max(dot(n, ldir), 0.0);
76     float ndoth = max(dot(n, hdir), 0.0);
77     
78     diffuse += kd * ndotl;
79     specular += ks * pow(ndoth, 50.0);
80     
81     float fog = clamp(300.0 / (total_dist * total_dist), 0.0, 1.0);
82
83     return mix(backdrop(dir), diffuse + specular, fog);
84 }
85
86 vec3 backdrop(in vec3 dir)
87 {
88         return vec3(0.1, 0.1, 0.1);
89 }
90
91 float eval_sdf(in vec3 p)
92 {
93         return eval_sdf_gen(p) + fbm(p, 4) * 0.05;
94 }
95
96 #define DELTA   1e-4
97 vec3 eval_grad(in vec3 p, float dist)
98 {
99         float dfdx = eval_sdf(p + vec3(DELTA, 0.0, 0.0)) - dist;
100         float dfdy = eval_sdf(p + vec3(0.0, DELTA, 0.0)) - dist;
101         float dfdz = eval_sdf(p + vec3(0.0, 0.0, DELTA)) - dist;
102         return normalize(vec3(dfdx, dfdy, dfdz));
103 }
104
105 vec3 primray(in vec2 uv, out vec3 org)
106 {
107         vec3 origin = (gl_ModelViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
108         org = origin;
109
110         vec2 nuv = uv * 2.0 - 1.0;
111         vec4 cp_near = vec4(nuv, -1.0, 1.0);
112
113         vec4 vdir = gl_ProjectionMatrixInverse * cp_near;
114         vec4 wdir = gl_ModelViewMatrixInverse * vec4(vdir.xyz, 0.0);
115
116         return normalize(wdir.xyz);
117 }
118
119 float boxdist(in vec3 p, in vec3 b)
120 {
121         vec3 q = abs(p) - b;
122         return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
123 }
124
125 float sphdist(in vec3 p, in vec3 sp, in float srad)
126 {
127         return length(p - sp) - srad;
128 }
129
130 #ifdef TEST_SDF
131 float eval_sdf_gen(in vec3 p)
132 {
133         return boxdist(p - vec3(14.000000, 0.0, 14.000000), vec3(0.550000, 1.0, 4.550000));
134 }
135 #endif
136
137 float fbm(vec3 v, int noct)
138 {
139         float val = 0.0;
140         float f = 1.0;
141         for(int i=0; i<noct; i++) {
142                 val += snoise(v * f) / f;
143                 f *= 2.0;
144         }
145         return val;
146 }
147
148 // Description : Array and textureless GLSL 2D/3D/4D simplex 
149 //               noise functions.
150 //      Author : Ian McEwan, Ashima Arts.
151 //  Maintainer : stegu
152 //     Lastmod : 20201014 (stegu)
153 //     License : Copyright (C) 2011 Ashima Arts. All rights reserved.
154 //               Distributed under the MIT License. See LICENSE file.
155 //               https://github.com/ashima/webgl-noise
156 //               https://github.com/stegu/webgl-noise
157 // 
158
159 vec3 mod289(vec3 x) {
160         return x - floor(x * (1.0 / 289.0)) * 289.0;
161 }
162
163 vec4 mod289(vec4 x) {
164         return x - floor(x * (1.0 / 289.0)) * 289.0;
165 }
166
167 vec4 permute(vec4 x) {
168         return mod289(((x*34.0)+10.0)*x);
169 }
170
171 vec4 taylorInvSqrt(vec4 r)
172 {
173         return 1.79284291400159 - 0.85373472095314 * r;
174 }
175
176 float snoise(vec3 v)
177
178         const vec2  C = vec2(1.0/6.0, 1.0/3.0) ;
179         const vec4  D = vec4(0.0, 0.5, 1.0, 2.0);
180
181         // First corner
182         vec3 i  = floor(v + dot(v, C.yyy) );
183         vec3 x0 =   v - i + dot(i, C.xxx) ;
184
185         // Other corners
186         vec3 g = step(x0.yzx, x0.xyz);
187         vec3 l = 1.0 - g;
188         vec3 i1 = min( g.xyz, l.zxy );
189         vec3 i2 = max( g.xyz, l.zxy );
190
191         //   x0 = x0 - 0.0 + 0.0 * C.xxx;
192         //   x1 = x0 - i1  + 1.0 * C.xxx;
193         //   x2 = x0 - i2  + 2.0 * C.xxx;
194         //   x3 = x0 - 1.0 + 3.0 * C.xxx;
195         vec3 x1 = x0 - i1 + C.xxx;
196         vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
197         vec3 x3 = x0 - D.yyy;      // -1.0+3.0*C.x = -0.5 = -D.y
198
199         // Permutations
200         i = mod289(i); 
201         vec4 p = permute( permute( permute( 
202                                         i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
203                                 + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) 
204                         + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
205
206         // Gradients: 7x7 points over a square, mapped onto an octahedron.
207         // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
208         float n_ = 0.142857142857; // 1.0/7.0
209         vec3  ns = n_ * D.wyz - D.xzx;
210
211         vec4 j = p - 49.0 * floor(p * ns.z * ns.z);  //  mod(p,7*7)
212
213         vec4 x_ = floor(j * ns.z);
214         vec4 y_ = floor(j - 7.0 * x_ );    // mod(j,N)
215
216         vec4 x = x_ *ns.x + ns.yyyy;
217         vec4 y = y_ *ns.x + ns.yyyy;
218         vec4 h = 1.0 - abs(x) - abs(y);
219
220         vec4 b0 = vec4( x.xy, y.xy );
221         vec4 b1 = vec4( x.zw, y.zw );
222
223         //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
224         //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
225         vec4 s0 = floor(b0)*2.0 + 1.0;
226         vec4 s1 = floor(b1)*2.0 + 1.0;
227         vec4 sh = -step(h, vec4(0.0));
228
229         vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
230         vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
231
232         vec3 p0 = vec3(a0.xy,h.x);
233         vec3 p1 = vec3(a0.zw,h.y);
234         vec3 p2 = vec3(a1.xy,h.z);
235         vec3 p3 = vec3(a1.zw,h.w);
236
237         //Normalise gradients
238         vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
239         p0 *= norm.x;
240         p1 *= norm.y;
241         p2 *= norm.z;
242         p3 *= norm.w;
243
244         // Mix final noise value
245         vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
246         m = m * m;
247         return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), 
248                                 dot(p2,x2), dot(p3,x3) ) );
249 }