Skip to content

Commit 5644126

Browse files
committed
Add computecullandlod rust shaders
1 parent e9385aa commit 5644126

File tree

8 files changed

+214
-0
lines changed

8 files changed

+214
-0
lines changed

shaders/rust/Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
5.84 KB
Binary file not shown.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "computecullandlod-cull"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["dylib"]
8+
9+
[dependencies]
10+
spirv-std = { workspace = true }
11+
12+
[package.metadata.rust-gpu.build]
13+
capabilities = ["VulkanMemoryModelDeviceScope"]
14+
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#![no_std]
2+
3+
use spirv_std::spirv;
4+
use spirv_std::glam::{UVec3, Vec3, Vec4, Mat4, Vec4Swizzles};
5+
use spirv_std::arch::atomic_i_add;
6+
7+
#[repr(C)]
8+
#[derive(Copy, Clone)]
9+
pub struct InstanceData {
10+
pub pos: [f32; 3],
11+
pub scale: f32,
12+
}
13+
14+
#[repr(C)]
15+
#[derive(Copy, Clone)]
16+
pub struct IndexedIndirectCommand {
17+
pub index_count: u32,
18+
pub instance_count: u32,
19+
pub first_index: u32,
20+
pub vertex_offset: u32,
21+
pub first_instance: u32,
22+
}
23+
24+
#[repr(C)]
25+
#[derive(Copy, Clone)]
26+
pub struct UBO {
27+
pub projection: Mat4,
28+
pub modelview: Mat4,
29+
pub camera_pos: Vec4,
30+
pub frustum_planes: [Vec4; 6],
31+
}
32+
33+
#[repr(C)]
34+
#[derive(Copy, Clone)]
35+
pub struct UBOOut {
36+
pub draw_count: i32,
37+
pub lod_count: [i32; 6], // MAX_LOD_LEVEL + 1
38+
}
39+
40+
#[repr(C)]
41+
#[derive(Copy, Clone)]
42+
pub struct LOD {
43+
pub first_index: u32,
44+
pub index_count: u32,
45+
pub distance: f32,
46+
pub _pad0: f32,
47+
}
48+
49+
fn frustum_check(pos: Vec4, radius: f32, frustum_planes: &[Vec4; 6]) -> bool {
50+
for i in 0..6 {
51+
if pos.dot(frustum_planes[i]) + radius < 0.0 {
52+
return false;
53+
}
54+
}
55+
true
56+
}
57+
58+
#[spirv(compute(threads(16)))]
59+
pub fn main_cs(
60+
#[spirv(global_invocation_id)] global_id: UVec3,
61+
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] instances: &[InstanceData],
62+
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] indirect_draws: &mut [IndexedIndirectCommand],
63+
#[spirv(uniform, descriptor_set = 0, binding = 2)] ubo: &UBO,
64+
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] ubo_out: &mut UBOOut,
65+
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] lods: &[LOD],
66+
#[spirv(spec_constant(id = 0, default = 5))] max_lod_level: u32,
67+
) {
68+
let idx = global_id.x as usize;
69+
70+
// Bounds check - important!
71+
if idx >= instances.len() || idx >= indirect_draws.len() {
72+
return;
73+
}
74+
75+
let pos = Vec4::new(instances[idx].pos[0], instances[idx].pos[1], instances[idx].pos[2], 1.0);
76+
77+
// Check if object is within current viewing frustum
78+
if frustum_check(pos, 1.0, &ubo.frustum_planes) {
79+
indirect_draws[idx].instance_count = 1;
80+
81+
// Increase number of indirect draw counts
82+
unsafe {
83+
atomic_i_add::<i32, { spirv_std::memory::Scope::Device as u32 }, { spirv_std::memory::Semantics::NONE.bits() }>(
84+
&mut ubo_out.draw_count,
85+
1
86+
);
87+
}
88+
89+
// Select appropriate LOD level based on distance to camera
90+
let mut lod_level = max_lod_level;
91+
let camera_pos_vec3 = ubo.camera_pos.xyz();
92+
let instance_pos = Vec3::new(instances[idx].pos[0], instances[idx].pos[1], instances[idx].pos[2]);
93+
let dist = instance_pos.distance(camera_pos_vec3);
94+
for i in 0..max_lod_level {
95+
if dist < lods[i as usize].distance {
96+
lod_level = i;
97+
break;
98+
}
99+
}
100+
indirect_draws[idx].first_index = lods[lod_level as usize].first_index;
101+
indirect_draws[idx].index_count = lods[lod_level as usize].index_count;
102+
103+
// Update stats
104+
unsafe {
105+
atomic_i_add::<i32, { spirv_std::memory::Scope::Device as u32 }, { spirv_std::memory::Semantics::NONE.bits() }>(
106+
&mut ubo_out.lod_count[lod_level as usize],
107+
1
108+
);
109+
}
110+
} else {
111+
indirect_draws[idx].instance_count = 0;
112+
}
113+
}
Binary file not shown.
Binary file not shown.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "computecullandlod-indirectdraw"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["dylib"]
8+
9+
[dependencies]
10+
spirv-std = { workspace = true }
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![no_std]
2+
3+
use spirv_std::spirv;
4+
use spirv_std::glam::{Vec3, Vec4, Mat4, Vec4Swizzles};
5+
6+
#[repr(C)]
7+
#[derive(Copy, Clone)]
8+
pub struct UBO {
9+
pub projection: Mat4,
10+
pub modelview: Mat4,
11+
}
12+
13+
#[spirv(vertex)]
14+
pub fn main_vs(
15+
#[spirv(vertex_index)] _vertex_index: i32,
16+
in_pos: Vec4,
17+
in_normal: Vec3,
18+
in_color: Vec3,
19+
instance_pos: Vec3,
20+
instance_scale: f32,
21+
#[spirv(uniform, descriptor_set = 0, binding = 0)] ubo: &UBO,
22+
#[spirv(position)] out_position: &mut Vec4,
23+
out_normal: &mut Vec3,
24+
out_color: &mut Vec3,
25+
out_view_vec: &mut Vec3,
26+
out_light_vec: &mut Vec3,
27+
) {
28+
*out_color = in_color;
29+
*out_normal = in_normal;
30+
31+
let pos = Vec4::new(
32+
(in_pos.x * instance_scale) + instance_pos.x,
33+
(in_pos.y * instance_scale) + instance_pos.y,
34+
(in_pos.z * instance_scale) + instance_pos.z,
35+
1.0
36+
);
37+
38+
*out_position = ubo.projection * ubo.modelview * pos;
39+
40+
let l_pos = Vec4::new(0.0, 10.0, 50.0, 1.0);
41+
*out_light_vec = l_pos.xyz() - pos.xyz();
42+
*out_view_vec = -pos.xyz();
43+
}
44+
45+
#[spirv(fragment)]
46+
pub fn main_fs(
47+
in_normal: Vec3,
48+
in_color: Vec3,
49+
_in_view_vec: Vec3,
50+
in_light_vec: Vec3,
51+
out_frag_color: &mut Vec4,
52+
) {
53+
let n = in_normal.normalize();
54+
let l = in_light_vec.normalize();
55+
let ambient = Vec3::splat(0.25);
56+
let diffuse = Vec3::splat(n.dot(l).max(0.0));
57+
*out_frag_color = Vec4::new(
58+
(ambient.x + diffuse.x) * in_color.x,
59+
(ambient.y + diffuse.y) * in_color.y,
60+
(ambient.z + diffuse.z) * in_color.z,
61+
1.0
62+
);
63+
}

0 commit comments

Comments
 (0)