summaryrefslogtreecommitdiff
path: root/assets/final/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'assets/final/shaders')
-rw-r--r--assets/final/shaders/mesh_render.wgsl9
-rw-r--r--assets/final/shaders/render/scene_query_bvh.wgsl13
-rw-r--r--assets/final/shaders/render/scene_query_linear.wgsl60
-rw-r--r--assets/final/shaders/renderer_3d.wgsl63
4 files changed, 112 insertions, 33 deletions
diff --git a/assets/final/shaders/mesh_render.wgsl b/assets/final/shaders/mesh_render.wgsl
index 3759747..3faf7ca 100644
--- a/assets/final/shaders/mesh_render.wgsl
+++ b/assets/final/shaders/mesh_render.wgsl
@@ -33,10 +33,9 @@ fn vs_main(in: VertexInput, @builtin(instance_index) instance_index: u32) -> Ver
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<f32>(obj.model[0].xyz, obj.model[1].xyz, obj.model[2].xyz);
- out.normal = normalize(normal_matrix * in.normal);
+ // Use transpose of inverse for normals
+ let normal_matrix = mat3x3<f32>(obj.inv_model[0].xyz, obj.inv_model[1].xyz, obj.inv_model[2].xyz);
+ out.normal = normalize(transpose(normal_matrix) * in.normal);
out.uv = in.uv;
out.color = obj.color;
@@ -56,4 +55,4 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let lit_color = calculate_lighting(in.color.rgb, in.normal, in.world_pos, shadow);
return vec4<f32>(lit_color, in.color.a);
-}
+} \ No newline at end of file
diff --git a/assets/final/shaders/render/scene_query_bvh.wgsl b/assets/final/shaders/render/scene_query_bvh.wgsl
index c7dfdf4..d040c1b 100644
--- a/assets/final/shaders/render/scene_query_bvh.wgsl
+++ b/assets/final/shaders/render/scene_query_bvh.wgsl
@@ -10,11 +10,13 @@ struct BVHNode {
@group(0) @binding(2) var<storage, read> bvh_nodes: array<BVHNode>;
-fn get_dist(p: vec3<f32>, obj_type: f32) -> f32 {
+fn get_dist(p: vec3<f32>, obj_params: vec4<f32>) -> f32 {
+ let obj_type = obj_params.x;
if (obj_type == 1.0) { return length(p) - 1.0; } // Unit Sphere
if (obj_type == 2.0) { return sdBox(p, vec3<f32>(1.0)); } // Unit Box
if (obj_type == 3.0) { return sdTorus(p, vec2<f32>(1.0, 0.4)); } // Unit Torus
if (obj_type == 4.0) { return sdPlane(p, vec3<f32>(0.0, 1.0, 0.0), 0.0); }
+ if (obj_type == 5.0) { return sdBox(p, obj_params.yzw); } // MESH AABB
return 100.0;
}
@@ -40,7 +42,14 @@ fn map_scene(p: vec3<f32>, skip_idx: u32) -> f32 {
let obj = object_data.objects[obj_idx];
let q = (obj.inv_model * vec4<f32>(p, 1.0)).xyz;
let s = min(length(obj.model[0].xyz), min(length(obj.model[1].xyz), length(obj.model[2].xyz)));
- d = min(d, get_dist(q, obj.params.x) * s);
+ // IMPORTANT: Plane (type 4.0) should not be scaled by 's' in this way.
+ // The sdPlane function expects its own scale/offset implicitly handled by the model matrix.
+ // The 's' factor is meant for primitives whose SDFs are defined relative to a unit size.
+ if (obj.params.x != 4.0) { // Only scale if not a plane
+ d = min(d, get_dist(q, obj.params) * s);
+ } else {
+ d = min(d, get_dist(q, obj.params));
+ }
} else { // Internal
if (stack_ptr < 31) {
stack[stack_ptr] = node.left_idx;
diff --git a/assets/final/shaders/render/scene_query_linear.wgsl b/assets/final/shaders/render/scene_query_linear.wgsl
index 7bcd96f..30a0371 100644
--- a/assets/final/shaders/render/scene_query_linear.wgsl
+++ b/assets/final/shaders/render/scene_query_linear.wgsl
@@ -1,26 +1,64 @@
#include "math/sdf_shapes"
+#include "math/sdf_utils"
-fn get_dist(p: vec3<f32>, obj_type: f32) -> f32 {
+struct BVHNode {
+ min: vec3<f32>,
+ left_idx: i32,
+ max: vec3<f32>,
+ obj_idx_or_right: i32,
+};
+
+@group(0) @binding(2) var<storage, read> bvh_nodes: array<BVHNode>;
+
+fn get_dist(p: vec3<f32>, obj_params: vec4<f32>) -> f32 {
+ let obj_type = obj_params.x;
if (obj_type == 1.0) { return length(p) - 1.0; } // Unit Sphere
if (obj_type == 2.0) { return sdBox(p, vec3<f32>(1.0)); } // Unit Box
if (obj_type == 3.0) { return sdTorus(p, vec2<f32>(1.0, 0.4)); } // Unit Torus
if (obj_type == 4.0) { return sdPlane(p, vec3<f32>(0.0, 1.0, 0.0), 0.0); }
+ if (obj_type == 5.0) { return sdBox(p, obj_params.yzw); } // MESH AABB
return 100.0;
}
fn map_scene(p: vec3<f32>, skip_idx: u32) -> f32 {
var d = 1000.0;
- let count = u32(globals.params.x);
+ var stack: array<i32, 32>;
+ var stack_ptr = 0;
- for (var i = 0u; i < count; i = i + 1u) {
- if (i == skip_idx) { continue; }
- let obj = object_data.objects[i];
- let obj_type = obj.params.x;
- if (obj_type <= 0.0) { continue; }
+ if (arrayLength(&bvh_nodes) > 0u) {
+ stack[stack_ptr] = 0;
+ stack_ptr++;
+ }
- let q = (obj.inv_model * vec4<f32>(p, 1.0)).xyz;
- let s = min(length(obj.model[0].xyz), min(length(obj.model[1].xyz), length(obj.model[2].xyz)));
- d = min(d, get_dist(q, obj_type) * s);
+ while (stack_ptr > 0) {
+ stack_ptr--;
+ let node_idx = stack[stack_ptr];
+ let node = bvh_nodes[node_idx];
+
+ if (aabb_sdf(p, node.min, node.max) < d) {
+ if (node.left_idx < 0) { // Leaf
+ let obj_idx = u32(node.obj_idx_or_right);
+ if (obj_idx == skip_idx) { continue; }
+ let obj = object_data.objects[obj_idx];
+ let q = (obj.inv_model * vec4<f32>(p, 1.0)).xyz;
+ let s = min(length(obj.model[0].xyz), min(length(obj.model[1].xyz), length(obj.model[2].xyz)));
+ // IMPORTANT: Plane (type 4.0) should not be scaled by 's' in this way.
+ // The sdPlane function expects its own scale/offset implicitly handled by the model matrix.
+ // The 's' factor is meant for primitives whose SDFs are defined relative to a unit size.
+ if (obj.params.x != 4.0) { // Only scale if not a plane
+ d = min(d, get_dist(q, obj.params) * s);
+ } else {
+ d = min(d, get_dist(q, obj.params));
+ }
+ } else { // Internal
+ if (stack_ptr < 31) {
+ stack[stack_ptr] = node.left_idx;
+ stack_ptr++;
+ stack[stack_ptr] = node.obj_idx_or_right;
+ stack_ptr++;
+ }
+ }
+ }
}
return d;
-}
+} \ No newline at end of file
diff --git a/assets/final/shaders/renderer_3d.wgsl b/assets/final/shaders/renderer_3d.wgsl
index e7cb810..4733f6f 100644
--- a/assets/final/shaders/renderer_3d.wgsl
+++ b/assets/final/shaders/renderer_3d.wgsl
@@ -15,6 +15,7 @@ struct VertexOutput {
@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
@@ -41,8 +42,10 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32,
let obj_type = obj.params.x;
if (obj_type == 5.0) { // MESH
+ // For meshes, we use the actual vertex data, not proxy geometry.
+ // The position here is a placeholder, the real mesh data is handled by mesh_pipeline_.
var out: VertexOutput;
- out.position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
+ out.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); // Outside far plane, so it's not rendered by this pipeline.
return out;
}
@@ -62,6 +65,22 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32,
out.color = obj.color;
out.instance_index = instance_index;
out.world_pos = world_pos.xyz;
+
+ // Correct normal transformation for meshes: transpose of inverse of model matrix
+ // For non-uniform scaling, this is necessary. For other primitives, we use their analytical normals.
+ if (obj_type == 5.0) {
+ // Calculate inverse transpose of the model matrix (upper 3x3 part)
+ let model_matrix = mat3x3<f32>(obj.model[0].xyz, obj.model[1].xyz, obj.model[2].xyz);
+ let normal_matrix = transpose(inverse(model_matrix));
+ out.transformed_normal = normalize(normal_matrix * in.normal);
+ } else {
+ // For SDF primitives, we don't use vertex normals directly here; they are computed in the fragment shader.
+ // However, we still need to output a normal for the fragment shader to use if it were a rasterized primitive.
+ // The transformed_normal is not used by the SDF fragment shader, but for correctness, we'll pass it.
+ // If this were a rasterized mesh, it would be used.
+ out.transformed_normal = normalize(vec3<f32>(0.0, 1.0, 0.0)); // Placeholder for non-mesh types
+ }
+
return out;
}
@@ -70,8 +89,13 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32,
#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) -> @location(0) vec4<f32> {
+fn fs_main(in: VertexOutput) -> FragmentOutput {
let obj = object_data.objects[in.instance_index];
let obj_type = obj.params.x;
@@ -80,11 +104,10 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var base_color = in.color.rgb;
let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0));
- if (obj_type <= 0.0) { // Raster path
+ if (obj_type <= 0.0) { // Raster path (legacy or generic)
p = in.world_pos;
- let local_normal = normalize(cross(dpdx(in.local_pos), dpdy(in.local_pos)));
- let normal_matrix = mat3x3<f32>(obj.inv_model[0].xyz, obj.inv_model[1].xyz, obj.inv_model[2].xyz);
- normal = normalize(transpose(normal_matrix) * local_normal);
+ // Use the transformed normal passed from the vertex shader for rasterized objects
+ normal = normalize(in.transformed_normal);
// Apply grid pattern to floor
let uv = p.xz * 0.5;
@@ -100,8 +123,10 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let rd_local = normalize((obj.inv_model * vec4<f32>(rd_world, 0.0)).xyz);
// Proxy box extent (matches vs_main)
+ // MESHES use obj.params.yzw for extent
var extent = vec3<f32>(1.0);
- if (obj_type == 3.0) { extent = vec3<f32>(1.5, 0.5, 1.5); }
+ if (obj.params.x == 3.0) { extent = vec3<f32>(1.5, 0.5, 1.5); } // Torus
+ else if (obj.params.x == 5.0) { extent = obj.params.yzw; } // MESH extent
let bounds = ray_box_intersection(ro_local, rd_local, extent);
@@ -111,7 +136,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var hit = false;
for (var i = 0; i < 64; i = i + 1) {
let q = ro_local + rd_local * t;
- let d_local = get_dist(q, obj_type);
+ let d_local = get_dist(q, obj.params);
if (d_local < 0.0005) { hit = true; break; }
t = t + d_local;
if (t > bounds.t_exit) { break; }
@@ -128,32 +153,32 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let q_x1 = q_hit + e.xyy;
let uv_x1 = vec2<f32>(atan2(q_x1.x, q_x1.z) / 6.28 + 0.5, acos(clamp(q_x1.y / length(q_x1), -1.0, 1.0)) / 3.14);
let h_x1 = textureSample(noise_tex, noise_sampler, uv_x1).r;
- let d_x1 = get_dist(q_x1, obj_type) - disp_strength * h_x1;
+ let d_x1 = get_dist(q_x1, obj.params) - disp_strength * h_x1;
let q_x2 = q_hit - e.xyy;
let uv_x2 = vec2<f32>(atan2(q_x2.x, q_x2.z) / 6.28 + 0.5, acos(clamp(q_x2.y / length(q_x2), -1.0, 1.0)) / 3.14);
let h_x2 = textureSample(noise_tex, noise_sampler, uv_x2).r;
- let d_x2 = get_dist(q_x2, obj_type) - disp_strength * h_x2;
+ let d_x2 = get_dist(q_x2, obj.params) - disp_strength * h_x2;
let q_y1 = q_hit + e.yxy;
let uv_y1 = vec2<f32>(atan2(q_y1.x, q_y1.z) / 6.28 + 0.5, acos(clamp(q_y1.y / length(q_y1), -1.0, 1.0)) / 3.14);
let h_y1 = textureSample(noise_tex, noise_sampler, uv_y1).r;
- let d_y1 = get_dist(q_y1, obj_type) - disp_strength * h_y1;
+ let d_y1 = get_dist(q_y1, obj.params) - disp_strength * h_y1;
let q_y2 = q_hit - e.yxy;
let uv_y2 = vec2<f32>(atan2(q_y2.x, q_y2.z) / 6.28 + 0.5, acos(clamp(q_y2.y / length(q_y2), -1.0, 1.0)) / 3.14);
let h_y2 = textureSample(noise_tex, noise_sampler, uv_y2).r;
- let d_y2 = get_dist(q_y2, obj_type) - disp_strength * h_y2;
+ let d_y2 = get_dist(q_y2, obj.params) - disp_strength * h_y2;
let q_z1 = q_hit + e.yyx;
let uv_z1 = vec2<f32>(atan2(q_z1.x, q_z1.z) / 6.28 + 0.5, acos(clamp(q_z1.y / length(q_z1), -1.0, 1.0)) / 3.14);
let h_z1 = textureSample(noise_tex, noise_sampler, uv_z1).r;
- let d_z1 = get_dist(q_z1, obj_type) - disp_strength * h_z1;
+ let d_z1 = get_dist(q_z1, obj.params) - disp_strength * h_z1;
let q_z2 = q_hit - e.yyx;
let uv_z2 = vec2<f32>(atan2(q_z2.x, q_z2.z) / 6.28 + 0.5, acos(clamp(q_z2.y / length(q_z2), -1.0, 1.0)) / 3.14);
let h_z2 = textureSample(noise_tex, noise_sampler, uv_z2).r;
- let d_z2 = get_dist(q_z2, obj_type) - disp_strength * h_z2;
+ let d_z2 = get_dist(q_z2, obj.params) - disp_strength * h_z2;
let n_local = normalize(vec3<f32>(d_x1 - d_x2, d_y1 - d_y2, d_z1 - d_z2));
let normal_matrix = mat3x3<f32>(obj.inv_model[0].xyz, obj.inv_model[1].xyz, obj.inv_model[2].xyz);
@@ -174,5 +199,13 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let shadow = calc_shadow(p, light_dir, 0.05, 20.0, in.instance_index);
let lit_color = calculate_lighting(base_color, normal, p, shadow);
- return vec4<f32>(lit_color, 1.0);
+
+ var out: FragmentOutput;
+ out.color = vec4<f32>(lit_color, 1.0);
+
+ // Calculate and write correct depth
+ let clip_pos = globals.view_proj * vec4<f32>(p, 1.0);
+ out.depth = clip_pos.z / clip_pos.w;
+
+ return out;
} \ No newline at end of file