// 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 globals: GlobalUniforms; @group(0) @binding(1) var object_data: ObjectsBuffer; @group(0) @binding(3) var noise_tex: texture_2d; @group(0) @binding(4) var noise_sampler: sampler; @group(0) @binding(5) var sky_tex: texture_2d; @group(1) @binding(0) var mask_tex: texture_2d; @group(1) @binding(1) var mask_sampler: sampler; struct VertexOutput { @builtin(position) position: vec4, @location(0) local_pos: vec3, @location(1) color: vec4, @location(2) @interpolate(flat) instance_index: u32, @location(3) world_pos: vec3, @location(4) transformed_normal: vec3, }; @vertex fn vs_main(@builtin(vertex_index) vertex_index: u32, @builtin(instance_index) instance_index: u32) -> VertexOutput { var pos = array, 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(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(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, @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; var normal: vec3; var base_color = in.color.rgb; let light_dir = normalize(vec3(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(ray_origin, 1.0)).xyz; let local_dir = normalize((inv_model * vec4(ray_dir, 0.0)).xyz); let t = ray_box(local_origin, local_dir, vec3(-1.0), vec3(1.0)); if (t.y < 0.0) { discard; } let t_start = max(t.x, 0.0); let t_end = t.y; var t_march = t_start; let max_steps = 128; var hit = false; var local_p = vec3(0.0); for (var step = 0; step < max_steps; step++) { local_p = local_origin + t_march * local_dir; let d = sdBox(local_p, vec3(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( sdBox(p + vec3(eps, 0.0, 0.0), vec3(1.0)) - sdBox(p - vec3(eps, 0.0, 0.0), vec3(1.0)), sdBox(p + vec3(0.0, eps, 0.0), vec3(1.0)) - sdBox(p - vec3(0.0, eps, 0.0), vec3(1.0)), sdBox(p + vec3(0.0, 0.0, eps), vec3(1.0)) - sdBox(p - vec3(0.0, 0.0, eps), vec3(1.0)) )); let world_p = (obj.model * vec4(p, 1.0)).xyz; let world_normal = normalize((obj.model * vec4(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(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(world_p, 1.0); let depth = clip_p.z / clip_p.w; var out: FragmentOutput; out.color = vec4(final_color, 1.0); out.depth = depth; return out; }