1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#version 430
layout(local_size_x = 1, local_size_y = 1) in;
#include <sdf>
#include <utils>
#include <noise>
uniform float seconds = 0;
layout(rgba8) uniform readonly image2D cloud_noise_texture;
// layout(rgba8) uniform readonly image2D terrain_noise_texture;
layout(rgba8) uniform writeonly image2D output_image;
uniform vec3 camera_position = vec3(0, 1, 0);
uniform vec3 uv_direction = vec3(0);
uniform vec3 primary_light_position = vec3(1, 2, 1);
#define MAX_RAYMARCH_ITERATIONS 500
#define MAX_DISTANCE 100.0
#define SURFACE_DIST 0.01
// TODO: Enumify
#define OID_TERRAIN 4.
vec2 scene(in vec3 p) {
float c1 = sdf_circle(p - vec3(0, 1, 2.4), 0.2);
float c2 = sdf_circle(p - vec3(-0.6, 1, 3), 0.3);
float box = sdf_box(p - vec3(1, 0.5, 3), vec3(0.5, 0.18, 0.2), 0.07);
float terrain_noise = 6.0 * noise(p / 20.0) + 0.2 * noise((p + 10.0) / 2.0);
float terrain =
sdf_plane(p + vec3(0.0, terrain_noise, 0.0), vec3(0., 1., 0.), 0.0);
float light_indicator =
sdf_circle(p - primary_light_position + vec3(0.1, 0.1, -0.4), 0.01);
float dist = min(min(min(min(c1, c2), terrain), box), light_indicator);
float oid = 0.;
if (dist == c1)
oid = 1.;
else if (dist == c2)
oid = 2.;
else if (dist == box)
oid = 3.;
else if (dist == terrain)
oid = OID_TERRAIN;
else if (dist == light_indicator)
oid = -1.;
return vec2(dist, oid);
}
vec2 ray_march_scene(in vec3 ray_origin, in vec3 ray_direction) {
float dist = 0.;
for (int i = 0; i < MAX_RAYMARCH_ITERATIONS && dist < MAX_DISTANCE; i++) {
vec3 p = ray_origin + dist * ray_direction;
vec2 obj = scene(p);
float gap = obj.x;
dist += gap;
if (gap <= SURFACE_DIST)
return vec2(dist, obj.y);
}
return vec2(dist, 0.0);
}
float shadow_scene(in vec3 ray_origin, in vec3 ray_direction,
in float light_intensity) {
float dist = 0.;
float res = 1.;
float prev_gap = 1e10;
for (int i = 0; i < 50 && dist < MAX_DISTANCE; i++) {
vec3 p = ray_origin + dist * ray_direction;
vec2 obj = scene(p);
float gap = obj.x;
if (obj.y < 0.) // Debug objects dont cast shadows
continue;
float y = gap * gap / (10000.0 * prev_gap);
float d = sqrt(abs(gap * gap - y * y));
res = min(res, light_intensity * d / max(0., dist - y));
prev_gap = gap;
dist += gap;
if (res < 0.0001)
break;
}
res = clamp(res, 0.08, 1.0);
return res * res * (3.0 - 2.0 * res);
}
vec3 surface_normal_scene(in vec3 p) {
vec2 inc = vec2(0.01, 0);
return normalize(vec3(scene(p + inc.xyy).x - scene(p - inc.xyy).x,
scene(p + inc.yxy).x - scene(p - inc.yxy).x,
scene(p + inc.yyx).x - scene(p - inc.yyx).x));
}
void main() {
vec2 resolution = vec2(imageSize(output_image).xy);
vec3 uv = vec3((gl_GlobalInvocationID.xy - resolution / 2.0) / resolution, 0);
float aspect_ratio = resolution.y / resolution.x;
uv /= vec3(aspect_ratio, 1, 1);
vec3 uv_direction = normalize(vec3(uv.x, uv.y, 1));
vec3 light_pos = primary_light_position;
vec2 obj = ray_march_scene(camera_position, uv_direction);
float depth = obj.x;
float oid = obj.y;
vec3 p = camera_position + uv_direction * depth;
vec3 normal = surface_normal_scene(p);
vec3 light_dir = normalize(light_pos - p);
vec3 hal = normalize(light_dir - uv_direction);
vec3 col = vec3(0.9, 0.3, 0.4);
if (oid < 0.) // Debug objects
col = vec3(1.0, 0.2, 0.2);
else if (oid == OID_TERRAIN)
col = vec3(0.24, 0.61, 0.08);
else if (oid == 0) { // Sky
vec4 cloud_noise =
imageLoad(cloud_noise_texture, ivec2(gl_GlobalInvocationID.xy));
col = vec3(0.35, 0.6, 0.9);
col = mix(col, cloud_noise.xyz, clamp(0.5, 0., 1.));
}
if (depth < MAX_DISTANCE && oid > 0.) {
float contrast = 1.;
contrast *= clamp(dot(normal, light_dir), 0, 1.);
contrast *= shadow_scene(p, light_dir, 24.0);
col = col * 1.1 + 0.01;
col *= contrast;
if (oid != OID_TERRAIN) {
float spe =
pow(clamp(dot(normal, hal), 0.0, 1.0), 16.0) * contrast *
(0.04 +
0.96 * pow(clamp(1.0 + dot(hal, uv_direction), 0.0, 1.0), 5.0));
col += 12.0 * spe * vec3(1.00, 0.70, 0.5);
}
// col *= max(0.1, exp(-0.00005 * depth * depth * depth));
}
imageStore(output_image, ivec2(gl_GlobalInvocationID.xy),
vec4(clamp(col, 0., 1.), 1));
}
|