Make subdivision parameterised

This commit is contained in:
2025-07-11 15:24:17 +01:00
parent fcac31e796
commit 1bbac92645
8 changed files with 144 additions and 48 deletions
+17 -1
View File
@@ -4,7 +4,10 @@ use egui::{Color32, Frame, Id};
use egui_plot::{Line, Plot, PlotPoints};
use egui_winit_vulkano::Gui;
use crate::objects::{CSG, Light, Mesh};
use crate::{
MAXIMUM_SUBDIVISION, MINUMUM_SUBDIVISION,
objects::{CSG, Light, Mesh},
};
fn sized_text(ui: &mut egui::Ui, text: impl Into<String>, size: f32) {
ui.label(egui::RichText::new(text).size(size));
@@ -145,6 +148,19 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState, new_csg_needed: &mut boo
ui.add(egui::Slider::new(&mut csg.scale.x, 0.0..=2.0).text("Scale.x"));
ui.add(egui::Slider::new(&mut csg.scale.y, 0.0..=2.0).text("Scale.y"));
ui.add(egui::Slider::new(&mut csg.scale.z, 0.0..=2.0).text("Scale.z"));
ui.horizontal(|ui| {
ui.label("Subdivision");
for x in MINUMUM_SUBDIVISION.ilog2()..=MAXIMUM_SUBDIVISION.ilog2() {
let subdivision = 1 << x;
csg.new_pipelines_needed |= ui
.selectable_value(
&mut csg.subdivision,
subdivision,
format!("{}", subdivision),
)
.clicked();
}
});
}
for i in csgdel
.into_iter()
+6 -1
View File
@@ -1,11 +1,16 @@
#ifndef implicit_include
#define implicit_include
#extension GL_GOOGLE_include_directive:require
#include "include.glsl"
layout(set = 1, binding = 0) uniform Object {
uvec4 enable[(16*16*16)/(4*32)];
uvec4 enable[(SPEC_MAXIMUM_SUBDIVISION * SPEC_MAXIMUM_SUBDIVISION * SPEC_MAXIMUM_SUBDIVISION) / (4 * 32)];
vec3 dimensions;
vec3 lowest_corner;
uint material;
uint subdivision_log2;
float farplane;
} object_uniforms;
float scene(vec4 p) {
+12 -9
View File
@@ -1,6 +1,18 @@
#ifndef glsl_include
#define glsl_include
layout(constant_id = 0) const bool SPEC_BOUNDING_BOXES = false;
layout(constant_id = 1) const bool SPEC_BRUTE_FORCE = false;
layout(constant_id = 2) const bool SPEC_SHOW_AO = false;
layout(constant_id = 3) const bool SPEC_SHOW_NORMALS = false;
layout(constant_id = 4) const bool SPEC_SHOW_DEPTH = false;
layout(constant_id = 5) const bool SPEC_SHOW_ALBEDO = false;
layout(constant_id = 6) const bool SPEC_SHOW_ALL = false;
layout(constant_id = 7) const bool SPEC_DISABLE_AO = false;
//layout(constant_id = 30) const uint SPEC_MAXIMUM_SUBDIVISION = 64;
const uint SPEC_MAXIMUM_SUBDIVISION = 64;
layout(push_constant) uniform PushConstantData {
mat4 world;
mat4 inv_world;
@@ -18,13 +30,4 @@ layout(set = 0, binding = 1) uniform Camera {
vec4 campos_and_time;
} camera_uniforms;
layout(constant_id = 0) const bool SPEC_BOUNDING_BOXES = false;
layout(constant_id = 1) const bool SPEC_BRUTE_FORCE = false;
layout(constant_id = 2) const bool SPEC_SHOW_AO = false;
layout(constant_id = 3) const bool SPEC_SHOW_NORMALS = false;
layout(constant_id = 4) const bool SPEC_SHOW_DEPTH = false;
layout(constant_id = 5) const bool SPEC_SHOW_ALBEDO = false;
layout(constant_id = 6) const bool SPEC_SHOW_ALL = false;
layout(constant_id = 7) const bool SPEC_DISABLE_AO = false;
#endif
+51 -1
View File
@@ -8,6 +8,10 @@ const PIPELINE_CACHING: bool = false;
const BYTECODE_IMITATES_GLSL: bool = false;
const DEFAULT_SUBDIVISION: u32 = 16;
const MAXIMUM_SUBDIVISION: u32 = 64;
const MINUMUM_SUBDIVISION: u32 = 8;
use std::{
error::Error,
fs::{File, remove_file, rename},
@@ -877,6 +881,7 @@ impl ApplicationHandler for App {
self.block_enable_allocator.clone(),
self.descriptor_set_allocator.clone(),
rcx.swapchain.image_count(),
DEFAULT_SUBDIVISION,
0,
))
.unwrap();
@@ -1175,7 +1180,15 @@ impl App {
.push_constants(csg.trace_pipeline.layout().clone(), 0, push_constants[i])
.unwrap();
unsafe { builder.draw(VERTEX_COUNT as u32, 16 * 16 * 16, 0, 0) }.unwrap();
unsafe {
builder.draw(
VERTEX_COUNT as u32,
csg.subdivision * csg.subdivision * csg.subdivision,
0,
0,
)
}
.unwrap();
}
}
@@ -1297,6 +1310,7 @@ impl App {
self.block_enable_allocator.clone(),
self.descriptor_set_allocator.clone(),
rcx.swapchain.image_count(),
DEFAULT_SUBDIVISION,
-1,
))
.unwrap();
@@ -1385,6 +1399,37 @@ impl App {
rcx.recreate_pipelines = false;
}
{
let mut csg_left = 0;
for (i, csg) in self.gstate.csg.iter().enumerate() {
let rcsg = csg.read().unwrap();
if rcsg.new_pipelines_needed {
self.thread_work_creation
.send(WorkItem::RecompilePipelines(
csg.clone(),
self.device.clone(),
rcx.render_pass.clone(),
self.pipeline_cache.clone(),
rcx.shader_modules.clone(),
self.previous_debug.clone(),
i,
))
.unwrap();
csg_left += 1;
}
}
while csg_left > 0 {
for work in self.thread_work_completion.try_iter() {
match work {
WorkComplete::RecompilePipelines(index) => {
csg_left -= 1;
},
other => work_for_later.push(other),
}
}
}
}
self.move_camera();
let (image_index, suboptimal, acquire_future) =
@@ -1701,6 +1746,7 @@ fn get_spec_constants(debug: &PreviousDebug) -> HashMap<u32, SpecializationConst
const SPEC_SHOW_ALBEDO: u32 = 5;
const SPEC_SHOW_ALL: u32 = 6;
const SPEC_DISABLE_AO: u32 = 7;
const SPEC_MAXIMUM_SUBDISIVION: u32 = 30;
let mut spec_constants = HashMap::with_capacity(6);
spec_constants.insert(
@@ -1729,6 +1775,10 @@ fn get_spec_constants(debug: &PreviousDebug) -> HashMap<u32, SpecializationConst
SPEC_DISABLE_AO,
SpecializationConstant::Bool(debug.disable_ao),
);
spec_constants.insert(
SPEC_MAXIMUM_SUBDISIVION,
SpecializationConstant::U32(MAXIMUM_SUBDIVISION),
);
trace!("Specs: {:?}", spec_constants);
+4 -1
View File
@@ -9,7 +9,8 @@ use vulkano::{
memory::allocator::{
AllocationCreateInfo, MemoryAllocatePreference, MemoryTypeFilter, StandardMemoryAllocator,
},
pipeline::{graphics::vertex_input::Vertex, GraphicsPipeline}, shader::ShaderModule,
pipeline::{GraphicsPipeline, graphics::vertex_input::Vertex},
shader::ShaderModule,
};
use crate::{ssa::SSATape, trace_vs::Object};
@@ -42,10 +43,12 @@ pub(crate) struct CSG {
pub(crate) pos: Vec3,
pub(crate) rot: Vec3,
pub(crate) scale: Vec3,
pub(crate) new_pipelines_needed: bool,
pub(crate) trace_shader_module: Arc<ShaderModule>,
pub(crate) normals_shader_module: Arc<ShaderModule>,
pub(crate) trace_pipeline: Arc<GraphicsPipeline>,
pub(crate) normals_pipeline: Arc<GraphicsPipeline>,
pub(crate) subdivision: u32,
pub(crate) enable_buffer: Vec<Subbuffer<Object>>,
pub(crate) trace_descriptor_set: Vec<Arc<DescriptorSet>>,
pub(crate) normals_descriptor_set: Vec<Arc<DescriptorSet>>,
+43 -29
View File
@@ -36,7 +36,8 @@ use vulkano::{
};
use crate::{
DUMP_SPV_TO_FILE, IVertex, ShaderModules, get_spec_constants,
DUMP_SPV_TO_FILE, IVertex, MAXIMUM_SUBDIVISION, MINUMUM_SUBDIVISION, ShaderModules,
get_spec_constants,
gui::PreviousDebug,
interpreter::{self, IntervalInterpreter, PointInterpreter, VALUE_0},
objects::CSG,
@@ -58,6 +59,7 @@ pub enum WorkItem {
Arc<Mutex<SubbufferAllocator>>,
Arc<StandardDescriptorSetAllocator>,
u32,
u32,
isize,
),
GetPushConstants(Arc<RwLock<CSG>>, f32, usize, usize),
@@ -93,6 +95,7 @@ pub fn thread_loop(recv: mpmc::Receiver<WorkItem>, send: mpsc::SyncSender<WorkCo
block_enable_allocator,
descriptor_set_allocator,
frames,
subdivision,
index,
) => {
let csg_start = Instant::now();
@@ -168,10 +171,12 @@ pub fn thread_loop(recv: mpmc::Receiver<WorkItem>, send: mpsc::SyncSender<WorkCo
pos: Vec3::ZERO,
rot: Vec3::ZERO,
scale: Vec3::ONE,
new_pipelines_needed: false,
trace_shader_module,
normals_shader_module,
trace_pipeline,
normals_pipeline,
subdivision,
enable_buffer,
trace_descriptor_set,
normals_descriptor_set,
@@ -226,6 +231,7 @@ pub fn thread_loop(recv: mpmc::Receiver<WorkItem>, send: mpsc::SyncSender<WorkCo
csg.normals_shader_module.clone(),
debug,
);
csg.new_pipelines_needed = false;
send.send(WorkComplete::RecompilePipelines(index)).unwrap();
},
}
@@ -466,70 +472,78 @@ fn interval_check(csg: &CSG, material: u32, time: f32, frame_index: usize) {
let lowest_corner =
Vec3::new(interpreter_out[3], interpreter_out[4], interpreter_out[5]) - EPSILON;
const XDIM: usize = 16;
const YDIM: usize = 16;
const ZDIM: usize = 16;
// csg.subdivision must be a power of 2
assert_eq!(csg.subdivision.count_ones(), 1);
assert!(csg.subdivision <= MAXIMUM_SUBDIVISION);
assert!(csg.subdivision >= MINUMUM_SUBDIVISION);
let xdim = csg.subdivision as usize;
let ydim = csg.subdivision as usize;
let zdim = csg.subdivision as usize;
let mut obj = Object {
dimensions: (highest_corner - lowest_corner).to_array().into(),
lowest_corner: lowest_corner.into(),
enable: [[0; 4]; (XDIM * YDIM * ZDIM) / (32 * 4)],
enable: [[0; 4];
(MAXIMUM_SUBDIVISION * MAXIMUM_SUBDIVISION * MAXIMUM_SUBDIVISION) as usize / (32 * 4)],
material,
subdivision_log2: csg.subdivision.ilog2(),
farplane: (highest_corner - lowest_corner).length() / csg.subdivision as f32,
};
for x in 0..XDIM {
for y in 0..YDIM {
for z in 0..(ZDIM / 8) {
for x in 0..xdim {
for y in 0..ydim {
for z in 0..(zdim / 8) {
let interval_input_z: Interval = Interval::new_unchecked(
interpreter::Value::from_array([
((((8.0 / (ZDIM as f32)) * z as f32) + (0.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (0.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (1.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (1.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (2.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (2.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (3.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (3.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (4.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (4.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (5.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (5.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (6.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (6.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (7.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (7.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
]),
interpreter::Value::from_array([
((((8.0 / (ZDIM as f32)) * z as f32) + (1.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (1.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (2.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (2.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (3.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (3.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (4.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (4.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (5.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (5.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (6.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (6.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (7.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (7.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
((((8.0 / (ZDIM as f32)) * z as f32) + (8.0 / (ZDIM as f32)))
((((8.0 / (zdim as f32)) * z as f32) + (8.0 / (zdim as f32)))
* obj.dimensions[2])
+ obj.lowest_corner[2],
]),
@@ -538,18 +552,18 @@ fn interval_check(csg: &CSG, material: u32, time: f32, frame_index: usize) {
let mut interpreter = IntervalInterpreter::new(csg);
let output = interpreter.scene(
Interval::const_splat2(
(x as f32 / (XDIM as f32)) * obj.dimensions[0] + obj.lowest_corner[0],
((x + 1) as f32 / (XDIM as f32)) * obj.dimensions[0] + obj.lowest_corner[0],
(x as f32 / (xdim as f32)) * obj.dimensions[0] + obj.lowest_corner[0],
((x + 1) as f32 / (xdim as f32)) * obj.dimensions[0] + obj.lowest_corner[0],
),
Interval::const_splat2(
(y as f32 / (YDIM as f32)) * obj.dimensions[1] + obj.lowest_corner[1],
((y + 1) as f32 / (YDIM as f32)) * obj.dimensions[1] + obj.lowest_corner[1],
(y as f32 / (ydim as f32)) * obj.dimensions[1] + obj.lowest_corner[1],
((y + 1) as f32 / (ydim as f32)) * obj.dimensions[1] + obj.lowest_corner[1],
),
interval_input_z,
Interval::const_splat(time),
);
let total_index = (x * ZDIM * YDIM) + (y * ZDIM) + (z * 8);
let total_index = (x * zdim * ydim) + (y * zdim) + (z * 8);
let output = ((output.lower().simd_le(VALUE_0) & output.upper().simd_ge(VALUE_0))
.to_bitmask() as u32)
<< (total_index & 31);
+3 -2
View File
@@ -10,7 +10,6 @@ layout(depth_greater) out float gl_FragDepth;
layout(location = 0) out uint material;
const float EPSILON = .001;
float FARPLANE = SPEC_BRUTE_FORCE ? length(object_uniforms.dimensions) : length(object_uniforms.dimensions / 16.);
void main() {
if (SPEC_BOUNDING_BOXES) {
@@ -21,6 +20,8 @@ void main() {
vec3 raypos = pos.xyz;
vec3 raydir = normalize(raypos - (pc.inv_world * vec4(camera_uniforms.campos_and_time.xyz, 1)).xyz);
float farplane = SPEC_BRUTE_FORCE ? length(object_uniforms.dimensions) : object_uniforms.farplane;
vec3 p = raypos;
float total_dist = 0.;
do {
@@ -32,7 +33,7 @@ void main() {
gl_FragDepth = (tpoint.z / tpoint.w);
material = object_uniforms.material;
return;
} else if (total_dist > FARPLANE) {
} else if (total_dist > farplane) {
discard;
}
} while (true);
+8 -4
View File
@@ -17,9 +17,12 @@ void main() {
pos = vec4((position * object_uniforms.dimensions) + object_uniforms.lowest_corner, 1.);
} else {
vec3 internal_pos = vec3(
float((base_index >> 8) & 15) / 16.0,
float((base_index >> 4) & 15) / 16.0,
float((base_index >> 0) & 15) / 16.0
float((base_index >> (object_uniforms.subdivision_log2 * 2)) & ((1 << object_uniforms.subdivision_log2) - 1))
/ float(1 << object_uniforms.subdivision_log2),
float((base_index >> (object_uniforms.subdivision_log2 * 1)) & ((1 << object_uniforms.subdivision_log2) - 1))
/ float(1 << object_uniforms.subdivision_log2),
float((base_index >> (object_uniforms.subdivision_log2 * 0)) & ((1 << object_uniforms.subdivision_log2) - 1))
/ float(1 << object_uniforms.subdivision_log2)
);
bool enable;
@@ -43,7 +46,8 @@ void main() {
gl_Position = vec4(0.0 / 0.0);
return;
}
pos = vec4((((position / 16.0) + internal_pos) * object_uniforms.dimensions) + object_uniforms.lowest_corner, 1.);
pos = vec4((((position / float(1 << object_uniforms.subdivision_log2)) + internal_pos)
* object_uniforms.dimensions) + object_uniforms.lowest_corner, 1.);
}
gl_Position = camera_uniforms.proj_view * pc.world * pos;