added vertex buffer

This commit is contained in:
Sven Vogel 2023-04-14 14:44:28 +02:00
parent dce8b57b0e
commit d26de46d92
9 changed files with 1588 additions and 43 deletions

2
res/cube.mtl Normal file
View File

@ -0,0 +1,2 @@
# Blender 3.5.0 MTL File: 'None'
# www.blender.org

25
res/cube.obj Normal file
View File

@ -0,0 +1,25 @@
# Blender 3.5.0
# www.blender.org
mtllib cube.mtl
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
s 0
f 2 3 1
f 4 7 3
f 8 5 7
f 6 1 5
f 7 1 3
f 4 6 8
f 2 4 3
f 4 8 7
f 8 6 5
f 6 2 1
f 7 5 1
f 4 2 6

2
res/sphere.mtl Normal file
View File

@ -0,0 +1,2 @@
# Blender 3.5.0 MTL File: 'None'
# www.blender.org

1447
res/sphere.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,21 +3,21 @@ use cgmath::prelude::*;
use cgmath::{Rad, Vector2, Vector3}; use cgmath::{Rad, Vector2, Vector3};
pub struct Camera { pub struct Camera {
front: Vector3<f32>, pub(crate) front: Vector3<f32>,
left: Vector3<f32>, pub(crate) left: Vector3<f32>,
up: Vector3<f32>, pub(crate) up: Vector3<f32>,
pos: Vector3<f32>, pub(crate) pos: Vector3<f32>,
fov: f32, pub(crate) fov: f32,
} }
impl Camera { impl Camera {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
front: Vector3::new(0.0, 0.0, 1.0), front: Vector3::new(0.0, 0.0, -1.0),
left: Vector3::new(1.0, 0.0, 0.0), left: Vector3::new(1.0, 0.0, 0.0),
up: Vector3::new(0.0, 1.0, 0.0), up: Vector3::new(0.0, -1.0, 0.0),
pos: Vector3::new(0.0, 0.0, -4.0), pos: Vector3::new(0.0, 0.0, 9.0),
fov: 90.0f32 fov: 90.0f32
} }
} }

View File

@ -16,6 +16,7 @@ use vulkano::memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemo
use vulkano::padded::Padded; use vulkano::padded::Padded;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}; use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
use vulkano::sync::GpuFuture; use vulkano::sync::GpuFuture;
use crate::shader::pathtracing::camera::Camera;
use crate::vulkan::Renderer; use crate::vulkan::Renderer;
pub(crate) mod cs { pub(crate) mod cs {
@ -36,8 +37,9 @@ pub struct PathtracerPipeline {
raw_image: Subbuffer<[[f32; 4]]>, raw_image: Subbuffer<[[f32; 4]]>,
seconds: Instant, seconds: Instant,
uniform_buffer: Arc<SubbufferAllocator>, uniform_buffer: Arc<SubbufferAllocator>,
vertex_buffer: Subbuffer<[[f32; 3]]>, vertex_buffer: Subbuffer<[[f32; 4]]>,
index_buffer: Subbuffer<[u32]>, index_buffer: Subbuffer<[u32]>,
camera: Camera
} }
impl PathtracerPipeline { impl PathtracerPipeline {
@ -79,7 +81,8 @@ impl PathtracerPipeline {
uniform_buffer: Arc::new(uniform_buffer), uniform_buffer: Arc::new(uniform_buffer),
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
seconds: Instant::now() seconds: Instant::now(),
camera: Camera::new()
}; };
} }
@ -118,13 +121,13 @@ impl PathtracerPipeline {
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer,Arc<StandardCommandBufferAllocator>> builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer,Arc<StandardCommandBufferAllocator>>
) { ) {
let camera = cs::Camera { let camera = cs::Camera {
front: Padded::from([0f32, 0f32, 1f32]), front: Padded::from(Into::<[f32; 3]>::into(self.camera.front)),
left: Padded::from([1f32, 0f32, 0f32]), left: Padded::from(Into::<[f32; 3]>::into(self.camera.left)),
up: Padded::from([0f32, 1f32, 0f32]), up: Padded::from(Into::<[f32; 3]>::into(self.camera.up)),
position: [0f32, 0f32, -12f32], position: Into::<[f32; 3]>::into(self.camera.pos),
fov: 90f32 fov: self.camera.fov,
}; };
let subbuffer = self.uniform_buffer.allocate_sized().unwrap(); let subbuffer = self.uniform_buffer.allocate_sized().unwrap();
@ -188,35 +191,33 @@ fn create_image(memory_allocator: &StandardMemoryAllocator, queue: &Arc<Queue>,
(raw_image, image) (raw_image, image)
} }
fn load_example_scene() -> (Vec<[f32; 3]>, Vec<u32>) { fn load_example_scene() -> (Vec<[f32; 4]>, Vec<u32>) {
let (mut models, materials) = tobj::load_obj("res/example-scene.obj", &tobj::GPU_LOAD_OPTIONS).expect("unable to load scene from obj"); let (mut models, materials) = tobj::load_obj("res/example-scene.obj", &tobj::GPU_LOAD_OPTIONS).expect("unable to load scene from obj");
let mut vertices:Vec<[f32; 3]> = Vec::new(); let mut vertices:Vec<[f32; 4]> = vec![];
let mut indices:Vec<u32> = Vec::new(); let mut indices:Vec<u32> = vec![];
for model in models.iter_mut() { for model in models.iter_mut() {
let num_triangles = model.mesh.positions.len() / 3; let offset = vertices.len() as u32;
for triangle_index in 0..num_triangles { for vertex_index in (0..model.mesh.positions.len()).step_by(3) {
let vertex_index = triangle_index * 3;
vertices.push([ vertices.push([
model.mesh.positions[vertex_index], model.mesh.positions[vertex_index],
model.mesh.positions[vertex_index + 1], model.mesh.positions[vertex_index + 1],
model.mesh.positions[vertex_index + 2] model.mesh.positions[vertex_index + 2],
0.0
]); ]);
} }
for index in model.mesh.indices.iter() { for index in model.mesh.indices.iter() {
indices.push(*index); indices.push(*index + offset);
} }
// model.mesh.indices.iter_mut().for_each(|i| indices.push(*i));
} }
(vertices, indices) (vertices, indices)
} }
fn create_gpu_buffer(vertices: &Vec<[f32; 3]>, indices: &Vec<u32>, memory_allocator: &StandardMemoryAllocator) -> (Subbuffer<[[f32; 3]]>, Subbuffer<[u32]>) { fn create_gpu_buffer(vertices: &Vec<[f32; 4]>, indices: &Vec<u32>, memory_allocator: &StandardMemoryAllocator) -> (Subbuffer<[[f32; 4]]>, Subbuffer<[u32]>) {
let vertex_buffer = Buffer::from_iter( let vertex_buffer = Buffer::from_iter(
memory_allocator, memory_allocator,
BufferCreateInfo { BufferCreateInfo {

View File

@ -25,6 +25,45 @@ uint get_pixel_index() {
return gl_GlobalInvocationID.y * uint(program_metadata.resolution.x) + gl_GlobalInvocationID.x; return gl_GlobalInvocationID.y * uint(program_metadata.resolution.x) + gl_GlobalInvocationID.x;
} }
vec3 project(in vec3 a, in vec3 b) {
return a * (dot(a, b) / dot(a, a));
}
void construct_orthonormal_basis(in vec3 up, out vec3 u, out vec3 v, out vec3 w) {
u = normalize(up);
vec3 n2 = vec3(1) - u;
vec3 n3 = vec3(1) - u.zxy;
vec3 w2 = normalize(n2 - (project(u, n2)));
vec3 w3 = normalize(n3 - project(u, n3) - project(w2, n3));
v = w2;
w = w3;
}
vec3 cosine_weighted_hemisphere() {
float u1 = random();
float u2 = random();
float r = sqrt(u1);
float theta = 2 * 3.1415926535 * u2;
float x = r * cos(theta);
float y = r * sin(theta);
return vec3(x, y, sqrt(1.0 - u1));
}
vec3 generate_diffuse_ray_direction(in vec3 nor) {
vec3 hemisphere = cosine_weighted_hemisphere();
vec3 u, v, w;
construct_orthonormal_basis(nor, u, v, w);
return normalize(u * hemisphere.x + v * hemisphere.y + w * hemisphere.z);
}
void main() { void main() {
init_random_state(floatBitsToInt(program_metadata.seconds)); init_random_state(floatBitsToInt(program_metadata.seconds));
@ -34,10 +73,20 @@ void main() {
vec3 color = vec3(0); vec3 color = vec3(0);
vec4 result = intersect_scene(camera_ray); Hit result = intersect_scene(camera_ray);
if (result.a == 1.0) { if (result.depth < camera_ray.far) {
color = vec3(result.y, result.z, 0); Ray ao;
ao.origin = camera_ray.origin + camera_ray.direction * result.depth;
ao.direction = generate_diffuse_ray_direction(result.nor);
ao.near = 1e-3;
ao.far = 1e3;
Hit r2 = intersect_scene(ao);
if (r2.depth > 1.0) {
color = vec3(1);
}
} }
// index of the current pixel as array index // index of the current pixel as array index

View File

@ -7,42 +7,54 @@ struct Ray {
float far; float far;
}; };
struct Hit {
vec3 nor;
vec2 uv;
float depth;
};
layout(set = 0, binding = 3) buffer VertexBuffer { layout(set = 0, binding = 3) buffer VertexBuffer {
vec3 vertices[]; vec4 vertices[];
}; };
layout(set = 0, binding = 4) buffer IndexBuffer { layout(set = 0, binding = 4) buffer IndexBuffer {
uint indices[]; uint indices[];
}; };
vec3 intersect_triangle(in Ray ray, in vec3 v0, in vec3 v1, in vec3 v2) { vec3 intersect_triangle(in Ray ray, in vec3 v0, in vec3 v1, in vec3 v2, out vec3 n) {
vec3 v1v0 = v1 - v0; vec3 v1v0 = v1 - v0;
vec3 v2v0 = v2 - v0; vec3 v2v0 = v2 - v0;
vec3 rov0 = ray.origin - v0; vec3 rov0 = ray.origin - v0;
vec3 n = cross(v1v0, v2v0); n = cross(v1v0, v2v0);
vec3 q = cross(rov0, ray.direction); vec3 q = cross(rov0, ray.direction);
float d = 1.0 / dot(ray.direction, n); float d = 1.0 / dot(ray.direction, n);
float u = d * dot( -q, v2v0); float u = d * dot( -q, v2v0);
float v = d * dot( q, v1v0); float v = d * dot( q, v1v0);
float t = d * dot( -n, rov0); float t = d * dot( -n, rov0);
t = min(u, min(v, min(1.0 - (u + v), t))); if(u < 0.0 || v < 0.0 || (u+v) > 1.0 || d > 0.0)
t = -1.0;
return vec3( t, u, v ); return vec3(t, u, v);
} }
vec4 intersect_scene(in Ray ray) { Hit intersect_scene(in Ray ray) {
vec4 hit = vec4(ray.far, -1, -1, 0); Hit hit;
hit.depth = ray.far;
for (int i = 0; i < indices.length(); i += 3) { for (int i = 0; i < indices.length(); i += 3) {
vec3 v0 = vertices[indices[i]]; vec3 v0 = vertices[indices[i]].xyz;
vec3 v1 = vertices[indices[i + 1]]; vec3 v1 = vertices[indices[i + 1]].xyz;
vec3 v2 = vertices[indices[i + 2]]; vec3 v2 = vertices[indices[i + 2]].xyz;
vec3 result = intersect_triangle(ray, v0, v1, v2); vec3 n;
vec3 result = intersect_triangle(ray, v0, v1, v2, n);
if (result.x > ray.near && result.x < hit.x) { if (result.x > ray.near && result.x < hit.depth) {
hit = vec4(result, 1); hit.uv = result.yz;
hit.depth = result.x;
hit.nor = n;
} }
} }

View File

@ -2,6 +2,7 @@ mod device;
pub(crate) mod textured_quad; pub(crate) mod textured_quad;
use std::sync::Arc; use std::sync::Arc;
use std::time::Instant;
use vulkano::device::{Device}; use vulkano::device::{Device};
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage}; use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, InstanceCreateInfo}; use vulkano::instance::{Instance, InstanceCreateInfo};
@ -17,7 +18,7 @@ use vulkano::image::view::ImageView;
use vulkano::pipeline::graphics::viewport::Viewport; use vulkano::pipeline::graphics::viewport::Viewport;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass}; use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass};
use vulkano::sync::{FlushError, GpuFuture}; use vulkano::sync::{FlushError, GpuFuture};
use winit::event::{Event, WindowEvent}; use winit::event::{Event, VirtualKeyCode, WindowEvent};
use crate::shader::composite::TextureDrawPipeline; use crate::shader::composite::TextureDrawPipeline;
use crate::shader::pathtracing::PathtracerPipeline; use crate::shader::pathtracing::PathtracerPipeline;
@ -133,6 +134,8 @@ pub fn init() {
let mut now_keys = [false; 255]; let mut now_keys = [false; 255];
let mut start_frame = Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
match event { match event {
Event::WindowEvent { Event::WindowEvent {
@ -172,6 +175,8 @@ pub fn init() {
} }
}, },
Event::RedrawEventsCleared => { Event::RedrawEventsCleared => {
let elapsed = (Instant::now() - start_frame).as_secs_f32();
// Do not draw the frame when the screen dimensions are zero. On Windows, this can // Do not draw the frame when the screen dimensions are zero. On Windows, this can
// occur when minimizing the application. // occur when minimizing the application.
let window = surface.object().unwrap().downcast_ref::<Window>().unwrap(); let window = surface.object().unwrap().downcast_ref::<Window>().unwrap();
@ -280,6 +285,8 @@ pub fn init() {
// previous_frame_end = Some(sync::now(device.clone()).boxed()); // previous_frame_end = Some(sync::now(device.clone()).boxed());
} }
} }
start_frame = Instant::now();
} }
_ => (), _ => (),
} }