hack in the vulkano raytracing example
This commit is contained in:
@@ -7,6 +7,10 @@ glslangValidator --spirv-val -gVS -S vert --target-env vulkan1.3 -o shaders_out/
|
|||||||
glslangValidator --spirv-val -gVS -S frag --target-env vulkan1.3 -o shaders_out/lighting.frag.spv src/shaders/lighting.frag.glsl
|
glslangValidator --spirv-val -gVS -S frag --target-env vulkan1.3 -o shaders_out/lighting.frag.spv src/shaders/lighting.frag.glsl
|
||||||
glslangValidator --spirv-val -gVS -S vert --target-env vulkan1.3 -o shaders_out/trace.vert.spv src/shaders/trace.vert.glsl
|
glslangValidator --spirv-val -gVS -S vert --target-env vulkan1.3 -o shaders_out/trace.vert.spv src/shaders/trace.vert.glsl
|
||||||
|
|
||||||
|
glslangValidator --spirv-val -gVS -S rgen --target-env vulkan1.3 -o shaders_out/rgen.spv src/shaders/rgen.glsl
|
||||||
|
glslangValidator --spirv-val -gVS -S rchit --target-env vulkan1.3 -o shaders_out/rchit.spv src/shaders/rchit.glsl
|
||||||
|
glslangValidator --spirv-val -gVS -S rmiss --target-env vulkan1.3 -o shaders_out/rmiss.spv src/shaders/rmiss.glsl
|
||||||
|
|
||||||
echo src/shaders/trace.frag.glsl
|
echo src/shaders/trace.frag.glsl
|
||||||
glslangValidator --spirv-val --spirv-dis -g0 -S frag --target-env vulkan1.3 --quiet src/shaders/trace.frag.glsl > shaders_out/trace.spv-dis
|
glslangValidator --spirv-val --spirv-dis -g0 -S frag --target-env vulkan1.3 --quiet src/shaders/trace.frag.glsl > shaders_out/trace.spv-dis
|
||||||
sed -i '/%11 =/,/OpFunctionEnd/d' shaders_out/trace.spv-dis
|
sed -i '/%11 =/,/OpFunctionEnd/d' shaders_out/trace.spv-dis
|
||||||
|
|||||||
+441
-149
@@ -12,6 +12,9 @@ const DEFAULT_SUBDIVISION: u32 = 16;
|
|||||||
const MAXIMUM_SUBDIVISION: u32 = 64;
|
const MAXIMUM_SUBDIVISION: u32 = 64;
|
||||||
const MINUMUM_SUBDIVISION: u32 = 8;
|
const MINUMUM_SUBDIVISION: u32 = 8;
|
||||||
|
|
||||||
|
const RUN_STANDARD_PIPELINE: bool = false;
|
||||||
|
const RUN_RT_PIPELINE: bool = true;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fs::{File, remove_file, rename},
|
fs::{File, remove_file, rename},
|
||||||
@@ -50,15 +53,15 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
format::{ClearValue, Format, FormatFeatures},
|
format::{ClearValue, Format, FormatFeatures},
|
||||||
image::{
|
image::{
|
||||||
Image, ImageAspects, ImageCreateInfo, ImageSubresourceRange, ImageType, ImageUsage,
|
Image, ImageAspects, ImageCreateInfo, ImageFormatInfo, ImageSubresourceRange, ImageType,
|
||||||
SampleCount,
|
ImageUsage, SampleCount,
|
||||||
view::{ImageView, ImageViewCreateInfo},
|
view::{ImageView, ImageViewCreateInfo},
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||||
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
||||||
pipeline::{
|
pipeline::{
|
||||||
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineCreateFlags,
|
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
|
||||||
PipelineLayout, PipelineShaderStageCreateInfo,
|
PipelineShaderStageCreateInfo,
|
||||||
cache::{PipelineCache, PipelineCacheCreateInfo},
|
cache::{PipelineCache, PipelineCacheCreateInfo},
|
||||||
graphics::{
|
graphics::{
|
||||||
GraphicsPipelineCreateInfo,
|
GraphicsPipelineCreateInfo,
|
||||||
@@ -70,6 +73,10 @@ use vulkano::{
|
|||||||
viewport::Viewport,
|
viewport::Viewport,
|
||||||
},
|
},
|
||||||
layout::PipelineDescriptorSetLayoutCreateInfo,
|
layout::PipelineDescriptorSetLayoutCreateInfo,
|
||||||
|
ray_tracing::{
|
||||||
|
RayTracingPipeline, RayTracingPipelineCreateInfo, RayTracingShaderGroupCreateInfo,
|
||||||
|
ShaderBindingTable,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||||
shader::{ShaderModule, ShaderModuleCreateInfo, SpecializationConstant},
|
shader::{ShaderModule, ShaderModuleCreateInfo, SpecializationConstant},
|
||||||
@@ -86,7 +93,6 @@ use vulkano::{
|
|||||||
use winit::platform::x11::EventLoopBuilderExtX11;
|
use winit::platform::x11::EventLoopBuilderExtX11;
|
||||||
use winit::{
|
use winit::{
|
||||||
application::ApplicationHandler,
|
application::ApplicationHandler,
|
||||||
dpi::PhysicalSize,
|
|
||||||
event::{DeviceEvent, ElementState, MouseButton, WindowEvent},
|
event::{DeviceEvent, ElementState, MouseButton, WindowEvent},
|
||||||
event_loop::{ActiveEventLoop, EventLoop},
|
event_loop::{ActiveEventLoop, EventLoop},
|
||||||
keyboard::{KeyCode, PhysicalKey},
|
keyboard::{KeyCode, PhysicalKey},
|
||||||
@@ -96,6 +102,7 @@ use winit::{
|
|||||||
mod gui;
|
mod gui;
|
||||||
use crate::{
|
use crate::{
|
||||||
gui::*,
|
gui::*,
|
||||||
|
scene::Scene,
|
||||||
threads::{WorkComplete, WorkItem},
|
threads::{WorkComplete, WorkItem},
|
||||||
trace_vs::{Camera, Lights, PushConstantData},
|
trace_vs::{Camera, Lights, PushConstantData},
|
||||||
};
|
};
|
||||||
@@ -113,6 +120,8 @@ mod vm;
|
|||||||
|
|
||||||
mod threads;
|
mod threads;
|
||||||
|
|
||||||
|
mod scene;
|
||||||
|
|
||||||
fn main() -> Result<(), impl Error> {
|
fn main() -> Result<(), impl Error> {
|
||||||
CombinedLogger::init(vec![
|
CombinedLogger::init(vec![
|
||||||
TermLogger::new(
|
TermLogger::new(
|
||||||
@@ -228,13 +237,16 @@ struct ShaderModules {
|
|||||||
trace_vs: Arc<ShaderModule>,
|
trace_vs: Arc<ShaderModule>,
|
||||||
fullscreen_vs: Arc<ShaderModule>,
|
fullscreen_vs: Arc<ShaderModule>,
|
||||||
lighting_fs: Arc<ShaderModule>,
|
lighting_fs: Arc<ShaderModule>,
|
||||||
|
raygen: Arc<ShaderModule>,
|
||||||
|
closest_hit: Arc<ShaderModule>,
|
||||||
|
miss: Arc<ShaderModule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenderContext {
|
struct RenderContext {
|
||||||
window: Arc<Window>,
|
window: Arc<Window>,
|
||||||
swapchain: Arc<Swapchain>,
|
swapchain: Arc<Swapchain>,
|
||||||
render_pass: Arc<RenderPass>,
|
render_pass: Arc<RenderPass>,
|
||||||
framebuffers: Vec<Arc<Framebuffer>>,
|
framebuffers: Vec<(Arc<ImageView>, Arc<Framebuffer>)>,
|
||||||
color_buffer: Arc<ImageView>,
|
color_buffer: Arc<ImageView>,
|
||||||
material_buffer: Arc<ImageView>,
|
material_buffer: Arc<ImageView>,
|
||||||
ao_r_m_buffer: Arc<ImageView>,
|
ao_r_m_buffer: Arc<ImageView>,
|
||||||
@@ -246,6 +258,9 @@ struct RenderContext {
|
|||||||
lights_buffers_host_visible: Vec<Subbuffer<Lights>>,
|
lights_buffers_host_visible: Vec<Subbuffer<Lights>>,
|
||||||
shader_modules: ShaderModules,
|
shader_modules: ShaderModules,
|
||||||
lighting_pipeline: Arc<GraphicsPipeline>,
|
lighting_pipeline: Arc<GraphicsPipeline>,
|
||||||
|
rt_pipeline: Arc<RayTracingPipeline>,
|
||||||
|
rt_shader_binding_table: ShaderBindingTable,
|
||||||
|
scene: Scene,
|
||||||
viewport: Viewport,
|
viewport: Viewport,
|
||||||
recreate_swapchain: bool,
|
recreate_swapchain: bool,
|
||||||
recreate_pipelines: bool,
|
recreate_pipelines: bool,
|
||||||
@@ -271,6 +286,7 @@ impl App {
|
|||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
enabled_extensions: InstanceExtensions {
|
enabled_extensions: InstanceExtensions {
|
||||||
|
ext_swapchain_colorspace: true,
|
||||||
..required_extensions
|
..required_extensions
|
||||||
},
|
},
|
||||||
engine_name: Some("Tape Drive".to_owned()),
|
engine_name: Some("Tape Drive".to_owned()),
|
||||||
@@ -284,19 +300,45 @@ impl App {
|
|||||||
|
|
||||||
let device_extensions = DeviceExtensions {
|
let device_extensions = DeviceExtensions {
|
||||||
khr_swapchain: true,
|
khr_swapchain: true,
|
||||||
|
khr_ray_tracing_pipeline: true,
|
||||||
|
khr_ray_tracing_maintenance1: true,
|
||||||
|
khr_synchronization2: true,
|
||||||
|
khr_deferred_host_operations: true,
|
||||||
|
khr_acceleration_structure: true,
|
||||||
..DeviceExtensions::empty()
|
..DeviceExtensions::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let device_features = DeviceFeatures {
|
||||||
|
shader_int16: true,
|
||||||
|
shader_int8: true,
|
||||||
|
storage_buffer8_bit_access: true,
|
||||||
|
storage_buffer16_bit_access: true,
|
||||||
|
maintenance4: true,
|
||||||
|
fill_mode_non_solid: true,
|
||||||
|
shader_draw_parameters: true,
|
||||||
|
shader_demote_to_helper_invocation: true,
|
||||||
|
acceleration_structure: true,
|
||||||
|
ray_tracing_pipeline: true,
|
||||||
|
buffer_device_address: true,
|
||||||
|
synchronization2: true,
|
||||||
|
..DeviceFeatures::empty()
|
||||||
|
};
|
||||||
|
|
||||||
let (physical_device, (graphics_queue_index, transfer_queue_index)) = instance
|
let (physical_device, (graphics_queue_index, transfer_queue_index)) = instance
|
||||||
.enumerate_physical_devices()
|
.enumerate_physical_devices()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.filter(|p| p.supported_extensions().contains(&device_extensions))
|
.filter(|p| p.api_version() >= Version::V1_3)
|
||||||
|
.filter(|p| {
|
||||||
|
p.supported_extensions().contains(&device_extensions)
|
||||||
|
&& p.supported_features().contains(&device_features)
|
||||||
|
})
|
||||||
.filter_map(|p| {
|
.filter_map(|p| {
|
||||||
p.queue_family_properties()
|
p.queue_family_properties()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.position(|(i, q)| {
|
.position(|(i, q)| {
|
||||||
q.queue_flags.intersects(QueueFlags::GRAPHICS)
|
q.queue_flags
|
||||||
|
.contains(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
|
||||||
&& p.presentation_support(i as u32, event_loop)
|
&& p.presentation_support(i as u32, event_loop)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
@@ -305,11 +347,11 @@ impl App {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.position(|(i, q)| {
|
.position(|(i, q)| {
|
||||||
q.queue_flags.intersects(QueueFlags::TRANSFER) && i != graphics
|
q.queue_flags.contains(QueueFlags::TRANSFER) && i != graphics
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
p.queue_family_properties().iter().enumerate().position(
|
p.queue_family_properties().iter().enumerate().position(
|
||||||
|(_i, q)| q.queue_flags.intersects(QueueFlags::TRANSFER),
|
|(_i, q)| q.queue_flags.contains(QueueFlags::TRANSFER),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|i| (graphics as u32, i as u32))
|
.map(|i| (graphics as u32, i as u32))
|
||||||
@@ -384,20 +426,7 @@ impl App {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
enabled_features: DeviceFeatures {
|
enabled_features: device_features,
|
||||||
mesh_shader: false,
|
|
||||||
task_shader: false,
|
|
||||||
//shader_float16: true,
|
|
||||||
shader_int16: true,
|
|
||||||
shader_int8: true,
|
|
||||||
storage_buffer8_bit_access: true,
|
|
||||||
storage_buffer16_bit_access: true,
|
|
||||||
maintenance4: true,
|
|
||||||
fill_mode_non_solid: true,
|
|
||||||
shader_draw_parameters: true,
|
|
||||||
shader_demote_to_helper_invocation: true,
|
|
||||||
..DeviceFeatures::empty()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -456,6 +485,7 @@ impl App {
|
|||||||
&memory_allocator,
|
&memory_allocator,
|
||||||
&mut Cursor::new(PLATONIC_SOLIDS[0].1),
|
&mut Cursor::new(PLATONIC_SOLIDS[0].1),
|
||||||
PLATONIC_SOLIDS[0].0.to_string(),
|
PLATONIC_SOLIDS[0].0.to_string(),
|
||||||
|
BufferUsage::empty(),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
@@ -618,6 +648,33 @@ mod lighting_fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod raygen {
|
||||||
|
vulkano_shaders::shader! {
|
||||||
|
bytes: "shaders_out/rgen.spv",
|
||||||
|
vulkan_version: "1.3",
|
||||||
|
spirv_version: "1.6",
|
||||||
|
custom_derives: [Debug, Clone, Copy],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod closest_hit {
|
||||||
|
vulkano_shaders::shader! {
|
||||||
|
bytes: "shaders_out/rchit.spv",
|
||||||
|
vulkan_version: "1.3",
|
||||||
|
spirv_version: "1.6",
|
||||||
|
custom_derives: [Debug, Clone, Copy],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod miss {
|
||||||
|
vulkano_shaders::shader! {
|
||||||
|
bytes: "shaders_out/rmiss.spv",
|
||||||
|
vulkan_version: "1.3",
|
||||||
|
spirv_version: "1.6",
|
||||||
|
custom_derives: [Debug, Clone, Copy],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for App {
|
impl ApplicationHandler for App {
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
let window = Arc::new(
|
let window = Arc::new(
|
||||||
@@ -663,11 +720,24 @@ impl ApplicationHandler for App {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (image_format, _) = self
|
let (image_format, image_color_space) = self
|
||||||
.device
|
.device
|
||||||
.physical_device()
|
.physical_device()
|
||||||
.surface_formats(&surface, Default::default())
|
.surface_formats(&surface, Default::default())
|
||||||
.unwrap()[0];
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.find(|(format, _)| {
|
||||||
|
self.device
|
||||||
|
.physical_device()
|
||||||
|
.image_format_properties(ImageFormatInfo {
|
||||||
|
format: *format,
|
||||||
|
usage: ImageUsage::STORAGE,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Swapchain::new(
|
Swapchain::new(
|
||||||
self.device.clone(),
|
self.device.clone(),
|
||||||
@@ -678,9 +748,12 @@ impl ApplicationHandler for App {
|
|||||||
.min(surface_capabilities.max_image_count.unwrap_or(u32::MAX)),
|
.min(surface_capabilities.max_image_count.unwrap_or(u32::MAX)),
|
||||||
|
|
||||||
image_format,
|
image_format,
|
||||||
|
image_color_space,
|
||||||
image_extent: window_size.into(),
|
image_extent: window_size.into(),
|
||||||
|
|
||||||
image_usage: ImageUsage::COLOR_ATTACHMENT | ImageUsage::TRANSFER_DST,
|
image_usage: ImageUsage::COLOR_ATTACHMENT
|
||||||
|
| ImageUsage::TRANSFER_DST
|
||||||
|
| ImageUsage::STORAGE,
|
||||||
|
|
||||||
composite_alpha: surface_capabilities
|
composite_alpha: surface_capabilities
|
||||||
.supported_composite_alpha
|
.supported_composite_alpha
|
||||||
@@ -725,17 +798,40 @@ impl ApplicationHandler for App {
|
|||||||
::std::sync::Arc<::vulkano::shader::ShaderModule>,
|
::std::sync::Arc<::vulkano::shader::ShaderModule>,
|
||||||
::vulkano::Validated<::vulkano::VulkanError>,
|
::vulkano::Validated<::vulkano::VulkanError>,
|
||||||
>),
|
>),
|
||||||
|
((raygen::load)
|
||||||
|
as fn(
|
||||||
|
::std::sync::Arc<::vulkano::device::Device>,
|
||||||
|
) -> Result<
|
||||||
|
::std::sync::Arc<::vulkano::shader::ShaderModule>,
|
||||||
|
::vulkano::Validated<::vulkano::VulkanError>,
|
||||||
|
>),
|
||||||
|
((closest_hit::load)
|
||||||
|
as fn(
|
||||||
|
::std::sync::Arc<::vulkano::device::Device>,
|
||||||
|
) -> Result<
|
||||||
|
::std::sync::Arc<::vulkano::shader::ShaderModule>,
|
||||||
|
::vulkano::Validated<::vulkano::VulkanError>,
|
||||||
|
>),
|
||||||
|
((miss::load)
|
||||||
|
as fn(
|
||||||
|
::std::sync::Arc<::vulkano::device::Device>,
|
||||||
|
) -> Result<
|
||||||
|
::std::sync::Arc<::vulkano::shader::ShaderModule>,
|
||||||
|
::vulkano::Validated<::vulkano::VulkanError>,
|
||||||
|
>),
|
||||||
];
|
];
|
||||||
|
|
||||||
let pariter = loaders
|
let mut pariter = loaders
|
||||||
.iter()
|
.iter()
|
||||||
.map(|load| load(self.device.clone()).unwrap())
|
.map(|load| load(self.device.clone()).unwrap());
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let shader_modules = ShaderModules {
|
let shader_modules = ShaderModules {
|
||||||
trace_vs: pariter[0].clone(),
|
trace_vs: pariter.next().unwrap(),
|
||||||
fullscreen_vs: pariter[1].clone(),
|
fullscreen_vs: pariter.next().unwrap(),
|
||||||
lighting_fs: pariter[2].clone(),
|
lighting_fs: pariter.next().unwrap(),
|
||||||
|
raygen: pariter.next().unwrap(),
|
||||||
|
closest_hit: pariter.next().unwrap(),
|
||||||
|
miss: pariter.next().unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
drop(pariter);
|
drop(pariter);
|
||||||
@@ -794,11 +890,6 @@ impl ApplicationHandler for App {
|
|||||||
color: [final_color],
|
color: [final_color],
|
||||||
depth_stencil: {},
|
depth_stencil: {},
|
||||||
input: [color, normals, ao_r_m, depth, material],
|
input: [color, normals, ao_r_m, depth, material],
|
||||||
},
|
|
||||||
{
|
|
||||||
color: [final_color],
|
|
||||||
depth_stencil: {},
|
|
||||||
input: [],
|
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -823,13 +914,21 @@ impl ApplicationHandler for App {
|
|||||||
self.depth_format,
|
self.depth_format,
|
||||||
);
|
);
|
||||||
|
|
||||||
let lighting_pipeline = pipeline_recompile(
|
let (lighting_pipeline, rt_pipeline, rt_shader_binding_table) = pipeline_recompile(
|
||||||
|
&self.memory_allocator,
|
||||||
&render_pass,
|
&render_pass,
|
||||||
&self.pipeline_cache,
|
&self.pipeline_cache,
|
||||||
&shader_modules,
|
&shader_modules,
|
||||||
&self.gstate.debug,
|
&self.gstate.debug,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let scene = Scene::new(
|
||||||
|
&self.device,
|
||||||
|
&self.graphics_queue,
|
||||||
|
&self.memory_allocator,
|
||||||
|
&self.command_buffer_allocator,
|
||||||
|
);
|
||||||
|
|
||||||
let (
|
let (
|
||||||
camera_buffers,
|
camera_buffers,
|
||||||
camera_buffers_host_visible,
|
camera_buffers_host_visible,
|
||||||
@@ -856,11 +955,10 @@ impl ApplicationHandler for App {
|
|||||||
let previous_frame_end = (0..swapchain.image_count()).map(|_| None).collect();
|
let previous_frame_end = (0..swapchain.image_count()).map(|_| None).collect();
|
||||||
|
|
||||||
// Create an egui GUI
|
// Create an egui GUI
|
||||||
let gui = Gui::new_with_subpass(
|
let gui = Gui::new(
|
||||||
event_loop,
|
event_loop,
|
||||||
surface.clone(),
|
surface.clone(),
|
||||||
self.graphics_queue.clone(),
|
self.graphics_queue.clone(),
|
||||||
Subpass::from(render_pass.clone(), 3).unwrap(),
|
|
||||||
images[0].format(),
|
images[0].format(),
|
||||||
GuiConfig {
|
GuiConfig {
|
||||||
allow_srgb_render_target: true,
|
allow_srgb_render_target: true,
|
||||||
@@ -885,6 +983,9 @@ impl ApplicationHandler for App {
|
|||||||
lights_buffers_host_visible,
|
lights_buffers_host_visible,
|
||||||
shader_modules,
|
shader_modules,
|
||||||
lighting_pipeline,
|
lighting_pipeline,
|
||||||
|
rt_pipeline,
|
||||||
|
rt_shader_binding_table,
|
||||||
|
scene,
|
||||||
viewport,
|
viewport,
|
||||||
recreate_swapchain: false,
|
recreate_swapchain: false,
|
||||||
recreate_pipelines: false,
|
recreate_pipelines: false,
|
||||||
@@ -1073,6 +1174,8 @@ impl App {
|
|||||||
let uniform_data = trace_vs::Camera {
|
let uniform_data = trace_vs::Camera {
|
||||||
proj_view: (proj * view).to_cols_array_2d(),
|
proj_view: (proj * view).to_cols_array_2d(),
|
||||||
inv_proj_view: (proj * view).inverse().to_cols_array_2d(),
|
inv_proj_view: (proj * view).inverse().to_cols_array_2d(),
|
||||||
|
inv_proj: (proj).inverse().to_cols_array_2d(),
|
||||||
|
inv_view: (view).inverse().to_cols_array_2d(),
|
||||||
campos_and_time: [
|
campos_and_time: [
|
||||||
self.cstate.position.x,
|
self.cstate.position.x,
|
||||||
self.cstate.position.y,
|
self.cstate.position.y,
|
||||||
@@ -1146,6 +1249,9 @@ impl App {
|
|||||||
Option<Arc<DescriptorSet>>,
|
Option<Arc<DescriptorSet>>,
|
||||||
Arc<DescriptorSet>,
|
Arc<DescriptorSet>,
|
||||||
Arc<DescriptorSet>,
|
Arc<DescriptorSet>,
|
||||||
|
Arc<DescriptorSet>,
|
||||||
|
Arc<DescriptorSet>,
|
||||||
|
Arc<DescriptorSet>,
|
||||||
) {
|
) {
|
||||||
let trace_set1 = if self.csg_count > 0 {
|
let trace_set1 = if self.csg_count > 0 {
|
||||||
let trace_layout = &self.gstate.csg[0]
|
let trace_layout = &self.gstate.csg[0]
|
||||||
@@ -1243,12 +1349,51 @@ impl App {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let rt_layout1 = &rcx.rt_pipeline.layout().set_layouts()[0];
|
||||||
|
let rt_set1 = DescriptorSet::new(
|
||||||
|
self.descriptor_set_allocator.clone(),
|
||||||
|
rt_layout1.clone(),
|
||||||
|
[WriteDescriptorSet::buffer(
|
||||||
|
1,
|
||||||
|
rcx.camera_buffers[index].clone(),
|
||||||
|
)],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let rt_layout2 = &rcx.rt_pipeline.layout().set_layouts()[1];
|
||||||
|
let rt_set2 = DescriptorSet::new(
|
||||||
|
self.descriptor_set_allocator.clone(),
|
||||||
|
rt_layout2.clone(),
|
||||||
|
[WriteDescriptorSet::acceleration_structure(
|
||||||
|
0,
|
||||||
|
rcx.scene.tlas.clone(),
|
||||||
|
)],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let rt_layout3 = &rcx.rt_pipeline.layout().set_layouts()[2];
|
||||||
|
let rt_set3 = DescriptorSet::new(
|
||||||
|
self.descriptor_set_allocator.clone(),
|
||||||
|
rt_layout3.clone(),
|
||||||
|
[WriteDescriptorSet::image_view(
|
||||||
|
0,
|
||||||
|
rcx.framebuffers[index].0.clone(),
|
||||||
|
)],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
trace_set1,
|
trace_set1,
|
||||||
normals_set1,
|
normals_set1,
|
||||||
normals_set3,
|
normals_set3,
|
||||||
lighting_set1,
|
lighting_set1,
|
||||||
lighting_set2,
|
lighting_set2,
|
||||||
|
rt_set1,
|
||||||
|
rt_set2,
|
||||||
|
rt_set3,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1267,21 +1412,6 @@ impl App {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_commands_secondary_subpass(
|
|
||||||
&self,
|
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
|
||||||
) {
|
|
||||||
builder
|
|
||||||
.next_subpass(
|
|
||||||
Default::default(),
|
|
||||||
SubpassBeginInfo {
|
|
||||||
contents: SubpassContents::SecondaryCommandBuffers,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_commands_depth_pass(
|
fn add_commands_depth_pass(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
||||||
@@ -1377,14 +1507,29 @@ impl App {
|
|||||||
unsafe { builder.draw(3, 1, 0, 0) }.unwrap();
|
unsafe { builder.draw(3, 1, 0, 0) }.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_commands_gui(
|
fn add_commands_raytrace(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
||||||
rcx: &mut RenderContext,
|
rcx: &mut RenderContext,
|
||||||
window_size: PhysicalSize<u32>,
|
rt_set1: Arc<DescriptorSet>,
|
||||||
|
rt_set2: Arc<DescriptorSet>,
|
||||||
|
rt_set3: Arc<DescriptorSet>,
|
||||||
) {
|
) {
|
||||||
let guicb = rcx.gui.draw_on_subpass_image(window_size.into());
|
builder
|
||||||
builder.execute_commands(guicb).unwrap();
|
.bind_descriptor_sets(
|
||||||
|
PipelineBindPoint::RayTracing,
|
||||||
|
rcx.rt_pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
vec![rt_set1, rt_set2, rt_set3],
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_ray_tracing(rcx.rt_pipeline.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let extent = rcx.framebuffers[0].0.image().extent();
|
||||||
|
|
||||||
|
unsafe { builder.trace_rays(rcx.rt_shader_binding_table.addresses().clone(), extent) }
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_work_complete(&mut self, work: WorkComplete) {
|
fn handle_work_complete(&mut self, work: WorkComplete) {
|
||||||
@@ -1437,6 +1582,27 @@ impl App {
|
|||||||
}
|
}
|
||||||
let lighting_frag = lighting_frag.unwrap();
|
let lighting_frag = lighting_frag.unwrap();
|
||||||
|
|
||||||
|
let raygen = read_spirv_words_from_file("rgen.spv");
|
||||||
|
if raygen.is_err() {
|
||||||
|
error!("Could not read raygen file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let raygen = raygen.unwrap();
|
||||||
|
|
||||||
|
let closest_hit = read_spirv_words_from_file("rchit.spv");
|
||||||
|
if closest_hit.is_err() {
|
||||||
|
error!("Could not read closest hit file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let closest_hit = closest_hit.unwrap();
|
||||||
|
|
||||||
|
let miss = read_spirv_words_from_file("rmiss.spv");
|
||||||
|
if miss.is_err() {
|
||||||
|
error!("Could not read miss file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let miss = miss.unwrap();
|
||||||
|
|
||||||
let mut trace_loader = rspirv::dr::Loader::new();
|
let mut trace_loader = rspirv::dr::Loader::new();
|
||||||
rspirv::binary::parse_words(trace_frag, &mut trace_loader).unwrap();
|
rspirv::binary::parse_words(trace_frag, &mut trace_loader).unwrap();
|
||||||
|
|
||||||
@@ -1467,10 +1633,37 @@ impl App {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let raygen = unsafe {
|
||||||
|
::vulkano::shader::ShaderModule::new(
|
||||||
|
self.device.clone(),
|
||||||
|
ShaderModuleCreateInfo::new(&raygen),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let closest_hit = unsafe {
|
||||||
|
::vulkano::shader::ShaderModule::new(
|
||||||
|
self.device.clone(),
|
||||||
|
ShaderModuleCreateInfo::new(&closest_hit),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let miss = unsafe {
|
||||||
|
::vulkano::shader::ShaderModule::new(
|
||||||
|
self.device.clone(),
|
||||||
|
ShaderModuleCreateInfo::new(&miss),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
rcx.shader_modules = ShaderModules {
|
rcx.shader_modules = ShaderModules {
|
||||||
trace_vs: trace_vert,
|
trace_vs: trace_vert,
|
||||||
fullscreen_vs: fullscreen_vert,
|
fullscreen_vs: fullscreen_vert,
|
||||||
lighting_fs: lighting_frag,
|
lighting_fs: lighting_frag,
|
||||||
|
raygen,
|
||||||
|
closest_hit,
|
||||||
|
miss,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.trace_module = trace_loader.module();
|
self.trace_module = trace_loader.module();
|
||||||
@@ -1500,7 +1693,12 @@ impl App {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
rcx.lighting_pipeline = pipeline_recompile(
|
(
|
||||||
|
rcx.lighting_pipeline,
|
||||||
|
rcx.rt_pipeline,
|
||||||
|
rcx.rt_shader_binding_table,
|
||||||
|
) = pipeline_recompile(
|
||||||
|
&self.memory_allocator,
|
||||||
&rcx.render_pass,
|
&rcx.render_pass,
|
||||||
&self.pipeline_cache,
|
&self.pipeline_cache,
|
||||||
&rcx.shader_modules,
|
&rcx.shader_modules,
|
||||||
@@ -1715,8 +1913,16 @@ impl App {
|
|||||||
.then_signal_semaphore_and_flush()
|
.then_signal_semaphore_and_flush()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (trace_set, normals_set1, normals_set2, lighting_set1, lighting_set2) =
|
let (
|
||||||
self.get_descriptor_sets(rcx, image_index);
|
trace_set,
|
||||||
|
normals_set1,
|
||||||
|
normals_set2,
|
||||||
|
lighting_set1,
|
||||||
|
lighting_set2,
|
||||||
|
rt_set1,
|
||||||
|
rt_set2,
|
||||||
|
rt_set3,
|
||||||
|
) = self.get_descriptor_sets(rcx, image_index);
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
self.command_buffer_allocator.clone(),
|
self.command_buffer_allocator.clone(),
|
||||||
@@ -1725,88 +1931,92 @@ impl App {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let depth_clear = if self.depth_format.numeric_format_stencil().is_some() {
|
let mut futures = camera_and_lights.boxed();
|
||||||
Some((0.0, 0).into())
|
|
||||||
} else {
|
|
||||||
Some((0.0).into())
|
|
||||||
};
|
|
||||||
|
|
||||||
builder
|
if RUN_RT_PIPELINE {
|
||||||
.begin_render_pass(
|
self.add_commands_raytrace(&mut builder, rcx, rt_set1, rt_set2, rt_set3);
|
||||||
RenderPassBeginInfo {
|
}
|
||||||
clear_values: vec![
|
|
||||||
Some([0.0, 0.0, 0.0, 1.0].into()),
|
|
||||||
Some(ClearValue::Uint([0, 0, 0, 0])),
|
|
||||||
Some([0.12, 0.1, 0.1, 1.0].into()),
|
|
||||||
Some([0.0, 0.0, 0.0, 1.0].into()),
|
|
||||||
Some([0.0, 0.0, 0.0, 1.0].into()),
|
|
||||||
depth_clear,
|
|
||||||
],
|
|
||||||
..RenderPassBeginInfo::framebuffer(rcx.framebuffers[image_index].clone())
|
|
||||||
},
|
|
||||||
SubpassBeginInfo {
|
|
||||||
contents: SubpassContents::Inline,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [rcx.viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut push_constant_future: Option<Box<dyn GpuFuture>> = None;
|
if RUN_STANDARD_PIPELINE {
|
||||||
|
let depth_clear = if self.depth_format.numeric_format_stencil().is_some() {
|
||||||
|
Some((0.0, 0).into())
|
||||||
|
} else {
|
||||||
|
Some((0.0).into())
|
||||||
|
};
|
||||||
|
|
||||||
while push_constants_left > 0 {
|
builder
|
||||||
for work in self.thread_work_completion.try_iter() {
|
.begin_render_pass(
|
||||||
match work {
|
RenderPassBeginInfo {
|
||||||
WorkComplete::GetPushConstants(pc, future, index) => {
|
clear_values: vec![
|
||||||
push_constants[index] = pc;
|
Some([0.0, 0.0, 0.0, 1.0].into()),
|
||||||
push_constant_future = if push_constant_future.is_some() {
|
Some(ClearValue::Uint([0, 0, 0, 0])),
|
||||||
Some(push_constant_future.unwrap().join(future).boxed())
|
Some([0.12, 0.1, 0.1, 1.0].into()),
|
||||||
} else {
|
Some([0.0, 0.0, 0.0, 1.0].into()),
|
||||||
Some(future.boxed())
|
Some([0.0, 0.0, 0.0, 1.0].into()),
|
||||||
};
|
depth_clear,
|
||||||
push_constants_left -= 1;
|
],
|
||||||
|
..RenderPassBeginInfo::framebuffer(rcx.framebuffers[image_index].1.clone())
|
||||||
},
|
},
|
||||||
other => work_for_later.push(other),
|
SubpassBeginInfo {
|
||||||
|
contents: SubpassContents::Inline,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [rcx.viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut push_constant_future: Option<Box<dyn GpuFuture>> = None;
|
||||||
|
|
||||||
|
while push_constants_left > 0 {
|
||||||
|
for work in self.thread_work_completion.try_iter() {
|
||||||
|
match work {
|
||||||
|
WorkComplete::GetPushConstants(pc, future, index) => {
|
||||||
|
push_constants[index] = pc;
|
||||||
|
push_constant_future = if push_constant_future.is_some() {
|
||||||
|
Some(push_constant_future.unwrap().join(future).boxed())
|
||||||
|
} else {
|
||||||
|
Some(future.boxed())
|
||||||
|
};
|
||||||
|
push_constants_left -= 1;
|
||||||
|
},
|
||||||
|
other => work_for_later.push(other),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(f) = push_constant_future {
|
||||||
|
futures = f
|
||||||
|
.then_signal_semaphore_and_flush()
|
||||||
|
.unwrap()
|
||||||
|
.join(futures)
|
||||||
|
.boxed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.gstate.csg.len() > 0 {
|
||||||
|
self.add_commands_depth_pass(
|
||||||
|
&mut builder,
|
||||||
|
&push_constants,
|
||||||
|
trace_set.unwrap(),
|
||||||
|
image_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.add_commands_primary_subpass(&mut builder);
|
||||||
|
if self.gstate.csg.len() > 0 {
|
||||||
|
self.add_commands_normal_pass(
|
||||||
|
&mut builder,
|
||||||
|
&push_constants,
|
||||||
|
normals_set1.unwrap(),
|
||||||
|
normals_set2.unwrap(),
|
||||||
|
image_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.add_commands_primary_subpass(&mut builder);
|
||||||
|
self.add_commands_lighting_pass(&mut builder, rcx, lighting_set1, lighting_set2);
|
||||||
|
|
||||||
|
builder.end_render_pass(Default::default()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let futures = if let Some(f) = push_constant_future {
|
|
||||||
f.then_signal_semaphore_and_flush()
|
|
||||||
.unwrap()
|
|
||||||
.join(camera_and_lights)
|
|
||||||
.boxed()
|
|
||||||
} else {
|
|
||||||
camera_and_lights.boxed()
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.gstate.csg.len() > 0 {
|
|
||||||
self.add_commands_depth_pass(
|
|
||||||
&mut builder,
|
|
||||||
&push_constants,
|
|
||||||
trace_set.unwrap(),
|
|
||||||
image_index,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.add_commands_primary_subpass(&mut builder);
|
|
||||||
if self.gstate.csg.len() > 0 {
|
|
||||||
self.add_commands_normal_pass(
|
|
||||||
&mut builder,
|
|
||||||
&push_constants,
|
|
||||||
normals_set1.unwrap(),
|
|
||||||
normals_set2.unwrap(),
|
|
||||||
image_index,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.add_commands_primary_subpass(&mut builder);
|
|
||||||
self.add_commands_lighting_pass(&mut builder, rcx, lighting_set1, lighting_set2);
|
|
||||||
self.add_commands_secondary_subpass(&mut builder);
|
|
||||||
if self.draw_gui {
|
|
||||||
self.add_commands_gui(&mut builder, rcx, window_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.end_render_pass(Default::default()).unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
for future in rcx.previous_frame_end.iter_mut().flatten() {
|
for future in rcx.previous_frame_end.iter_mut().flatten() {
|
||||||
@@ -1821,7 +2031,16 @@ impl App {
|
|||||||
.join(acquire_future)
|
.join(acquire_future)
|
||||||
.join(futures)
|
.join(futures)
|
||||||
.then_execute(self.graphics_queue.clone(), command_buffer)
|
.then_execute(self.graphics_queue.clone(), command_buffer)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
|
|
||||||
|
let future = if self.draw_gui {
|
||||||
|
rcx.gui
|
||||||
|
.draw_on_image(future, rcx.framebuffers[image_index].0.clone())
|
||||||
|
} else {
|
||||||
|
future.boxed()
|
||||||
|
};
|
||||||
|
|
||||||
|
let future = future
|
||||||
.then_swapchain_present(
|
.then_swapchain_present(
|
||||||
self.graphics_queue.clone(),
|
self.graphics_queue.clone(),
|
||||||
SwapchainPresentInfo::swapchain_image_index(
|
SwapchainPresentInfo::swapchain_image_index(
|
||||||
@@ -1867,7 +2086,7 @@ fn framebuffer_generation(
|
|||||||
allocator: &Arc<StandardMemoryAllocator>,
|
allocator: &Arc<StandardMemoryAllocator>,
|
||||||
depth_format: Format,
|
depth_format: Format,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<Arc<Framebuffer>>,
|
Vec<(Arc<ImageView>, Arc<Framebuffer>)>,
|
||||||
Arc<ImageView>,
|
Arc<ImageView>,
|
||||||
Arc<ImageView>,
|
Arc<ImageView>,
|
||||||
Arc<ImageView>,
|
Arc<ImageView>,
|
||||||
@@ -1978,12 +2197,13 @@ fn framebuffer_generation(
|
|||||||
let framebuffers = images
|
let framebuffers = images
|
||||||
.iter()
|
.iter()
|
||||||
.map(|image| {
|
.map(|image| {
|
||||||
let view = ImageView::new_default(image.clone()).unwrap();
|
let image_view = ImageView::new_default(image.clone()).unwrap();
|
||||||
Framebuffer::new(
|
|
||||||
|
let framebuffer = Framebuffer::new(
|
||||||
render_pass.clone(),
|
render_pass.clone(),
|
||||||
FramebufferCreateInfo {
|
FramebufferCreateInfo {
|
||||||
attachments: vec![
|
attachments: vec![
|
||||||
view,
|
image_view.clone(),
|
||||||
material_buffer.clone(),
|
material_buffer.clone(),
|
||||||
color_buffer.clone(),
|
color_buffer.clone(),
|
||||||
ao_r_m_buffer.clone(),
|
ao_r_m_buffer.clone(),
|
||||||
@@ -1993,7 +2213,9 @@ fn framebuffer_generation(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
|
|
||||||
|
(image_view, framebuffer)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -2066,11 +2288,16 @@ fn get_spec_constants(debug: &PreviousDebug) -> HashMap<u32, SpecializationConst
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pipeline_recompile(
|
fn pipeline_recompile(
|
||||||
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
render_pass: &Arc<RenderPass>,
|
render_pass: &Arc<RenderPass>,
|
||||||
cache: &Arc<PipelineCache>,
|
cache: &Arc<PipelineCache>,
|
||||||
shader_modules: &ShaderModules,
|
shader_modules: &ShaderModules,
|
||||||
debug: &PreviousDebug,
|
debug: &PreviousDebug,
|
||||||
) -> Arc<GraphicsPipeline> {
|
) -> (
|
||||||
|
Arc<GraphicsPipeline>,
|
||||||
|
Arc<RayTracingPipeline>,
|
||||||
|
ShaderBindingTable,
|
||||||
|
) {
|
||||||
let device = cache.device();
|
let device = cache.device();
|
||||||
|
|
||||||
let specs = get_spec_constants(debug);
|
let specs = get_spec_constants(debug);
|
||||||
@@ -2115,11 +2342,11 @@ fn pipeline_recompile(
|
|||||||
device.clone(),
|
device.clone(),
|
||||||
Some(cache.clone()),
|
Some(cache.clone()),
|
||||||
GraphicsPipelineCreateInfo {
|
GraphicsPipelineCreateInfo {
|
||||||
flags: PipelineCreateFlags::DISABLE_OPTIMIZATION,
|
//flags: PipelineCreateFlags::DISABLE_OPTIMIZATION,
|
||||||
stages,
|
stages,
|
||||||
vertex_input_state: Some(vertex_input_state),
|
vertex_input_state: Some(vertex_input_state),
|
||||||
input_assembly_state: Some(InputAssemblyState::default()),
|
input_assembly_state: Some(InputAssemblyState::default()),
|
||||||
dynamic_state,
|
dynamic_state: dynamic_state.clone(),
|
||||||
viewport_state: Some(Default::default()),
|
viewport_state: Some(Default::default()),
|
||||||
rasterization_state: Some(RasterizationState {
|
rasterization_state: Some(RasterizationState {
|
||||||
front_face: FrontFace::Clockwise,
|
front_face: FrontFace::Clockwise,
|
||||||
@@ -2140,9 +2367,74 @@ fn pipeline_recompile(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let rt_pipeline = {
|
||||||
|
let raygen = shader_modules
|
||||||
|
.raygen
|
||||||
|
.specialize(specs.clone())
|
||||||
|
.unwrap()
|
||||||
|
.single_entry_point()
|
||||||
|
.unwrap();
|
||||||
|
let closest_hit = shader_modules
|
||||||
|
.closest_hit
|
||||||
|
.specialize(specs.clone())
|
||||||
|
.unwrap()
|
||||||
|
.single_entry_point()
|
||||||
|
.unwrap();
|
||||||
|
let miss = shader_modules
|
||||||
|
.miss
|
||||||
|
.specialize(specs.clone())
|
||||||
|
.unwrap()
|
||||||
|
.single_entry_point()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Make a list of the shader stages that the pipeline will have.
|
||||||
|
let stages = [
|
||||||
|
&PipelineShaderStageCreateInfo::new(raygen),
|
||||||
|
&PipelineShaderStageCreateInfo::new(miss),
|
||||||
|
&PipelineShaderStageCreateInfo::new(closest_hit),
|
||||||
|
];
|
||||||
|
|
||||||
|
let layout = PipelineLayout::new(
|
||||||
|
device.clone(),
|
||||||
|
PipelineDescriptorSetLayoutCreateInfo::from_stages(stages)
|
||||||
|
.into_pipeline_layout_create_info(device.clone())
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Define the shader groups that will eventually turn into the shader binding
|
||||||
|
// table. The numbers are the indices of the stages in the `stages`
|
||||||
|
// array.
|
||||||
|
let groups = [
|
||||||
|
RayTracingShaderGroupCreateInfo::General { general_shader: 0 },
|
||||||
|
RayTracingShaderGroupCreateInfo::General { general_shader: 1 },
|
||||||
|
RayTracingShaderGroupCreateInfo::TrianglesHit {
|
||||||
|
closest_hit_shader: Some(2),
|
||||||
|
any_hit_shader: None,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
RayTracingPipeline::new(
|
||||||
|
device.clone(),
|
||||||
|
Some(cache.clone()),
|
||||||
|
RayTracingPipelineCreateInfo {
|
||||||
|
//flags: PipelineCreateFlags::DISABLE_OPTIMIZATION,
|
||||||
|
stages: stages.into_iter().cloned().collect(),
|
||||||
|
groups: groups.into_iter().collect(),
|
||||||
|
max_pipeline_ray_recursion_depth: 1,
|
||||||
|
//dynamic_state: dynamic_state.clone(),
|
||||||
|
..RayTracingPipelineCreateInfo::layout(layout)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let shader_binding_table =
|
||||||
|
ShaderBindingTable::new(memory_allocator.clone(), &rt_pipeline).unwrap();
|
||||||
|
|
||||||
dump_pipeline_cache(cache.clone());
|
dump_pipeline_cache(cache.clone());
|
||||||
|
|
||||||
lighting_pipeline
|
(lighting_pipeline, rt_pipeline, shader_binding_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gpu_upload<T>(
|
fn gpu_upload<T>(
|
||||||
|
|||||||
+3
-2
@@ -63,6 +63,7 @@ pub(crate) fn load_obj(
|
|||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
input: &mut dyn Read,
|
input: &mut dyn Read,
|
||||||
name: String,
|
name: String,
|
||||||
|
additional_usage: BufferUsage,
|
||||||
) -> Result<Vec<Mesh>, ObjError> {
|
) -> Result<Vec<Mesh>, ObjError> {
|
||||||
let object = ObjData::load_buf_with_config(input, LoadConfig::default())?;
|
let object = ObjData::load_buf_with_config(input, LoadConfig::default())?;
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ pub(crate) fn load_obj(
|
|||||||
let vertex_buffer = Buffer::from_iter(
|
let vertex_buffer = Buffer::from_iter(
|
||||||
memory_allocator.clone(),
|
memory_allocator.clone(),
|
||||||
BufferCreateInfo {
|
BufferCreateInfo {
|
||||||
usage: BufferUsage::VERTEX_BUFFER,
|
usage: BufferUsage::VERTEX_BUFFER | additional_usage,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
AllocationCreateInfo {
|
AllocationCreateInfo {
|
||||||
@@ -115,7 +116,7 @@ pub(crate) fn load_obj(
|
|||||||
let index_buffer = Buffer::from_iter(
|
let index_buffer = Buffer::from_iter(
|
||||||
memory_allocator.clone(),
|
memory_allocator.clone(),
|
||||||
BufferCreateInfo {
|
BufferCreateInfo {
|
||||||
usage: BufferUsage::INDEX_BUFFER,
|
usage: BufferUsage::INDEX_BUFFER | additional_usage,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
AllocationCreateInfo {
|
AllocationCreateInfo {
|
||||||
|
|||||||
+275
@@ -0,0 +1,275 @@
|
|||||||
|
use std::{io::Cursor, iter, mem::size_of, sync::Arc};
|
||||||
|
|
||||||
|
use vulkano::{
|
||||||
|
Packed24_8,
|
||||||
|
acceleration_structure::{
|
||||||
|
AccelerationStructure, AccelerationStructureBuildGeometryInfo,
|
||||||
|
AccelerationStructureBuildRangeInfo, AccelerationStructureBuildType,
|
||||||
|
AccelerationStructureCreateInfo, AccelerationStructureGeometries,
|
||||||
|
AccelerationStructureGeometryInstancesData, AccelerationStructureGeometryInstancesDataType,
|
||||||
|
AccelerationStructureGeometryTrianglesData, AccelerationStructureInstance,
|
||||||
|
AccelerationStructureType, BuildAccelerationStructureFlags, BuildAccelerationStructureMode,
|
||||||
|
GeometryInstanceFlags,
|
||||||
|
},
|
||||||
|
buffer::{Buffer, BufferCreateInfo, BufferUsage, IndexBuffer, Subbuffer},
|
||||||
|
command_buffer::{
|
||||||
|
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
|
||||||
|
allocator::{CommandBufferAllocator, StandardCommandBufferAllocator},
|
||||||
|
},
|
||||||
|
device::{Device, Queue},
|
||||||
|
format::Format,
|
||||||
|
memory::allocator::{
|
||||||
|
AllocationCreateInfo, DeviceLayout, MemoryAllocator, MemoryTypeFilter,
|
||||||
|
StandardMemoryAllocator,
|
||||||
|
},
|
||||||
|
sync::GpuFuture,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::objects::{Mesh, OVertex, PLATONIC_SOLIDS, load_obj};
|
||||||
|
|
||||||
|
pub struct Scene {
|
||||||
|
// The bottom-level acceleration structure is required to be kept alive
|
||||||
|
// as we reference it in the top-level acceleration structure.
|
||||||
|
pub _blas: Arc<AccelerationStructure>,
|
||||||
|
pub tlas: Arc<AccelerationStructure>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
pub fn new(
|
||||||
|
device: &Arc<Device>,
|
||||||
|
graphics_queue: &Arc<Queue>,
|
||||||
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
|
command_buffer_allocator: &Arc<StandardCommandBufferAllocator>,
|
||||||
|
) -> Self {
|
||||||
|
let mesh = load_obj(
|
||||||
|
&memory_allocator,
|
||||||
|
&mut Cursor::new(PLATONIC_SOLIDS[0].1),
|
||||||
|
PLATONIC_SOLIDS[0].0.to_string(),
|
||||||
|
BufferUsage::SHADER_DEVICE_ADDRESS
|
||||||
|
| BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Build the bottom-level acceleration structure and then the top-level
|
||||||
|
// acceleration structure. Acceleration structures are used to
|
||||||
|
// accelerate ray tracing. The bottom-level acceleration structure
|
||||||
|
// contains the geometry data. The top-level acceleration structure
|
||||||
|
// contains the instances of the bottom-level acceleration structures. In our
|
||||||
|
// shader, we will trace rays against the top-level acceleration
|
||||||
|
// structure.
|
||||||
|
let blas = unsafe {
|
||||||
|
build_acceleration_structure_triangles(
|
||||||
|
&mesh,
|
||||||
|
memory_allocator.clone(),
|
||||||
|
command_buffer_allocator.clone(),
|
||||||
|
device.clone(),
|
||||||
|
graphics_queue.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let tlas = unsafe {
|
||||||
|
build_top_level_acceleration_structure(
|
||||||
|
vec![AccelerationStructureInstance {
|
||||||
|
instance_shader_binding_table_record_offset_and_flags: Packed24_8::new(
|
||||||
|
0,
|
||||||
|
GeometryInstanceFlags::TRIANGLE_FACING_CULL_DISABLE.into(),
|
||||||
|
),
|
||||||
|
acceleration_structure_reference: blas.device_address().into(),
|
||||||
|
..Default::default()
|
||||||
|
}],
|
||||||
|
memory_allocator.clone(),
|
||||||
|
command_buffer_allocator.clone(),
|
||||||
|
device.clone(),
|
||||||
|
graphics_queue.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Scene { _blas: blas, tlas }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper function to build a acceleration structure and wait for its
|
||||||
|
/// completion.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If you are referencing a bottom-level acceleration structure in a
|
||||||
|
/// top-level acceleration structure, you must ensure that the bottom-level
|
||||||
|
/// acceleration structure is kept alive.
|
||||||
|
unsafe fn build_acceleration_structure_common(
|
||||||
|
geometries: AccelerationStructureGeometries,
|
||||||
|
primitive_count: u32,
|
||||||
|
ty: AccelerationStructureType,
|
||||||
|
memory_allocator: Arc<dyn MemoryAllocator>,
|
||||||
|
command_buffer_allocator: Arc<dyn CommandBufferAllocator>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
) -> Arc<AccelerationStructure> {
|
||||||
|
let min_acceleration_structure_scratch_offset_alignment = device
|
||||||
|
.physical_device()
|
||||||
|
.properties()
|
||||||
|
.min_acceleration_structure_scratch_offset_alignment
|
||||||
|
.unwrap_or(1);
|
||||||
|
|
||||||
|
let mut as_build_geometry_info = AccelerationStructureBuildGeometryInfo {
|
||||||
|
mode: BuildAccelerationStructureMode::Build,
|
||||||
|
flags: BuildAccelerationStructureFlags::PREFER_FAST_TRACE,
|
||||||
|
..AccelerationStructureBuildGeometryInfo::new(geometries)
|
||||||
|
};
|
||||||
|
|
||||||
|
let as_build_sizes_info = device
|
||||||
|
.acceleration_structure_build_sizes(
|
||||||
|
AccelerationStructureBuildType::Device,
|
||||||
|
&as_build_geometry_info,
|
||||||
|
&[primitive_count],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// We create a new scratch buffer for each acceleration structure for
|
||||||
|
// simplicity. You may want to reuse scratch buffers if you need to build
|
||||||
|
// many acceleration structures.
|
||||||
|
let scratch_buffer = Subbuffer::<[u8]>::new(
|
||||||
|
Buffer::new(
|
||||||
|
memory_allocator.clone(),
|
||||||
|
BufferCreateInfo {
|
||||||
|
usage: BufferUsage::SHADER_DEVICE_ADDRESS | BufferUsage::STORAGE_BUFFER,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AllocationCreateInfo::default(),
|
||||||
|
DeviceLayout::from_size_alignment(
|
||||||
|
as_build_sizes_info.build_scratch_size,
|
||||||
|
min_acceleration_structure_scratch_offset_alignment as u64,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let as_create_info = AccelerationStructureCreateInfo {
|
||||||
|
ty,
|
||||||
|
..AccelerationStructureCreateInfo::new(
|
||||||
|
Buffer::new_slice::<u8>(
|
||||||
|
memory_allocator,
|
||||||
|
BufferCreateInfo {
|
||||||
|
usage: BufferUsage::ACCELERATION_STRUCTURE_STORAGE
|
||||||
|
| BufferUsage::SHADER_DEVICE_ADDRESS,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AllocationCreateInfo::default(),
|
||||||
|
as_build_sizes_info.acceleration_structure_size,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let acceleration = unsafe { AccelerationStructure::new(device, as_create_info) }.unwrap();
|
||||||
|
|
||||||
|
as_build_geometry_info.dst_acceleration_structure = Some(acceleration.clone());
|
||||||
|
as_build_geometry_info.scratch_data = Some(scratch_buffer);
|
||||||
|
|
||||||
|
let as_build_range_info = AccelerationStructureBuildRangeInfo {
|
||||||
|
primitive_count,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// For simplicity, we build a single command buffer that builds the acceleration
|
||||||
|
// structure, then waits for its execution to complete.
|
||||||
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
|
command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
builder
|
||||||
|
.build_acceleration_structure(
|
||||||
|
as_build_geometry_info,
|
||||||
|
iter::once(as_build_range_info).collect(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
builder
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.execute(queue)
|
||||||
|
.unwrap()
|
||||||
|
.then_signal_fence_and_flush()
|
||||||
|
.unwrap()
|
||||||
|
.wait(None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
acceleration
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn build_acceleration_structure_triangles(
|
||||||
|
mesh: &Mesh,
|
||||||
|
memory_allocator: Arc<dyn MemoryAllocator>,
|
||||||
|
command_buffer_allocator: Arc<dyn CommandBufferAllocator>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
) -> Arc<AccelerationStructure> {
|
||||||
|
let primitive_count = (mesh.vertices.len() / 3) as u32;
|
||||||
|
let as_geometry_triangles_data = AccelerationStructureGeometryTrianglesData {
|
||||||
|
max_vertex: mesh.vertices.len() as _,
|
||||||
|
vertex_data: Some(mesh.vertices.clone().into_bytes()),
|
||||||
|
vertex_stride: size_of::<OVertex>() as _,
|
||||||
|
index_data: Some(IndexBuffer::U32(mesh.indices.clone())),
|
||||||
|
..AccelerationStructureGeometryTrianglesData::new(Format::R32G32B32_SFLOAT)
|
||||||
|
};
|
||||||
|
|
||||||
|
let geometries = AccelerationStructureGeometries::Triangles(vec![as_geometry_triangles_data]);
|
||||||
|
|
||||||
|
build_acceleration_structure_common(
|
||||||
|
geometries,
|
||||||
|
primitive_count,
|
||||||
|
AccelerationStructureType::BottomLevel,
|
||||||
|
memory_allocator,
|
||||||
|
command_buffer_allocator,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn build_top_level_acceleration_structure(
|
||||||
|
as_instances: Vec<AccelerationStructureInstance>,
|
||||||
|
allocator: Arc<dyn MemoryAllocator>,
|
||||||
|
command_buffer_allocator: Arc<dyn CommandBufferAllocator>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
) -> Arc<AccelerationStructure> {
|
||||||
|
let primitive_count = as_instances.len() as u32;
|
||||||
|
|
||||||
|
let instance_buffer = Buffer::from_iter(
|
||||||
|
allocator.clone(),
|
||||||
|
BufferCreateInfo {
|
||||||
|
usage: BufferUsage::SHADER_DEVICE_ADDRESS
|
||||||
|
| BufferUsage::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AllocationCreateInfo {
|
||||||
|
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||||
|
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
as_instances,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let as_geometry_instances_data = AccelerationStructureGeometryInstancesData::new(
|
||||||
|
AccelerationStructureGeometryInstancesDataType::Values(Some(instance_buffer)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let geometries = AccelerationStructureGeometries::Instances(as_geometry_instances_data);
|
||||||
|
|
||||||
|
build_acceleration_structure_common(
|
||||||
|
geometries,
|
||||||
|
primitive_count,
|
||||||
|
AccelerationStructureType::TopLevel,
|
||||||
|
allocator,
|
||||||
|
command_buffer_allocator,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -29,6 +29,8 @@ layout(set = 0, binding = 0) uniform Lights {
|
|||||||
layout(set = 0, binding = 1) uniform Camera {
|
layout(set = 0, binding = 1) uniform Camera {
|
||||||
mat4 proj_view;
|
mat4 proj_view;
|
||||||
mat4 inv_proj_view;
|
mat4 inv_proj_view;
|
||||||
|
mat4 inv_proj;
|
||||||
|
mat4 inv_view;
|
||||||
vec4 campos_and_time;
|
vec4 campos_and_time;
|
||||||
|
|
||||||
float specular;
|
float specular;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#version 460
|
||||||
|
#extension GL_EXT_ray_tracing : require
|
||||||
|
#extension GL_GOOGLE_include_directive:require
|
||||||
|
#include "include.glsl"
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadInEXT vec3 hit_value;
|
||||||
|
hitAttributeEXT vec2 attribs;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
|
||||||
|
hit_value = barycentrics;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#version 460
|
||||||
|
#extension GL_EXT_ray_tracing : require
|
||||||
|
#extension GL_GOOGLE_include_directive:require
|
||||||
|
#include "include.glsl"
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadEXT vec3 hit_value;
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform accelerationStructureEXT top_level_as;
|
||||||
|
layout(set = 2, binding = 0, rgba32f) uniform image2D image;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const vec2 pixel_center = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
|
||||||
|
const vec2 in_uv = pixel_center / vec2(gl_LaunchSizeEXT.xy);
|
||||||
|
vec2 d = in_uv * 2.0 - 1.0;
|
||||||
|
|
||||||
|
vec4 origin = camera_uniforms.inv_view * vec4(0, 0, 0, 1);
|
||||||
|
vec4 target = camera_uniforms.inv_proj * vec4(d.x, d.y, 1, 1);
|
||||||
|
vec4 direction = camera_uniforms.inv_view * vec4(normalize(target.xyz), 0);
|
||||||
|
|
||||||
|
uint ray_flags = gl_RayFlagsOpaqueEXT;
|
||||||
|
float t_min = 0.001;
|
||||||
|
float t_max = 10000.0;
|
||||||
|
|
||||||
|
traceRayEXT(
|
||||||
|
top_level_as, // acceleration structure
|
||||||
|
ray_flags, // rayFlags
|
||||||
|
0xFF, // cullMask
|
||||||
|
0, // sbtRecordOffset
|
||||||
|
0, // sbtRecordStride
|
||||||
|
0, // missIndex
|
||||||
|
origin.xyz, // ray origin
|
||||||
|
t_min, // ray min range
|
||||||
|
direction.xyz, // ray direction
|
||||||
|
t_max, // ray max range
|
||||||
|
0); // payload (location = 0)
|
||||||
|
|
||||||
|
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hit_value, 1.0));
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#version 460
|
||||||
|
#extension GL_EXT_ray_tracing : require
|
||||||
|
#extension GL_GOOGLE_include_directive:require
|
||||||
|
#include "include.glsl"
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadInEXT vec3 hit_value;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
hit_value = vec3(0.0, 0.0, 0.2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user