Skip to content

Commit

Permalink
porting over more gltf tests
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed Dec 8, 2023
1 parent 8078c32 commit 30aad19
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 46 deletions.
3 changes: 3 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ previous tests. Mainly because of little things I had forgotten. Little bits of
state that need to be updated to run the shaders. The most recent was that the
size of the atlas needs to be updated on the GPU when the atlas changes.

I'm moving over tests from `renderling/scene/gltf_support.rs` to
`renderling/stage/gltf_support.rs` one at a time.

## Thu Dec 7, 2023

Ongoing work to get GLTF files on-the-slab working. When this work is done GLTF
Expand Down
17 changes: 9 additions & 8 deletions crates/renderling-shader/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ impl<T> Copy for Array<T> {}

impl<T> core::fmt::Debug for Array<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(if self.is_null() {
"Array (null)"
if self.is_null() {
f.write_fmt(format_args!("Array<{}>(null)", core::any::type_name::<T>()))
} else {
"Array"
})
.field("index", &self.index)
.field("len", &self.len)
.field("_phantom", &self._phantom)
.finish()
f.write_fmt(format_args!(
"Array<{}>({}, {})",
core::any::type_name::<T>(),
self.index,
self.len
))
}
}
}

Expand Down
9 changes: 5 additions & 4 deletions crates/renderling-shader/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ impl<T> Default for Id<T> {

impl<T> core::fmt::Debug for Id<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Id")
.field("type", &core::any::type_name::<T>())
.field("index", &self.0)
.finish()
f.write_fmt(format_args!(
"Id<{}>({})",
&core::any::type_name::<T>(),
&self.0
))
}
}

Expand Down
9 changes: 7 additions & 2 deletions crates/renderling/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use snafu::prelude::*;
use std::{ops::Deref, sync::Arc};

use crate::{
hdr::HdrSurface, CreateSurfaceFn, Graph, RenderTarget, Scene, SceneBuilder, TextureError,
UiDrawObject, UiScene, UiSceneBuilder, View, ViewMut, WgpuStateError,
hdr::HdrSurface, CreateSurfaceFn, Graph, RenderTarget, Scene, SceneBuilder, Stage,
TextureError, UiDrawObject, UiScene, UiSceneBuilder, View, ViewMut, WgpuStateError,
};

#[derive(Debug, Snafu)]
Expand Down Expand Up @@ -400,6 +400,11 @@ impl Renderling {
self.graph.get_resource().unwrap().unwrap()
}

pub fn new_stage(&self) -> Stage {
let (device, queue) = self.get_device_and_queue_owned();
Stage::new(device, queue)
}

pub fn new_scene(&self) -> SceneBuilder {
let (device, queue) = self.get_device_and_queue_owned();
SceneBuilder::new(device.0, queue.0)
Expand Down
31 changes: 0 additions & 31 deletions crates/renderling/src/scene/gltf_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1206,37 +1206,6 @@ mod test {

use crate::{camera, shader::pbr::PbrMaterial, LightingModel, RenderGraphConfig, Renderling};

#[test]
fn simple_texture() {
let size = 100;
let mut r =
Renderling::headless(size, size).with_background_color(Vec3::splat(0.0).extend(1.0));
let mut builder = r.new_scene();
let _loader = builder
.gltf_load("../../gltf/gltfTutorial_013_SimpleTexture.gltf")
.unwrap();

let projection = camera::perspective(size as f32, size as f32);
let view = camera::look_at(Vec3::new(0.5, 0.5, 1.25), Vec3::new(0.5, 0.5, 0.0), Vec3::Y);
builder.set_camera(projection, view);

// there are no lights in the scene and the material isn't marked as "unlit", so
// let's force it to be unlit.
let mut material = builder.materials.get(0).copied().unwrap();
material.lighting_model = LightingModel::NO_LIGHTING;
builder.materials[0] = material;

let scene = builder.build().unwrap();
r.setup_render_graph(RenderGraphConfig {
scene: Some(scene),
with_screen_capture: true,
..Default::default()
});

let img = r.render_image().unwrap();
img_diff::assert_img_eq("gltf_simple_texture.png", img);
}

#[test]
fn normal_mapping_brick_sphere() {
let size = 600;
Expand Down
129 changes: 128 additions & 1 deletion crates/renderling/src/stage/gltf_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use snafu::{OptionExt, ResultExt, Snafu};

#[derive(Debug, Snafu)]
pub enum StageGltfError {
#[snafu(display("{source}"))]
Gltf { source: gltf::Error },

#[snafu(display("{source}"))]
Atlas { source: crate::atlas::AtlasError },

Expand Down Expand Up @@ -42,6 +45,9 @@ pub enum StageGltfError {
#[snafu(display("Missing sampler"))]
MissingSampler,

#[snafu(display("Missing gltf camera at index {index}"))]
MissingCamera { index: usize },

#[snafu(display("{source}"))]
Slab { source: crate::slab::SlabError },
}
Expand All @@ -52,6 +58,12 @@ impl From<crate::slab::SlabError> for StageGltfError {
}
}

impl From<gltf::Error> for StageGltfError {
fn from(source: gltf::Error) -> Self {
Self::Gltf { source }
}
}

pub fn get_vertex_count(primitive: &gltf::Primitive<'_>) -> u32 {
if let Some(indices) = primitive.indices() {
let count = indices.count() as u32;
Expand Down Expand Up @@ -109,6 +121,15 @@ pub fn make_accessor(accessor: gltf::Accessor<'_>, buffers: &Array<GltfBuffer>)
}

impl Stage {
pub fn load_gltf_document_from_path(
&self,
path: impl AsRef<std::path::Path>,
) -> Result<(gltf::Document, GltfDocument), StageGltfError> {
let (document, buffers, images) = gltf::import(path)?;
let gpu_doc = self.load_gltf_document(&document, buffers, images)?;
Ok((document, gpu_doc))
}

pub fn load_gltf_document(
&self,
document: &gltf::Document,
Expand Down Expand Up @@ -527,10 +548,17 @@ impl Stage {
Some(data.0.as_slice())
});
let indices = get_indices(buffer_data, primitive, indices);
let uvs: Vec<Vec2> = reader
let mut uvs: Vec<Vec2> = reader
.read_tex_coords(0)
.map(|coords| coords.into_f32().map(Vec2::from).collect::<Vec<_>>())
.unwrap_or_else(|| vec![Vec2::ZERO; indices.len()]);
if uvs.len() != indices.len() {
let mut new_uvs = Vec::with_capacity(indices.len());
for index in indices {
new_uvs.push(uvs[*index as usize]);
}
uvs = new_uvs;
}
*uv_vec = Some(uvs);
}
// UNWRAP: safe because we just set it to `Some`
Expand Down Expand Up @@ -913,6 +941,56 @@ impl Stage {
})
}

/// Create a native camera for the gltf camera with the given index.
pub fn create_camera_from_gltf(
&self,
cpu_doc: &gltf::Document,
index: usize,
) -> Result<Camera, StageGltfError> {
let gltf_camera = cpu_doc
.cameras()
.nth(index)
.context(MissingCameraSnafu { index })?;
let projection = match gltf_camera.projection() {
gltf::camera::Projection::Orthographic(o) => glam::Mat4::orthographic_rh(
-o.xmag(),
o.xmag(),
-o.ymag(),
o.ymag(),
o.znear(),
o.zfar(),
),
gltf::camera::Projection::Perspective(p) => {
let fovy = p.yfov();
let aspect = p.aspect_ratio().unwrap_or(1.0);
if let Some(zfar) = p.zfar() {
glam::Mat4::perspective_rh(fovy, aspect, p.znear(), zfar)
} else {
glam::Mat4::perspective_infinite_rh(
p.yfov(),
p.aspect_ratio().unwrap_or(1.0),
p.znear(),
)
}
}
};
let view = cpu_doc
.nodes()
.find_map(|node| {
if node.camera().map(|c| c.index()) == Some(index) {
Some(glam::Mat4::from_cols_array_2d(&node.transform().matrix()).inverse())
} else {
None
}
})
.unwrap_or_default();
Ok(Camera {
projection,
view,
..Default::default()
})
}

// For now we have to keep the original document around to figure out
// what to draw.
fn draw_gltf_node_with<'a>(
Expand Down Expand Up @@ -1305,4 +1383,53 @@ mod test {
let img = r.render_image().unwrap();
img_diff::assert_img_eq("gltf_images.png", img);
}

#[test]
fn simple_texture() {
let size = 100;
let mut r =
Renderling::headless(size, size).with_background_color(Vec3::splat(0.0).extend(1.0));
let (device, queue) = r.get_device_and_queue_owned();
let stage = Stage::new(device.clone(), queue.clone())
// There are no lights in the scene and the material isn't marked as "unlit", so
// let's force it to be unlit.
.with_lighting(false);
stage.configure_graph(&mut r, true);
let (cpu_doc, gpu_doc) = stage
.load_gltf_document_from_path("../../gltf/gltfTutorial_013_SimpleTexture.gltf")
.unwrap();

let position = Vec3::new(0.5, 0.5, 1.25);
let projection = crate::camera::perspective(size as f32, size as f32);
let view = crate::camera::look_at(position, Vec3::new(0.5, 0.5, 0.0), Vec3::Y);
let camera = stage.append(&Camera {
projection,
view,
position,
});
let _unit_ids = stage.draw_gltf_scene(&gpu_doc, camera, cpu_doc.default_scene().unwrap());

let img = r.render_image().unwrap();
img_diff::assert_img_eq("gltf_simple_texture.png", img);
}

#[test]
fn normal_mapping_brick_sphere() {
let size = 600;
let mut r =
Renderling::headless(size, size).with_background_color(Vec3::splat(1.0).extend(1.0));
let stage = r.new_stage();
stage.configure_graph(&mut r, true);
let (cpu_doc, gpu_doc) = stage
.load_gltf_document_from_path("../../gltf/red_brick_03_1k.glb")
.unwrap();
let camera = stage.create_camera_from_gltf(&cpu_doc, 0).unwrap();
let camera_id = stage.append(&camera);
let _unit_ids =
stage.draw_gltf_scene(&gpu_doc, camera_id, cpu_doc.default_scene().unwrap());

let img = r.render_image().unwrap();
println!("saving frame");
img_diff::assert_img_eq("gltf_normal_mapping_brick_sphere.png", img);
}
}

0 comments on commit 30aad19

Please sign in to comment.