distance function generation from level data, first pass
[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        250
7 #define MAX_STEP        1.0
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 void main()
20 {
21         vec2 uv = gl_TexCoord[0].st;
22         vec3 rorg;
23         vec3 rdir = primray(uv, rorg);
24         float depth;
25
26         gl_FragColor.rgb = raymarch(rorg, rdir, depth);
27         gl_FragColor.a = 1.0;
28
29         vec4 projp = gl_ProjectionMatrix * vec4(0.0, 0.0, -depth, 1.0);
30         float zval = projp.z / projp.w;
31
32         gl_FragDepth = zval;
33 }
34
35 vec3 raymarch(inout vec3 p, in vec3 dir, out float depth)
36 {
37         float d, total_d = 0.0;
38
39         for(int i=0; i<MAX_ITER; i++) {
40                 if((d = eval_sdf(p)) <= DIST_THRES) {
41                         depth = total_d;
42                         return shade(p, dir, d, total_d);
43                 }
44
45                 d = min(d, MAX_STEP);
46
47                 p = p + dir * d;
48                 total_d += d;
49         }
50
51         depth = -gl_DepthRange.far;
52         return backdrop(dir);
53 }
54
55 vec3 shade(in vec3 p, in vec3 dir, in float dist, in float total_dist)
56 {
57     const vec3 kd = vec3(1.0, 0.3, 0.1);
58     const vec3 ks = vec3(0.7, 0.7, 0.7);
59     const vec3 ldir = normalize(vec3(-1.0, 1.0, -1.5));
60     const vec3 vdir = vec3(0.0, 0.0, -1.0);
61
62     vec3 diffuse = vec3(0.0, 0.0, 0.0);
63     vec3 specular = vec3(0.0, 0.0, 0.0);
64     
65     vec3 n = eval_grad(p, dist);
66         return n * 0.5 + 0.5;
67     vec3 hdir = normalize(ldir + vdir);
68
69     float ndotl = max(dot(n, ldir), 0.0);
70     float ndoth = max(dot(n, hdir), 0.0);
71     
72     diffuse += kd * ndotl;
73     specular += ks * pow(ndoth, 50.0);
74     
75     float fog = clamp(300.0 / (total_dist * total_dist), 0.0, 1.0);
76
77     return mix(backdrop(dir), diffuse + specular, fog);
78 }
79
80 vec3 backdrop(in vec3 dir)
81 {
82         return vec3(0.1, 0.1, 0.1);
83 }
84
85 #define DELTA   1e-4
86 vec3 eval_grad(in vec3 p, float dist)
87 {
88         float dfdx = eval_sdf(p + vec3(DELTA, 0.0, 0.0)) - dist;
89         float dfdy = eval_sdf(p + vec3(0.0, DELTA, 0.0)) - dist;
90         float dfdz = eval_sdf(p + vec3(0.0, 0.0, DELTA)) - dist;
91         return normalize(vec3(dfdx, dfdy, dfdz));
92 }
93
94 vec3 primray(in vec2 uv, out vec3 org)
95 {
96         vec3 origin = (gl_ModelViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
97         org = origin;
98
99         vec2 nuv = uv * 2.0 - 1.0;
100         vec4 cp_near = vec4(nuv, -1.0, 1.0);
101
102         vec4 vdir = gl_ProjectionMatrixInverse * cp_near;
103         vec4 wdir = gl_ModelViewMatrixInverse * vec4(vdir.xyz, 0.0);
104
105         return normalize(wdir.xyz);
106 }
107
108 float boxdist(in vec3 p, in vec3 b)
109 {
110         vec3 q = abs(p) - b;
111         return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
112 }
113
114 float sphdist(in vec3 p, in vec3 sp, in float srad)
115 {
116         return length(p - sp) - srad;
117 }