Skip to content

Commit

Permalink
WIP drawing gltf nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed Dec 2, 2023
1 parent c8121d4 commit 75f7cd0
Show file tree
Hide file tree
Showing 11 changed files with 440 additions and 53 deletions.
93 changes: 92 additions & 1 deletion crates/renderling-shader/src/gltf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
//! Gltf types that are used in shaders.
use glam::Vec4;

use crate::{
self as renderling_shader, array::Array, id::Id, pbr::PbrMaterial, slab::Slabbed,
self as renderling_shader,
array::Array,
id::Id,
pbr::PbrMaterial,
slab::{Slab, Slabbed},
texture::GpuTexture,
};
#[repr(transparent)]
Expand Down Expand Up @@ -118,8 +124,47 @@ pub struct GltfAccessor {
pub normalized: bool,
}

impl GltfAccessor {
pub fn get_scalar_u32(&self, index: usize, slab: &[u32]) -> u32 {
let byte_offset = self.view_offset + index as u32 * self.view_stride;
let u32_offset = byte_offset / 4;
let mut scalar = 0u32;
let _ = scalar.read_slab(u32_offset as usize, slab);
scalar
}

pub fn get_vec4(&self, vertex_index: usize, slab: &[u32]) -> glam::Vec4 {
let byte_offset = self.view_offset as usize + vertex_index * self.view_stride as usize;
let u32_offset = byte_offset / 4;
let mut vec4 = glam::Vec4::ZERO;
match self.dimensions {
Dimensions::Scalar => {
vec4.x.read_slab(u32_offset + 0, slab);
}
Dimensions::Vec2 => {
vec4.x.read_slab(u32_offset + 0, slab);
vec4.y.read_slab(u32_offset + 1, slab);
}
Dimensions::Vec3 => {
vec4.x.read_slab(u32_offset + 0, slab);
vec4.y.read_slab(u32_offset + 1, slab);
vec4.z.read_slab(u32_offset + 2, slab);
}
Dimensions::Vec4 => {
vec4.x.read_slab(u32_offset + 0, slab);
vec4.y.read_slab(u32_offset + 1, slab);
vec4.z.read_slab(u32_offset + 2, slab);
vec4.w.read_slab(u32_offset + 3, slab);
}
_ => {}
}
vec4
}
}

#[derive(Default, Clone, Copy, Slabbed)]
pub struct GltfPrimitive {
pub vertex_count: u32,
pub material: Id<PbrMaterial>,
pub indices: Id<GltfAccessor>,
pub positions: Id<GltfAccessor>,
Expand All @@ -132,6 +177,52 @@ pub struct GltfPrimitive {
pub weights: Id<GltfAccessor>,
}

impl GltfPrimitive {
pub fn get_vertex(&self, index: usize, slab: &[u32]) -> crate::stage::Vertex {
let index = if self.indices.is_some() {
let indices = slab.read(self.indices);
let index = indices.get_scalar_u32(index, slab);
index as usize
} else {
index
};
let positions = slab.read(self.positions);
let position = positions.get_vec4(index, slab);
let normals = slab.read(self.normals);
let normal = normals.get_vec4(index, slab);
// TODO: If tangents are not present, calculate them.
let tangents = slab.read(self.tangents);
let tangent = tangents.get_vec4(index, slab);
let colors = slab.read(self.colors);
let color = colors.get_vec4(index, slab);
let tex_coords0 = slab.read(self.tex_coords0);
let tex_coords0 = tex_coords0.get_vec4(index, slab);
let tex_coords1 = slab.read(self.tex_coords1);
let tex_coords1 = tex_coords1.get_vec4(index, slab);
let uv = Vec4::new(tex_coords0.x, tex_coords0.y, tex_coords1.x, tex_coords1.y);
let joints = slab.read(self.joints);
let joints = joints.get_vec4(index, slab);
let joints = [
joints.x.to_bits(),
joints.y.to_bits(),
joints.z.to_bits(),
joints.w.to_bits(),
];
let weights = slab.read(self.weights);
let weights = weights.get_vec4(index, slab);
let weights = [weights.x, weights.y, weights.z, weights.w];
crate::stage::Vertex {
position,
color,
uv,
normal,
tangent,
joints,
weights,
}
}
}

#[derive(Default, Clone, Copy, Slabbed)]
pub struct GltfMesh {
pub primitives: Array<GltfPrimitive>,
Expand Down
149 changes: 129 additions & 20 deletions crates/renderling-shader/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
array::Array,
bits::{bits, extract, insert},
debug::*,
gltf::{GltfMesh, GltfNode},
id::{Id, ID_NONE},
pbr::{self, PbrMaterial},
slab::{Slab, Slabbed},
Expand Down Expand Up @@ -891,37 +892,145 @@ pub struct StageLegend {
pub light_array: Array<GpuLight>,
}

/// A fully-computed unit of rendering, roughly meaning a mesh with model matrix
/// transformations.
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Slabbed)]
pub struct RenderUnit {
#[derive(Default, Clone, Copy, PartialEq, Slabbed)]
pub struct NativeVertexData {
// Points to an array of `Vertex` in the stage's slab.
pub vertices: Array<Vertex>,
// Points to a `PbrMaterial` in the stage's slab.
pub material: Id<PbrMaterial>,
// Points to a `Camera` in the stage's slab.
pub camera: Id<Camera>,
}

pub position: Vec3,
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[repr(C)]
#[derive(Default, Clone, Copy, PartialEq, Slabbed)]
pub struct GltfVertexData {
// A path of node ids that leads to the node that contains the mesh.
pub parent_node_path: Array<Id<GltfNode>>,
// Points to a `GltfMesh` in the stage's slab.
pub mesh: Id<GltfMesh>,
// The index of the primitive within the mesh that this unit draws.
pub primitive_index: u32,
}

#[repr(u32)]
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[derive(Clone, Copy, PartialEq)]
pub enum VertexData {
Native(Id<NativeVertexData>),
Gltf(Id<GltfVertexData>),
}

impl Default for VertexData {
fn default() -> Self {
VertexData::Native(Id::NONE)
}
}

impl Slabbed for VertexData {
fn slab_size() -> usize {
2
}

fn read_slab(&mut self, index: usize, slab: &[u32]) -> usize {
let mut proxy = 0u32;
let index = proxy.read_slab(index, slab);
match proxy {
0 => {
let mut native = Id::default();
let index = native.read_slab(index, slab);
*self = Self::Native(native);
index
}
1 => {
let mut gltf = Id::default();
let index = gltf.read_slab(index, slab);
*self = Self::Gltf(gltf);
index
}
_ => index,
}
}

fn write_slab(&self, index: usize, slab: &mut [u32]) -> usize {
match self {
Self::Native(native) => {
let index = 0u32.write_slab(index, slab);
native.write_slab(index, slab)
}
Self::Gltf(gltf) => {
let index = 1u32.write_slab(index, slab);
gltf.write_slab(index, slab)
}
}
}
}

#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Slabbed)]
pub struct Transform {
pub translation: Vec3,
pub rotation: Quat,
pub scale: Vec3,
}

impl Default for RenderUnit {
impl Default for Transform {
fn default() -> Self {
Self {
vertices: Default::default(),
material: Default::default(),
camera: Default::default(),
position: Vec3::ZERO,
translation: Vec3::ZERO,
rotation: Quat::IDENTITY,
scale: Vec3::ONE,
}
}
}

/// A fully-computed unit of rendering, roughly meaning a mesh with model matrix
/// transformations.
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[repr(C)]
#[derive(Default, Clone, Copy, PartialEq, Slabbed)]
pub struct RenderUnit {
pub vertex_data: VertexData,
// Points to a `Camera` in the stage's slab.
pub camera: Id<Camera>,
// Points to a `Transform` in the stage's slab.
pub transform: Id<Transform>,
// Number of vertices to draw for this unit.
pub vertex_count: u32,
}

impl RenderUnit {
pub fn get_vertex_details(
&self,
vertex_index: u32,
slab: &[u32],
) -> (Vertex, Transform, Id<PbrMaterial>) {
let transform = slab.read(self.transform);
match self.vertex_data {
VertexData::Native(id) => {
let NativeVertexData { vertices, material } = slab.read(id);
let vertex = slab.read(vertices.at(vertex_index as usize));
(vertex, transform, material)
}
VertexData::Gltf(id) => {
let GltfVertexData {
parent_node_path: _,
mesh,
primitive_index,
} = slab.read(id);
// TODO: check nodes for skinning
let mesh = slab.read(mesh);
let primitive = slab.read(mesh.primitives.at(primitive_index as usize));
let material = primitive.material;
let vertex = primitive.get_vertex(vertex_index as usize, slab);
(vertex, transform, material)
}
}
}
}

#[spirv(vertex)]
pub fn new_stage_vertex(
// Which render unit are we rendering
Expand All @@ -939,24 +1048,24 @@ pub fn new_stage_vertex(
out_bitangent: &mut Vec3,
// position of the vertex/fragment in world space
out_pos: &mut Vec3,
#[spirv(position)] gl_pos: &mut Vec4,
#[spirv(position)] clip_pos: &mut Vec4,
) {
let unit_id: Id<RenderUnit> = Id::from(instance_index);
let unit = slab.read(unit_id);
let vertex = slab.read(unit.vertices.at(vertex_index as usize));
let (vertex, tfrm, material) = unit.get_vertex_details(vertex_index, slab);
let model_matrix =
Mat4::from_scale_rotation_translation(unit.scale, unit.rotation, unit.position);
*out_material = unit.material.into();
Mat4::from_scale_rotation_translation(tfrm.scale, tfrm.rotation, tfrm.translation);
*out_material = material.into();
*out_color = vertex.color;
*out_uv0 = vertex.uv.xy();
*out_uv1 = vertex.uv.zw();
let scale2 = unit.scale * unit.scale;
let scale2 = tfrm.scale * tfrm.scale;
let normal = vertex.normal.xyz().alt_norm_or_zero();
let tangent = vertex.tangent.xyz().alt_norm_or_zero();
let normal_w = (model_matrix * (normal / scale2).extend(0.0))
let normal_w: Vec3 = (model_matrix * (normal / scale2).extend(0.0))
.xyz()
.alt_norm_or_zero();
let tangent_w = (model_matrix * tangent.extend(0.0))
let tangent_w: Vec3 = (model_matrix * tangent.extend(0.0))
.xyz()
.alt_norm_or_zero();
let bitangent_w = normal_w.cross(tangent_w) * if vertex.tangent.w >= 0.0 { 1.0 } else { -1.0 };
Expand All @@ -967,7 +1076,7 @@ pub fn new_stage_vertex(
*out_pos = view_pos.xyz();
let camera = slab.read(unit.camera);
*out_camera = unit.camera.into();
*gl_pos = camera.projection * camera.view * view_pos;
*clip_pos = camera.projection * camera.view * view_pos;
}

#[allow(clippy::too_many_arguments)]
Expand Down
5 changes: 2 additions & 3 deletions crates/renderling-shader/src/tutorial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,9 @@ pub fn slabbed_render_unit(
) {
let unit_id = Id::<RenderUnit>::from(instance_index);
let unit = slab.read(unit_id);
let vertex_id = unit.vertices.at(vertex_index as usize);
let vertex = slab.read(vertex_id);
let (vertex, tfrm, _) = unit.get_vertex_details(vertex_index, slab);
let camera = slab.read(unit.camera);
let model = Mat4::from_scale_rotation_translation(unit.scale, unit.rotation, unit.position);
let model = Mat4::from_scale_rotation_translation(tfrm.scale, tfrm.rotation, tfrm.translation);
*clip_pos = camera.projection * camera.view * model * vertex.position.xyz().extend(1.0);
*out_color = vertex.color;
}
Binary file modified crates/renderling/src/linkage/stage-new_stage_vertex.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/stage-stage_fragment.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv
Binary file not shown.
Binary file modified crates/renderling/src/linkage/tutorial-slabbed_vertices.spv
Binary file not shown.
34 changes: 34 additions & 0 deletions crates/renderling/src/slab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ impl SlabBuffer {

#[cfg(test)]
mod test {
use renderling_shader::stage::{NativeVertexData, RenderUnit, Vertex, VertexData};

use crate::Renderling;

use super::*;
Expand Down Expand Up @@ -426,4 +428,36 @@ mod test {
let points_out = slab_u32.read_vec::<glam::Vec3>(array);
assert_eq!(points, points_out);
}

#[test]
fn slab_buffer_unit_roundtrip() {
let _ = env_logger::builder().is_test(true).try_init();
let r = Renderling::headless(10, 10);
let device = r.get_device();
let queue = r.get_queue();
let slab = SlabBuffer::new(device, 2);
let vertices = vec![
Vertex::default().with_position([0.0, 0.0, 0.0]),
Vertex::default().with_position([1.0, 1.0, 1.0]),
Vertex::default().with_position([2.0, 2.0, 2.0]),
];
let vertices = slab.append_array(device, queue, &vertices);
let data_id = slab.append(
device,
queue,
&NativeVertexData {
vertices,
material: Id::new(666),
},
);
let unit = RenderUnit {
vertex_data: VertexData::Native(data_id),
camera: Id::new(42),
transform: Id::new(1337),
vertex_count: vertices.len() as u32,
};
let unit_id = slab.append(device, queue, &unit);
let t = futures_lite::future::block_on(slab.read(device, queue, unit_id)).unwrap();
assert_eq!(unit, t, "read back what we wrote");
}
}
Loading

0 comments on commit 75f7cd0

Please sign in to comment.