struct VertexInput { @location(0) position: vec3 }; struct InstanceInput { @location(2) position: vec3, @location(3) radius: f32 }; struct VertexOutput { @builtin(position) clip_position: vec4, @location(0) local_position: vec3 }; struct CameraUniform { view: mat4x4, proj: mat4x4, scale: f32 }; @group(0) @binding(0) var camera: CameraUniform; @vertex fn vs_main( model: VertexInput, instance: InstanceInput ) -> VertexOutput { var out: VertexOutput; var view = camera.view; //Billboard the circle let camera_right = vec3(view[0][0], view[1][0], view[2][0]); let camera_up = vec3(view[0][1], view[1][1], view[2][1]); let model_pos = camera_right * model.position.x + camera_up * model.position.y; let min_size = 0.025; //Scale the world around the camera scale. let instance_pos = instance.position * camera.scale; let view_proj = camera.proj * view; let center_view_pos = view_proj * vec4(instance_pos, 1.0); let vertex_view_pos = view_proj * vec4(instance_pos + (model_pos * instance.radius * camera.scale), 1.0); let vertex_dist = length(vertex_view_pos - center_view_pos) / center_view_pos.w; if vertex_dist < min_size { out.clip_position = center_view_pos / center_view_pos.w; out.clip_position += camera.proj * vec4(model.position.xy * (min_size / 2), 0.0, 0.0); }else{ out.clip_position = vertex_view_pos; } out.local_position = model.position; return out; } @fragment fn fs_main(in: VertexOutput ) -> @location(0) vec4 { let point_dist = length(in.local_position); var alpha = 1.0; if point_dist > 1.0 { alpha = 0.0; } return vec4(1.0, 1.0, 1.0, alpha); }