scene module + better trait/generic relationships

This commit is contained in:
mars 2022-05-11 09:30:01 -06:00
parent 31e336f4ef
commit 7e855f5a46
8 changed files with 210 additions and 173 deletions

View File

@ -3,9 +3,9 @@ use std::f32::consts::LN_2;
use std::time::Instant;
use winit::event::{ElementState, VirtualKeyCode};
pub trait Camera {
fn get_eye(&self) -> [f32; 4];
fn get_vp(&self) -> [[f32; 4]; 4];
pub struct Camera {
pub eye: [f32; 4],
pub vp: [[f32; 4]; 4],
}
#[derive(Debug)]
@ -209,14 +209,19 @@ impl Flycam {
fn get_orientation(&self) -> glam::Quat {
Quat::from_euler(glam::EulerRot::YXZ, self.euler_y, self.euler_x, 0.0)
}
}
impl Camera for Flycam {
fn get_eye(&self) -> [f32; 4] {
pub fn get_camera(&self) -> Camera {
Camera {
eye: self.get_eye(),
vp: self.get_vp()
}
}
pub fn get_eye(&self) -> [f32; 4] {
self.position.extend(0.0).to_array()
}
fn get_vp(&self) -> [[f32; 4]; 4] {
pub fn get_vp(&self) -> [[f32; 4]; 4] {
// view matrix is inverted camera pose (world space to camera space)
let rotation = Mat4::from_quat(self.get_orientation().inverse());
let translation = Mat4::from_translation(-self.position);

View File

@ -1,13 +1,14 @@
//! Cyborg is a high-performance, modern, experimental rendering engine written
//! in Rust.
use parking_lot::Mutex;
use rayon::prelude::*;
use std::sync::Arc;
use parking_lot::Mutex;
pub mod camera;
pub mod pass;
pub mod phase;
pub mod scene;
pub mod shader;
pub mod staging;
pub mod storage;
@ -16,7 +17,7 @@ pub mod viewport;
use camera::Camera;
use pass::*;
use phase::*;
use viewport::ViewportImage;
use viewport::Viewport;
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
@ -26,10 +27,10 @@ pub struct ViewportUniform {
}
impl ViewportUniform {
pub fn from_camera(camera: &impl Camera) -> Self {
pub fn from_camera(camera: &Camera) -> Self {
Self {
eye: camera.get_eye(),
vp: camera.get_vp(),
eye: camera.eye,
vp: camera.vp,
}
}
}
@ -160,21 +161,16 @@ impl Renderer {
&self.layouts
}
pub fn add_pass<T: 'static + RenderPass>(&mut self, pass: T) {
let pass = Arc::new(pass);
self.add_pass_arc(pass);
pub fn get_frames_in_flight(&self) -> usize {
self.frames_in_flight
}
pub fn add_pass_arc<T: 'static + RenderPass>(&mut self, pass: Arc<T>) {
let pass = RenderPassBox::new(pass, self.frames_in_flight);
self.add_pass_box(pass);
}
pub fn add_pass_box(&mut self, pass: Box<dyn RenderPassBoxTrait>) {
self.render_passes.push(pass);
}
pub fn render<'a>(&mut self, target: &impl ViewportImage<'a>, camera: &impl Camera) {
pub fn render<'a>(
&mut self,
passes: &mut [&mut dyn RenderPassBoxTrait],
target: &dyn Viewport,
camera: &Camera,
) {
self.frame_index += 1;
if self.frame_index >= self.frame_datas.len() {
self.frame_index = 0;
@ -193,7 +189,7 @@ impl Renderer {
let phase_passes = multimap::MultiMap::<Phase, usize>::new();
let phase_passes = std::sync::Mutex::new(phase_passes);
self.render_passes
passes
.par_iter_mut()
.enumerate()
.for_each(|(pass_index, rp)| {
@ -219,7 +215,7 @@ impl Renderer {
if let Some(upload) = phase_passes.get_vec(&Phase::Upload) {
upload.iter().for_each(|pass_index| {
let phase_data = frame_data.make_phase_data(Phase::Upload, &viewport);
let pass = &self.render_passes[*pass_index];
let pass = &passes[*pass_index];
pass.record_commands(phase_data, &mut encoder);
});
}
@ -231,17 +227,17 @@ impl Renderer {
skinning.iter().for_each(|pass_index| {
let phase_data = frame_data.make_phase_data(Phase::Skinning, &viewport);
let pass = &self.render_passes[*pass_index];
let pass = &passes[*pass_index];
pass.record_compute(phase_data, &mut cmds);
})
}
let record_render = |phase| {
let cmds = Mutex::new(Vec::new());
if let Some(passes) = phase_passes.get_vec(&phase) {
passes.par_iter().for_each(|pass_index| {
if let Some(phase_passes) = phase_passes.get_vec(&phase) {
phase_passes.par_iter().for_each(|pass_index| {
let phase_data = frame_data.make_phase_data(phase, &viewport);
let pass = &self.render_passes[*pass_index];
let pass = &passes[*pass_index];
if let Some(cmd) = pass.record_render(phase_data) {
cmds.lock().push(cmd);

View File

@ -1,4 +1,5 @@
use cyborg::shader;
use cyborg::storage::mesh::*;
use cyborg::{pass, viewport::*, Renderer};
use std::sync::Arc;
use winit::{
@ -13,7 +14,7 @@ fn main() {
let mut viewport = pollster::block_on(WinitViewport::from_window(&window));
let mut renderer = Renderer::new(viewport.device.clone(), viewport.queue.clone());
let mut camera = cyborg::camera::Flycam::new(0.002, 10.0, 0.25);
let mut flycam = cyborg::camera::Flycam::new(0.002, 10.0, 0.25);
let mut is_grabbed = false;
let device = renderer.get_device();
@ -43,31 +44,85 @@ fn main() {
let debug_pass =
pass::debug::DebugPass::new(device.to_owned(), layouts.to_owned(), viewport.get_info());
renderer.add_pass(mesh_pass);
renderer.add_pass(debug_pass);
let example_vertices = vec![
pass::mesh::Vertex {
position: [-0.5, 0.5, 0.0],
tan_frame: 0,
},
pass::mesh::Vertex {
position: [0.5, 0.5, 0.0],
tan_frame: 0,
},
pass::mesh::Vertex {
position: [0.0, -0.5, 0.0],
tan_frame: 0,
},
];
let example_vertices = AttrBuffer {
id: mesh_pass.get_vertex_attr_id(),
count: example_vertices.len(),
data: bytemuck::cast_slice(&example_vertices).to_vec(),
};
let example_indices = vec![0u32, 1u32, 2u32];
let example_indices = AttrBuffer {
id: mesh_pass.get_index_attr_id(),
count: example_indices.len(),
data: bytemuck::cast_slice(&example_indices).to_vec(),
};
let mut example_mesh = MeshBuffer::default();
example_mesh.attributes.push(example_vertices);
example_mesh.attributes.push(example_indices);
let example_mesh = mesh_pass.get_mesh_pool().load(example_mesh).unwrap();
let meshes = mesh_pass.get_meshes().to_owned();
let r = 8;
let mut meshes_lock = meshes.write();
for x in -r..r {
for y in -r..r {
for z in -r..r {
let translation = glam::Vec3::new(x as f32, y as f32, z as f32);
let transform = glam::Mat4::from_translation(translation);
meshes_lock.transformed.push(cyborg::scene::TransformedMesh {
transform,
mesh: example_mesh.clone(),
});
}
}
}
drop(meshes_lock);
let frames_in_flight = renderer.get_frames_in_flight();
let mut mesh_pass = pass::RenderPassBox::new(Arc::new(mesh_pass), frames_in_flight);
let mut debug_pass = pass::RenderPassBox::new(Arc::new(debug_pass), frames_in_flight);
event_loop.run(move |event, _, control_flow| match event {
Event::RedrawRequested(_) => {
println!("camera: {:#?}", camera);
match viewport.acquire() {
Err(wgpu::SurfaceError::Lost) => viewport.resize(viewport.size),
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
Err(e) => eprintln!("error: {:?}", e),
Ok(target) => {
renderer.render(&target, &camera);
target.present();
Ok(_) => {
let mut passes: Vec<&mut dyn pass::RenderPassBoxTrait> = Vec::new();
passes.push(&mut mesh_pass);
passes.push(&mut debug_pass);
renderer.render(passes.as_mut_slice(), &viewport, &flycam.get_camera());
viewport.present();
}
}
}
Event::MainEventsCleared => {
shader_watcher.watch();
camera.update();
flycam.update();
window.request_redraw();
}
Event::DeviceEvent { ref event, .. } => match event {
DeviceEvent::MouseMotion { delta } => {
if is_grabbed {
camera.process_mouse(delta.0, delta.1);
flycam.process_mouse(delta.0, delta.1);
}
}
_ => {}
@ -92,7 +147,7 @@ fn main() {
is_grabbed = false;
}
} else {
camera.process_keyboard(*key, *state);
flycam.process_keyboard(*key, *state);
}
}
WindowEvent::MouseInput {

View File

@ -97,17 +97,23 @@ impl<T: 'static + RenderPass> RenderPassBox<T> {
///
/// Calls to [RenderPassBoxTrait] functions with frame indices greater
/// than or equal to `frame_num` are out-of-bounds and will panic.
pub fn new(render_pass: Arc<T>, frame_num: usize) -> Box<dyn RenderPassBoxTrait> {
pub fn new(render_pass: Arc<T>, frame_num: usize) -> Self {
let frame_data = {
(0..frame_num)
.map(|_| render_pass.create_frame_data())
.collect()
};
Box::new(Self {
Self {
render_pass,
frame_data,
})
}
}
/// Same as [Self::new], but creates a boxed [RenderPassBoxTrait] in a
/// generic-friendly interface.
pub fn new_boxed(render_pass: Arc<T>, frame_num: usize) -> Box<dyn RenderPassBoxTrait> {
Box::new(Self::new(render_pass, frame_num))
}
}

View File

@ -2,28 +2,7 @@ use super::*;
use crate::storage::GpuVec;
use crate::viewport::ViewportInfo;
use crate::RenderLayouts;
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex {
pub position: [f32; 3],
pub color: [f32; 3],
}
const VERTEX_ATTRS: &[wgpu::VertexAttribute] =
&wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3];
impl Vertex {
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: VERTEX_ATTRS,
}
}
}
pub type Index = u32;
use crate::scene::{DebugVertex as Vertex, DebugIndex as Index};
pub struct FrameData {
vertices: GpuVec<Vertex>,

View File

@ -1,10 +1,12 @@
use super::*;
use crate::scene;
use crate::shader::{ShaderHandle, ShaderStore};
use crate::storage::mesh::*;
use crate::storage::GpuVec;
use crate::viewport::ViewportInfo;
use crate::RenderLayouts;
#[derive(Clone)]
pub struct ShaderInfo {
pub store: Arc<ShaderStore>,
pub forward: ShaderHandle,
@ -66,11 +68,6 @@ struct MeshGroupCommands {
meshes: Vec<MeshCommand>,
}
pub struct MeshInstance {
pub transform: glam::Mat4,
pub mesh: MeshHandle,
}
pub struct FrameData {
skinned_vertices: GpuVec<Vertex>,
skinning_uniforms: GpuVec<SkinningUniform>,
@ -86,13 +83,12 @@ pub struct MeshPass {
vertex_attr_id: AttrId,
index_attr_id: AttrId,
mesh_layout_id: MeshLayoutId,
example_mesh: MeshHandle,
skinning_bind_group_layout: wgpu::BindGroupLayout,
skinning_pipeline: wgpu::ComputePipeline,
depth_pipeline: wgpu::RenderPipeline,
opaque_pipeline: wgpu::RenderPipeline,
target_info: ViewportInfo,
instances: Vec<MeshInstance>,
meshes: scene::MeshesHandle,
}
impl MeshPass {
@ -119,54 +115,6 @@ impl MeshPass {
mesh_layout.insert(index_attr_id, ());
let mesh_layout_id = mesh_pool.add_layout(mesh_layout).unwrap();
let example_vertices = vec![
Vertex {
position: [-0.5, 0.5, 0.0],
tan_frame: 0,
},
Vertex {
position: [0.5, 0.5, 0.0],
tan_frame: 0,
},
Vertex {
position: [0.0, -0.5, 0.0],
tan_frame: 0,
},
];
let example_vertices = AttrBuffer {
id: vertex_attr_id,
count: example_vertices.len(),
data: bytemuck::cast_slice(&example_vertices).to_vec(),
};
let example_indices = vec![0u32, 1u32, 2u32];
let example_indices = AttrBuffer {
id: index_attr_id,
count: example_indices.len(),
data: bytemuck::cast_slice(&example_indices).to_vec(),
};
let mut example_mesh = MeshBuffer::default();
example_mesh.attributes.push(example_vertices);
example_mesh.attributes.push(example_indices);
let example_mesh = mesh_pool.load(example_mesh).unwrap();
let mut instances = Vec::new();
let r = 4;
for x in -r..r {
for y in -r..r {
for z in -r..r {
let translation = glam::Vec3::new(x as f32, y as f32, z as f32);
let transform = glam::Mat4::from_translation(translation);
instances.push(MeshInstance {
transform,
mesh: example_mesh.clone(),
});
}
}
}
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("MeshPass Pipeline Layout"),
@ -297,15 +245,30 @@ impl MeshPass {
index_attr_id,
vertex_attr_id,
mesh_layout_id,
example_mesh,
skinning_bind_group_layout,
skinning_pipeline,
depth_pipeline,
opaque_pipeline,
target_info,
instances,
meshes: Default::default(),
}
}
pub fn get_mesh_pool(&self) -> &MeshPool {
&self.mesh_pool
}
pub fn get_vertex_attr_id(&self) -> AttrId {
self.vertex_attr_id
}
pub fn get_index_attr_id(&self) -> AttrId {
self.index_attr_id
}
pub fn get_meshes(&self) -> &scene::MeshesHandle {
&self.meshes
}
}
impl RenderPass for MeshPass {
@ -343,9 +306,12 @@ impl RenderPass for MeshPass {
data.groups.clear();
data.skinning_uniforms.clear();
let meshes_read = self.meshes.read();
let mesh_bindings = self
.mesh_pool
.iter_meshes(self.mesh_layout_id, self.instances.iter(), |i| &i.mesh)
.iter_meshes(self.mesh_layout_id, meshes_read.transformed.iter(), |i| {
&i.mesh
})
.unwrap();
let mut skinned_cursor = 0;
@ -468,8 +434,6 @@ impl RenderPass for MeshPass {
}
fn record_render(&self, data: PhaseData<&FrameData>) -> Option<wgpu::RenderBundle> {
println!("MeshPass::record_render(phase: {:?})", data.phase);
let pipeline = match data.phase {
Phase::Depth => &self.depth_pipeline,
Phase::Opaque => &self.opaque_pipeline,
@ -491,7 +455,7 @@ impl RenderPass for MeshPass {
});
// yikes
let mesh_bindings: Vec<(MeshLayoutBindings, &Vec<MeshCommand>)> = data
let mesh_bindings: Vec<_> = data
.frame_data
.groups
.iter()

54
src/scene.rs Normal file
View File

@ -0,0 +1,54 @@
//! Traits for describing Cyborg's scene representation.
//!
//! TODO this will all need to be replaced in favor of a way to represent
//! querying component and resource data framework-agnostically
use crate::storage::mesh::MeshHandle;
use parking_lot::RwLock;
use std::sync::Arc;
pub struct TransformedMesh {
pub transform: glam::Mat4,
pub mesh: MeshHandle,
}
#[derive(Default)]
pub struct Meshes {
pub transformed: Vec<TransformedMesh>,
}
pub type MeshesHandle = Arc<RwLock<Meshes>>;
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct DebugVertex {
pub position: [f32; 3],
pub color: [f32; 3],
}
pub const DEBUG_VERTEX_ATTRS: &[wgpu::VertexAttribute] =
&wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3];
impl DebugVertex {
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: DEBUG_VERTEX_ATTRS,
}
}
}
pub type DebugIndex = u32;
pub struct DebugDraw {
pub vertices: Vec<DebugVertex>,
pub indices: Vec<DebugIndex>,
}
#[derive(Default)]
pub struct DebugDraws {
pub draws: Vec<DebugDraw>,
}
pub type DebugDrawsHandle = Arc<RwLock<DebugDraws>>;

View File

@ -14,12 +14,6 @@ pub struct ViewportViews<'a> {
pub trait Viewport {
fn get_info(&self) -> ViewportInfo;
fn get_queue(&self) -> &wgpu::Queue;
}
pub trait ViewportImage<'a> {
type Viewport: Viewport;
fn get_viewport(&self) -> &Self::Viewport;
fn get_views(&self) -> ViewportViews;
}
@ -27,11 +21,13 @@ pub struct WinitViewport {
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
pub size: winit::dpi::PhysicalSize<u32>,
pub surface: wgpu::Surface,
pub config: wgpu::SurfaceConfiguration,
pub info: ViewportInfo,
pub depth_texture: wgpu::Texture,
pub depth_texture_view: wgpu::TextureView,
surface: wgpu::Surface,
config: wgpu::SurfaceConfiguration,
info: ViewportInfo,
depth_texture: wgpu::Texture,
depth_texture_view: wgpu::TextureView,
surface_texture: Option<wgpu::SurfaceTexture>,
output_view: Option<wgpu::TextureView>,
}
impl WinitViewport {
@ -88,22 +84,18 @@ impl WinitViewport {
info,
depth_texture,
depth_texture_view,
surface_texture: None,
output_view: None,
}
}
pub fn acquire(&mut self) -> Result<WinitImage, wgpu::SurfaceError> {
pub fn acquire(&mut self) -> Result<(), wgpu::SurfaceError> {
let surface_texture = self.surface.get_current_texture()?;
let output_view = surface_texture
self.output_view = Some(surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let depth_view = &self.depth_texture_view;
Ok(WinitImage {
viewport: self,
surface_texture,
output_view,
depth_view,
})
.create_view(&wgpu::TextureViewDescriptor::default()));
self.surface_texture = Some(surface_texture);
Ok(())
}
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
@ -119,6 +111,12 @@ impl WinitViewport {
}
}
pub fn present(&mut self) {
if let Some(surface_texture) = self.surface_texture.take() {
surface_texture.present();
}
}
fn make_depth_texture(
device: &wgpu::Device,
config: &wgpu::SurfaceConfiguration,
@ -151,32 +149,12 @@ impl Viewport for WinitViewport {
fn get_queue(&self) -> &wgpu::Queue {
&self.queue
}
}
pub struct WinitImage<'a> {
viewport: &'a WinitViewport,
surface_texture: wgpu::SurfaceTexture,
output_view: wgpu::TextureView,
depth_view: &'a wgpu::TextureView,
}
impl<'a> WinitImage<'a> {
pub fn present(self) {
self.surface_texture.present();
}
}
impl<'a> ViewportImage<'a> for WinitImage<'a> {
type Viewport = WinitViewport;
fn get_viewport(&self) -> &WinitViewport {
self.viewport
}
fn get_views(&self) -> ViewportViews {
ViewportViews {
output: &self.output_view,
depth: self.depth_view,
let output = self.output_view.as_ref().unwrap();
ViewportViews {
output,
depth: &self.depth_texture_view
}
}
}