aboutsummaryrefslogtreecommitdiff
path: root/src/main/resources/shaders/mrdoor.glsl
blob: a37cbab4346e904ac635c9754d0e4c3b50119b32 (plain) (blame)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#version 430
layout(local_size_x = 1, local_size_y = 1) in;

#include <sdf>
#include <utils>
#include <noise>

uniform float seconds = 0;
uniform vec3 camera_position = vec3(0, 1, 0);
uniform mat3 camera_transformation;
uniform vec3 key_light_position;
layout(rgba8) uniform writeonly image2D output_image;

const vec3 door1_light_position = vec3(0.8, 4, 0.4);
const vec3 sunlight_color = vec3(1, 0.99, 0.99);

#define PI 3.14159265358979323

struct Obj {
  int objid;
  float dist;
  vec3 material;
  bool lighting;
  float shine;
};

Obj null_object = Obj(-1, -1.0, vec3(0.01), false, 0.0); // 0.35, 0.6, 0.9
Obj create_obj(in int objid, in float dist) {
  return Obj(objid, dist, vec3(1), true, 0.0);
}

void timing_actions(out float door1angle) {
  float maxt = 4.0;
  float t = mod(seconds, maxt);
  door1angle = -t / 1.6;
  if ((int(t / 2) % 2) == 1)
    door1angle = (t - maxt / 2) / 1.6 - PI / 2.5;
}

Obj scene(in vec3 p) {
  vec3 roomposabs = vec3(-0.5, 1.4, 5);
  vec3 roompos = p - roomposabs;
  float debugshapesdist = sdf_circle(p, 0.01);

  vec3 doorpos = roompos;
  vec3 doorsize = vec3(1., 2., 0.1);
  float door1angle;
  timing_actions(door1angle);
  vec3 hingepos = vec3(-1.0, 0, -0.0);
  debugshapesdist = min(debugshapesdist, sdf_circle(doorpos - hingepos, 0.1));
  doorpos = vec3(
      hingepos.x + (doorpos.x - hingepos.x) * cos(door1angle) - (doorpos.z - hingepos.z) * sin(door1angle),
      doorpos.y,
      hingepos.z + (doorpos.x - hingepos.x) * sin(door1angle) + (doorpos.z - hingepos.z) * cos(door1angle));

  float doorbody = sdf_box(doorpos, doorsize, 0.04);
  doorbody = ssubtract(doorbody, sdf_box(doorpos - vec3(0, 1.1, -0.2), vec3(0.65, 0.5, 0.1), 0), 0.1);
  doorbody = ssubtract(doorbody, sdf_box(doorpos - vec3(0, -0.75, -0.2), vec3(0.65, 0.85, 0.1), 0), 0.1);
  Obj doorhandle = create_obj(2, sdf_circle(doorpos - vec3(0.75, 0.34, -0.2), 0.1));
  doorhandle.material = vec3(0.4, 0.4, 0.4);
  doorhandle.shine = 22.0;
  Obj door = create_obj(2, doorbody);
  door.material = vec3(0.68, 0.17, 0.20);
  door.shine = 2.0;

  float doorframe = ssubtract(
      sdf_box(roompos - vec3(0, 0.5, 0), vec3(2., 2.6, 0.1), 0),
      sdf_box(roompos, doorsize + vec3(0.01, 0.01, 0.04), 0), 0.0);
  vec3 wallpos = roompos;
  wallpos.xz *= mat2x2(cos(PI / 2.), -sin(PI / 2.), sin(PI / 2.), cos(PI / 2.));
  float wallsides = min(
      sdf_box(wallpos - vec3(0, 0.5, -2), vec3(2., 2.6, 0.08), 0),
      sdf_box(wallpos - vec3(0, 0.5, 2), vec3(2., 2.6, 0.08), 0));
  float roof = sdf_box(roompos - vec3(0, 3.3, -2), vec3(2., 0.08, 2.6), 0);
  Obj walls = create_obj(2, min(min(doorframe, wallsides), roof));
  walls.material = vec3(0.15, 0.28, 0.42);

  debugshapesdist = min(debugshapesdist, sdf_circle(p - door1_light_position, 0.1));
  Obj debug = create_obj(-1, debugshapesdist);
  debug.lighting = false;
  debug.material = vec3(0, 1, 0);

  Obj floor = create_obj(0, sdf_plane(p - vec3(0, -0.6, 0), vec3(0, 1, 0), 0.0));
  floor.material = vec3(0.4);
  float dist = floor.dist;
  dist = min(door.dist, dist);
  dist = min(doorhandle.dist, dist);
  dist = min(walls.dist, dist);
  dist = min(debug.dist, dist);
  if (dist == door.dist) return door;
  if (dist == doorhandle.dist) return doorhandle;
  if (dist == floor.dist) return floor;
  if (dist == walls.dist) return walls;
  if (dist == debug.dist) return debug;
  return null_object;
}

#define RM_SHADOW_MAX_ITERATIONS 100
#define RM_MAX_ITERATIONS 300
#define RM_MAX_DISTANCE 80

Obj ray_march_scene(in vec3 ray_origin, in vec3 ray_direction) {
  float dist = 0;
  for (int i = 0; i < RM_MAX_ITERATIONS && dist < RM_MAX_DISTANCE; i++) {
    vec3 p = ray_origin + ray_direction * dist;
    Obj o = scene(p);
    dist += o.dist;
    if (o.dist <= 0.01) {
      o.dist = dist;
      return o;
    }
  }
  return null_object;
}

vec3 surface_normal_scene(in vec3 p) {
  vec2 e = vec2(0.01, 0);
  return normalize(vec3(
      scene(p + e.xyy).dist - scene(p - e.xyy).dist,
      scene(p + e.yxy).dist - scene(p - e.yxy).dist,
      scene(p + e.yyx).dist - scene(p - e.yyx).dist));
}

float shadow_scene(in vec3 ray_origin, in vec3 ray_direction, in float light_intensity) {
  float dist = 0.015;
  float res = 1.;
  float prev_gap = 1e10;
  for (int i = 0; i < RM_SHADOW_MAX_ITERATIONS && dist < RM_MAX_DISTANCE; i++) {
    vec3 p = ray_origin + dist * ray_direction;
    Obj obj = scene(p);
    float gap = obj.dist;
    if (!obj.lighting)
      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 * 1.1, 0.18, 1.0);
  return res * res * (3.0 - 2.0 * res);
}

void main() {
  vec2 resolution = vec2(imageSize(output_image).xy);
  float aspect_ratio = resolution.y / resolution.x;
  vec2 uv = (gl_GlobalInvocationID.xy - resolution / 2) * vec2(1.0, aspect_ratio) / resolution;

  vec3 origin = vec3(0);
  vec3 uv_direction = normalize((vec3(uv.x, uv.y, 1) - origin) * camera_transformation + origin);

  Obj obj = ray_march_scene(camera_position, uv_direction);
  vec3 p = camera_position + uv_direction * obj.dist;
  vec3 normal = surface_normal_scene(p);

  vec3 color = srgb(obj.material);

  if (obj.lighting) {
    float ambient = 0.03;

    vec3 keyl_dir = normalize(key_light_position - p);
    float key_contrast = 1.;
    key_contrast *= clamp(dot(normal, keyl_dir), 0, 1);
    // key_contrast *= shadow_scene(p, keyl_dir, 8.);
    key_contrast = clamp(key_contrast, 0, 1);

    vec3 door1_ldir = normalize(door1_light_position - p);
    float door1_contrast = 1.;
    door1_contrast *= clamp(dot(normal, door1_ldir), 0, 1);
    door1_contrast *= shadow_scene(p, door1_ldir, 128.);
    door1_contrast = clamp(door1_contrast, 0, 1);

    float contrast = max(key_contrast, door1_contrast);
    color *= clamp(ambient + contrast * (1.0 - ambient), 0, 1);

    vec3 hal_door1 = normalize(door1_ldir - uv_direction);
    float spec_door1 =
      pow(clamp(dot(normal, hal_door1), 0.0, 1.0), 16.0) * contrast *
        (0.04 +
          0.96 * pow(clamp(1.0 + dot(hal_door1, uv_direction), 0.0, 1.0), 5.0));
    color += obj.shine * spec_door1 * vec3(1.00, 0.70, 0.5);
  }

  color = clamp(color, 0, 1);
  imageStore(output_image, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1));
}