#include "common_uniforms" @group(0) @binding(0) var globals: GlobalUniforms; @group(0) @binding(1) var object_data: ObjectsBuffer; // Binding 2 is reserved for BVH (not used here but matches layout for simplicity) @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; struct VertexInput { @location(0) position: vec3, @location(1) normal: vec3, @location(2) uv: vec2, }; struct VertexOutput { @builtin(position) clip_pos: vec4, @location(0) world_pos: vec3, @location(1) normal: vec3, @location(2) uv: vec2, @location(3) color: vec4, @location(4) @interpolate(flat) instance_index: u32, }; @vertex fn vs_main(in: VertexInput, @builtin(instance_index) instance_index: u32) -> VertexOutput { let obj = object_data.objects[instance_index]; let world_pos = obj.model * vec4(in.position, 1.0); var out: VertexOutput; out.clip_pos = globals.view_proj * world_pos; out.world_pos = world_pos.xyz; // Normal transform (assuming uniform scale or using transpose(inverse(model))) // For simplicity, we use the same mat3 logic as renderer_3d.wgsl let normal_matrix = mat3x3(obj.model[0].xyz, obj.model[1].xyz, obj.model[2].xyz); out.normal = normalize(normal_matrix * in.normal); out.uv = in.uv; out.color = obj.color; out.instance_index = instance_index; return out; } #include "render/scene_query_mode" #include "render/shadows" #include "render/lighting_utils" @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { let light_dir = normalize(vec3(1.0, 1.0, 1.0)); let shadow = calc_shadow(in.world_pos, light_dir, 0.05, 20.0, in.instance_index); let lit_color = calculate_lighting(in.color.rgb, in.normal, in.world_pos, shadow); return vec4(lit_color, in.color.a); }