summaryrefslogtreecommitdiff
path: root/assets/final/shaders/masked_cube.wgsl
blob: 5e673a3ac335a95f566cb350645ec55b63b41298 (plain)
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
// Masked cube shader - based on renderer_3d.wgsl with mask sampling
#include "common_uniforms"
#include "math/common_utils"
#include "math/sdf_utils"

@group(0) @binding(0) var<uniform> globals: GlobalUniforms;
@group(0) @binding(1) var<storage, read> object_data: ObjectsBuffer;
@group(0) @binding(3) var noise_tex: texture_2d<f32>;
@group(0) @binding(4) var noise_sampler: sampler;

@group(1) @binding(0) var mask_tex: texture_2d<f32>;
@group(1) @binding(1) var mask_sampler: sampler;

struct VertexOutput {
  @builtin(position) position: vec4<f32>,
  @location(0) local_pos: vec3<f32>,
  @location(1) color: vec4<f32>,
  @location(2) @interpolate(flat) instance_index: u32,
  @location(3) world_pos: vec3<f32>,
  @location(4) transformed_normal: vec3<f32>,
};

@vertex
fn vs_main(@builtin(vertex_index) vertex_index: u32,
           @builtin(instance_index) instance_index: u32) -> VertexOutput {
  var pos = array<vec3<f32>, 36>(
    vec3(-1.0, -1.0,  1.0), vec3( 1.0, -1.0,  1.0), vec3( 1.0,  1.0,  1.0),
    vec3(-1.0, -1.0,  1.0), vec3( 1.0,  1.0,  1.0), vec3(-1.0,  1.0,  1.0),
    vec3(-1.0, -1.0, -1.0), vec3(-1.0,  1.0, -1.0), vec3( 1.0,  1.0, -1.0),
    vec3(-1.0, -1.0, -1.0), vec3( 1.0,  1.0, -1.0), vec3( 1.0, -1.0, -1.0),
    vec3(-1.0,  1.0, -1.0), vec3(-1.0,  1.0,  1.0), vec3( 1.0,  1.0,  1.0),
    vec3(-1.0,  1.0, -1.0), vec3( 1.0,  1.0,  1.0), vec3( 1.0,  1.0, -1.0),
    vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0, -1.0), vec3( 1.0, -1.0,  1.0),
    vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0,  1.0), vec3(-1.0, -1.0,  1.0),
    vec3( 1.0, -1.0, -1.0), vec3( 1.0,  1.0, -1.0), vec3( 1.0,  1.0,  1.0),
    vec3( 1.0, -1.0, -1.0), vec3( 1.0,  1.0,  1.0), vec3( 1.0, -1.0,  1.0),
    vec3(-1.0, -1.0, -1.0), vec3(-1.0, -1.0,  1.0), vec3(-1.0,  1.0,  1.0),
    vec3(-1.0, -1.0, -1.0), vec3(-1.0,  1.0,  1.0), vec3(-1.0,  1.0, -1.0)
  );

  var p = pos[vertex_index];
  let obj = object_data.objects[instance_index];
  let world_pos = obj.model * vec4<f32>(p, 1.0);
  let clip_pos = globals.view_proj * world_pos;

  var out: VertexOutput;
  out.position = clip_pos;
  out.local_pos = p;
  out.color = obj.color;
  out.instance_index = instance_index;
  out.world_pos = world_pos.xyz;
  out.transformed_normal = normalize(vec3<f32>(0.0, 1.0, 0.0));

  return out;
}

#include "render/scene_query_mode"
#include "render/shadows"
#include "render/lighting_utils"
#include "ray_box"

struct FragmentOutput {
  @location(0) color: vec4<f32>,
  @builtin(frag_depth) depth: f32,
};

@fragment
fn fs_main(in: VertexOutput) -> FragmentOutput {
  let screen_uv = in.position.xy / globals.resolution;
  let mask_value = textureSample(mask_tex, mask_sampler, screen_uv).r;

  if (mask_value < 0.5) {
    discard;
  }

  let obj = object_data.objects[in.instance_index];
  let obj_type = obj.params.x;

  var p: vec3<f32>;
  var normal: vec3<f32>;
  var base_color = in.color.rgb;
  let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0));

  let ray_origin = globals.camera_pos_time.xyz;
  let ray_dir = normalize(in.world_pos - ray_origin);
  let inv_model = obj.inv_model;

  let local_origin = (inv_model * vec4<f32>(ray_origin, 1.0)).xyz;
  let local_dir = normalize((inv_model * vec4<f32>(ray_dir, 0.0)).xyz);

  let bounds = ray_box_intersection(local_origin, local_dir, vec3<f32>(1.0));
  if (!bounds.hit) {
    discard;
  }

  let t_start = bounds.t_entry;
  let t_end = bounds.t_exit;

  var t_march = t_start;
  let max_steps = 128;
  var hit = false;
  var local_p = vec3<f32>(0.0);

  for (var step = 0; step < max_steps; step++) {
    local_p = local_origin + t_march * local_dir;
    let d = sdBox(local_p, vec3<f32>(1.0));

    if (d < 0.001) {
      hit = true;
      break;
    }

    t_march += max(d * 0.5, 0.001);
    if (t_march > t_end) {
      break;
    }
  }

  if (!hit) {
    discard;
  }

  p = local_p;
  let eps = 0.001;
  normal = normalize(vec3<f32>(
    sdBox(p + vec3<f32>(eps, 0.0, 0.0), vec3<f32>(1.0)) -
    sdBox(p - vec3<f32>(eps, 0.0, 0.0), vec3<f32>(1.0)),
    sdBox(p + vec3<f32>(0.0, eps, 0.0), vec3<f32>(1.0)) -
    sdBox(p - vec3<f32>(0.0, eps, 0.0), vec3<f32>(1.0)),
    sdBox(p + vec3<f32>(0.0, 0.0, eps), vec3<f32>(1.0)) -
    sdBox(p - vec3<f32>(0.0, 0.0, eps), vec3<f32>(1.0))
  ));

  let world_p = (obj.model * vec4<f32>(p, 1.0)).xyz;
  let world_normal = normalize((obj.model * vec4<f32>(normal, 0.0)).xyz);

  let bump_strength = 0.3;
  let bump_scale = 4.0;
  let noise_uv = world_p.xy * bump_scale;
  let noise_val = textureSample(noise_tex, noise_sampler, noise_uv).r;
  let bump_offset = (noise_val - 0.5) * bump_strength;

  let bumped_normal = normalize(world_normal + vec3<f32>(bump_offset));

  let diffuse = max(dot(bumped_normal, light_dir), 0.0);
  let ambient = 0.3;
  let lighting = ambient + diffuse * 0.7;

  let final_color = base_color * lighting;

  let clip_p = globals.view_proj * vec4<f32>(world_p, 1.0);
  let depth = clip_p.z / clip_p.w;

  var out: FragmentOutput;
  out.color = vec4<f32>(final_color, 1.0);
  out.depth = depth;

  return out;
}