Skip to content

Commit

Permalink
examples: make intersection shader into sdf
Browse files Browse the repository at this point in the history
Use storage buffer for AABBs.
Make procedural geometry using ray marching for a signed distance
function.
  • Loading branch information
bwrsandman committed Apr 28, 2020
1 parent 255018d commit ebe867f
Showing 1 changed file with 148 additions and 11 deletions.
159 changes: 148 additions & 11 deletions examples/src/bin/nv-ray-tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;

use std::sync::Arc;
use std::time::Instant;

fn main() {
let required_extensions = vulkano_win::required_extensions();
Expand Down Expand Up @@ -68,6 +69,7 @@ fn main() {
khr_swapchain: true,
khr_get_memory_requirements2: true,
nv_ray_tracing: true,
khr_storage_buffer_storage_class: true,
..DeviceExtensions::none()
};
let (device, mut queues) = Device::new(
Expand Down Expand Up @@ -133,7 +135,10 @@ fn main() {
]
.iter()
.cloned(),
BufferUsage::ray_tracing(),
BufferUsage {
storage_buffer: true,
..BufferUsage::none()
},
queue.clone(),
)
.unwrap()
Expand All @@ -153,7 +158,13 @@ fn main() {
layout(set = 0, binding = 0, rgba8) uniform image2D result;
layout(set = 0, binding = 1) uniform accelerationStructureNV scene;
layout(location = 0) rayPayloadNV vec4 payload;
struct payload_t {
vec3 color;
uint recursion_depth;
};
layout(location = 0) rayPayloadNV payload_t payload;
void main() {
ivec2 coord = ivec2(gl_LaunchIDNV);
Expand All @@ -167,8 +178,9 @@ void main() {
vec3 origin = vec3(0.0, 0.0, 0.0);
vec3 direction = normalize(lower_left_corner + inUV.x * horizontal + inUV.y * vertical);
payload.recursion_depth = 0;
traceNV(scene, gl_RayFlagsOpaqueNV, 0xFF, 0, 0, 0, origin, 0.001, direction, 1000.0, 0);
imageStore(result, coord, payload);
imageStore(result, coord, vec4(payload.color, 1.0));
}
"
}
Expand All @@ -181,12 +193,17 @@ void main() {
src: "#version 460 core
#extension GL_NV_ray_tracing : enable
layout(location = 0) rayPayloadInNV vec4 payload;
struct payload_t {
vec3 color;
uint recursion_depth;
};
layout(location = 0) rayPayloadInNV payload_t payload;
void main() {
vec3 unit_direction = normalize(gl_WorldRayDirectionNV);
float t = 0.5 * (unit_direction.y + 1.0);
payload = vec4(mix(vec3(0.5, 0.7, 1.0), vec3(1.0, 1.0, 1.0), t), 1.0f);
payload.color = mix(vec3(0.5, 0.7, 1.0), vec3(1.0, 1.0, 1.0), t);
}
"
}
Expand All @@ -199,10 +216,29 @@ void main() {
src: "#version 460 core
#extension GL_NV_ray_tracing : enable
layout(location = 0) rayPayloadInNV vec4 payload;
layout(set = 0, binding = 1) uniform accelerationStructureNV scene;
struct payload_t {
vec3 color;
uint recursion_depth;
};
layout(location = 0) rayPayloadInNV payload_t payload;
struct hit_record_t {
vec3 position;
vec3 normal;
};
hitAttributeNV hit_record_t hit_record;
void main() {
payload = vec4(1, 1, 0, 1);
payload.recursion_depth++;
if (payload.recursion_depth < 15) {
vec3 target = reflect(gl_WorldRayDirectionNV, hit_record.normal);
vec3 origin = hit_record.position + 0.001 * hit_record.normal;
traceNV(scene, gl_RayFlagsOpaqueNV, 0xFF, 0, 0, 0, origin, 0.001, target, 1000.0, 0);
payload.color *= 0.9f;
}
}
"
}
Expand All @@ -215,18 +251,109 @@ void main() {
src: "#version 460 core
#extension GL_NV_ray_tracing : enable
hitAttributeNV bool _unused_but_required;
struct Aabb {
float min_x;
float min_y;
float min_z;
float max_x;
float max_y;
float max_z;
};
layout(set = 0, binding = 2) readonly buffer AabbArray { Aabb[] aabbs; };
layout(push_constant) uniform PushConstants {
float time;
} push_constants;
struct hit_record_t {
vec3 position;
vec3 normal;
};
hitAttributeNV hit_record_t hit_record;
const uint MAX_STEPS = 100;
const uint MAX_REFINE_STEPS = 4;
const float MIN_DISTANCE = 1e-6f;
const float MIN_STEP_SIZE = 0.5f;
float CUBE_SIDES = 0.45f;
float SPHERE_RADIUS = 0.55f;
float GRAD_STEP = 0.01f;
float sphere_sdf(vec3 point, float radius) {
return length(point) - radius;
}
float box_sdf(vec3 point, vec3 sides) {
vec3 q = abs(point) - sides;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
vec3 twist_point(vec3 point, float amount) {
float c = cos(amount * point.y);
float s = sin(amount * point.y);
mat2 m = mat2(c, -s, s, c);
return vec3(m * point.xz, point.y);
}
float signed_distance_function(vec3 point, vec3 size) {
vec3 twisted = twist_point(point, sin(push_constants.time) * (2 * gl_PrimitiveID - 1));
return max(box_sdf(twisted, size * CUBE_SIDES), -sphere_sdf(point, min(size.x, min(size.y, size.z)) * SPHERE_RADIUS));
}
void main() {
reportIntersectionNV(0.01, 0);
vec3 aabb_min = vec3(aabbs[gl_PrimitiveID].min_x, aabbs[gl_PrimitiveID].min_y, aabbs[gl_PrimitiveID].min_z);
vec3 aabb_max = vec3(aabbs[gl_PrimitiveID].max_x, aabbs[gl_PrimitiveID].max_y, aabbs[gl_PrimitiveID].max_z);
vec3 center = (aabb_min + aabb_max) * 0.5;
vec3 size = aabb_max - aabb_min;
float t = gl_RayTminNV; // TODO: start stepping at bounding box
float t_max = gl_RayTmaxNV; // TODO: stop stepping when out of the bb
float distance = gl_RayTmaxNV;
float step_size = 0.0f;
// Ray march
for (uint i = 0; i < MAX_STEPS; ++i) {
distance = signed_distance_function(gl_ObjectRayOriginNV + gl_ObjectRayDirectionNV * t - center, size);
// Ray has marched close enough to object, register a hit here
if (distance < MIN_DISTANCE) {
break;
}
// Not close enough, step forward
step_size = min(abs(distance), MIN_STEP_SIZE);
t += step_size;
// Ray has marched too far without any hits, register no hits
if (t > t_max) {
break;
}
}
// Ray has hit something
if (distance < MIN_DISTANCE) {
// refine the value for t by stepping back and taking smaller steps
t -= step_size;
for (uint i = 0; i < MAX_REFINE_STEPS; ++i) {
step_size *= 0.5;
distance = signed_distance_function(gl_ObjectRayOriginNV + gl_ObjectRayDirectionNV * t - center, size);
if (distance >= MIN_DISTANCE) {
t += step_size;
}
}
vec3 dx = vec3(GRAD_STEP, 0.0, 0.0);
vec3 dy = vec3(0.0, GRAD_STEP, 0.0);
vec3 dz = vec3(0.0, 0.0, GRAD_STEP);
hit_record.position = gl_ObjectRayOriginNV + gl_ObjectRayDirectionNV * t - center;
hit_record.normal = normalize(vec3(signed_distance_function(hit_record.position + dx, size) - signed_distance_function(hit_record.position - dx, size),
signed_distance_function(hit_record.position + dy, size) - signed_distance_function(hit_record.position - dy, size),
signed_distance_function(hit_record.position + dz, size) - signed_distance_function(hit_record.position - dz, size)));
reportIntersectionNV(t, 0);
}
}
"
}
}
let is = is::Shader::load(device.clone()).unwrap();

// We set a limit to the recursion of a ray so that the shader does not run infinitely
let max_recursion_depth = 5;
let max_recursion_depth = 15;

let pipeline = Arc::new(
RayTracingPipeline::nv(max_recursion_depth)
Expand Down Expand Up @@ -260,6 +387,8 @@ void main() {
.unwrap()
.add_acceleration_structure(acceleration_structure.clone())
.unwrap()
.add_buffer(aabb_buffer.clone())
.unwrap()
.build()
.unwrap(),
)
Expand Down Expand Up @@ -313,6 +442,7 @@ void main() {
let mut recreate_swapchain = false;
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);

let time_start = Instant::now();
event_loop.run(move |event, _, control_flow| match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
Expand Down Expand Up @@ -349,6 +479,8 @@ void main() {
.unwrap()
.add_acceleration_structure(acceleration_structure.clone())
.unwrap()
.add_buffer(aabb_buffer.clone())
.unwrap()
.build()
.unwrap(),
)
Expand Down Expand Up @@ -384,7 +516,12 @@ void main() {
callable_shader_binding_table.clone(),
[swapchain.dimensions()[0], swapchain.dimensions()[1], 1],
sets[image_num].clone(),
(),
is::ty::PushConstants {
time: {
let elapsed = time_start.elapsed();
elapsed.as_secs() as f32 + elapsed.subsec_nanos() as f32 / 1e9
},
},
)
.unwrap()
.build()
Expand Down

0 comments on commit ebe867f

Please sign in to comment.