Files
WebGPU-Framework/shaders/points.wgsl
2025-11-17 15:06:39 +01:00

74 lines
1.7 KiB
WebGPU Shading Language

struct Point {
pos: vec3<f32>,
_pad: f32,
};
struct BillboardAxis {
vector : vec3<f32>,
_pad : f32,
};
struct VSOut {
@builtin(position) Position : vec4<f32>,
@location(0) uv : vec2<f32>,
@location(1) color : vec3<f32>,
};
@group(0) @binding(0) var<storage, read> positions: array<Point>;
@group(0) @binding(1) var<storage, read> sortedIndices: array<u32>; // New binding for sorted indices
@group(0) @binding(2) var<uniform> viewProjectionMatrix: mat4x4<f32>;
@group(0) @binding(3) var<uniform> cameraRight : BillboardAxis;
@group(0) @binding(4) var<uniform> cameraUp : BillboardAxis;
@vertex
fn vertexEntryPoint(
@builtin(vertex_index) vertexIndex: u32,
@builtin(instance_index) instanceIndex: u32,
@location(0) quadOffset: vec2<f32>
) -> VSOut {
var output: VSOut;
// Use the sorted index to get the actual particle index
let actualIndex = sortedIndices[instanceIndex];
let point = positions[actualIndex];
let center = point.pos;
let radius = 0.03;
let rightOffset = cameraRight.vector * quadOffset.x * radius;
let upOffset = cameraUp.vector * quadOffset.y * radius;
let worldPos = vec4<f32>(center + rightOffset + upOffset, 1.0);
output.Position = viewProjectionMatrix * worldPos;
output.uv = quadOffset;
output.color = (center + vec3<f32>(1.0, 1.0, 1.0)) * 0.5;
return output;
}
@fragment
fn fragmentEntryPoint(
@location(0) uv: vec2<f32>,
@location(1) color: vec3<f32>
) -> @location(0) vec4<f32> {
let dist = length(uv);
if (dist > 1.0) {
discard;
}
let z = sqrt(1.0 - dist * dist);
let normal = normalize(vec3<f32>(uv.x, uv.y, z));
let light = normalize(vec3<f32>(1.0, 1.0, 1.0));
let diffuse = max(dot(normal, light), 0.0);
return vec4<f32>(color * diffuse, 1.0);
}