Loading textures from gltf blob and gltf.bin's, fix loading multiple meshses in a single model
This commit is contained in:
parent
fd9f4bee2a
commit
7ae59c0415
|
@ -1294,6 +1294,7 @@ dependencies = [
|
|||
"tracing-appender",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
@ -1552,7 +1553,7 @@ checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
|
|||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.4.6",
|
||||
"rustc-serialize",
|
||||
]
|
||||
|
||||
|
@ -1867,6 +1868,12 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-easy"
|
||||
version = "0.3.0"
|
||||
|
@ -1934,6 +1941,27 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
|
@ -1949,6 +1977,15 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "range-alloc"
|
||||
version = "0.1.3"
|
||||
|
@ -2483,11 +2520,12 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -36,3 +36,4 @@ aligned-vec = "0.5.0"
|
|||
tracing-appender = "0.2.2"
|
||||
stopwatch = "0.0.7"
|
||||
petgraph = "0.6.4"
|
||||
uuid = { version = "1.5.0", features = ["v4", "fast-rng"] }
|
|
@ -1333,6 +1333,7 @@ dependencies = [
|
|||
"tracing-appender",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
@ -1581,7 +1582,7 @@ checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
|
|||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.4.6",
|
||||
"rustc-serialize",
|
||||
]
|
||||
|
||||
|
@ -1877,6 +1878,12 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-easy"
|
||||
version = "0.3.0"
|
||||
|
@ -1944,6 +1951,27 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
|
@ -1959,6 +1987,15 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "range-alloc"
|
||||
version = "0.1.3"
|
||||
|
@ -2508,11 +2545,12 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,137 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v3.6.6",
|
||||
"version":"2.0"
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"Cube"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"doubleSided":true,
|
||||
"name":"Material",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorTexture":{
|
||||
"index":0
|
||||
},
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"Cube",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"TEXCOORD_0":1,
|
||||
"NORMAL":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures":[
|
||||
{
|
||||
"sampler":0,
|
||||
"source":0
|
||||
}
|
||||
],
|
||||
"images":[
|
||||
{
|
||||
"mimeType":"image/png",
|
||||
"name":"uvgrid",
|
||||
"uri":"uvgrid.png"
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":36,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":288,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":480,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":72,
|
||||
"byteOffset":768,
|
||||
"target":34963
|
||||
}
|
||||
],
|
||||
"samplers":[
|
||||
{
|
||||
"magFilter":9729,
|
||||
"minFilter":9987
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":840,
|
||||
"uri":"texture-sep.bin"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
|
@ -75,35 +75,18 @@ async fn main() {
|
|||
|
||||
let mut resman = world.get_resource_mut::<ResourceManager>().unwrap();
|
||||
let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
|
||||
//let cube_model = resman.request::<Model>("assets/cube-embedded.gltf").unwrap();
|
||||
let cube_model = resman.request::<Model>("assets/cube-texture-embedded.gltf").unwrap();
|
||||
let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap();
|
||||
let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").unwrap();
|
||||
drop(resman);
|
||||
|
||||
/* world.spawn((MeshComponent::new(
|
||||
Mesh {
|
||||
vertices: VERTICES.to_vec(),
|
||||
indices: Some(INDICES.to_vec())
|
||||
}, Material {
|
||||
shader_id: 0,
|
||||
texture: diffuse_texture.clone()
|
||||
}),
|
||||
TransformComponent::from(Transform::from_xyz(0.005, 0.0, -2.0)),
|
||||
));
|
||||
|
||||
world.spawn((MeshComponent::new(
|
||||
Mesh {
|
||||
vertices: VERTICES.to_vec(),
|
||||
indices: Some(INDICES.to_vec())
|
||||
}, Material {
|
||||
shader_id: 0,
|
||||
texture: diffuse_texture
|
||||
}),
|
||||
TransformComponent::from(Transform::from_xyz(0.005, 0.7, -0.5)),
|
||||
/* world.spawn((
|
||||
ModelComponent(cube_model.clone()),
|
||||
TransformComponent::from(Transform::from_xyz(3.0, 0.5, -2.2)),
|
||||
)); */
|
||||
|
||||
world.spawn((
|
||||
ModelComponent(cube_model),
|
||||
TransformComponent::from(Transform::from_xyz(0.005, 0.5, -2.2)),
|
||||
ModelComponent(antique_camera_model),
|
||||
TransformComponent::from(Transform::from_xyz(0.0, -5.0, -10.0)),
|
||||
));
|
||||
|
||||
let mut camera = CameraComponent::new_3d();
|
||||
|
@ -115,7 +98,6 @@ async fn main() {
|
|||
Ok(())
|
||||
};
|
||||
|
||||
//world.insert_resource(fps_counter::FPSCounter::new());
|
||||
let fps_system = |world: &mut World| -> anyhow::Result<()> {
|
||||
let mut counter: RefMut<fps_counter::FPSCounter> = world.get_resource_mut().unwrap();
|
||||
|
||||
|
|
|
@ -27,6 +27,17 @@ impl From<ModelLoaderError> for LoaderError {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct GltfLoadContext<'a> {
|
||||
pub resource_manager: &'a mut ResourceManager,
|
||||
pub gltf: &'a gltf::Gltf,
|
||||
/// Path to the gltf
|
||||
pub gltf_path: &'a str,
|
||||
/// The path to the directory that the gltf is contained in.
|
||||
pub gltf_parent_path: &'a str,
|
||||
/// List of buffers in the gltf
|
||||
pub buffers: &'a Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ModelLoader;
|
||||
|
||||
|
@ -59,7 +70,10 @@ impl ModelLoader {
|
|||
|
||||
// read the positions
|
||||
if let Some(pos) = reader.read_positions() {
|
||||
debug!("Mesh mode is {:?}", prim.mode());
|
||||
if prim.mode() != gltf::mesh::Mode::Triangles {
|
||||
todo!("Load position primitives that aren't triangles"); // TODO
|
||||
}
|
||||
|
||||
let pos: Vec<glam::Vec3> = pos.map(|t| t.into()).collect();
|
||||
new_mesh.add_attribute(MeshVertexAttribute::Position, VertexAttributeData::Vec3(pos));
|
||||
}
|
||||
|
@ -114,7 +128,7 @@ impl ModelLoader {
|
|||
impl ResourceLoader for ModelLoader {
|
||||
fn extensions(&self) -> &[&str] {
|
||||
&[
|
||||
"gltf"
|
||||
"gltf", "glb"
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -132,11 +146,27 @@ impl ResourceLoader for ModelLoader {
|
|||
parent_path.pop();
|
||||
let parent_path = parent_path.display().to_string();
|
||||
|
||||
/* let (document, buffers, images) = gltf::import(&path)?;
|
||||
let buffers: Vec<Vec<u8>> = buffers.into_iter().map(|b| b.0).collect();
|
||||
|
||||
let scene = document.scenes().next().unwrap();
|
||||
|
||||
let materials: Vec<Material> = document.materials()
|
||||
.map(|mat| Material::from_gltf(resource_manager, &parent_path, mat)).collect();
|
||||
|
||||
let meshes: Vec<Mesh> = scene.nodes()
|
||||
.map(|node| self.process_node(&buffers, &materials, node))
|
||||
.flatten().collect(); */
|
||||
|
||||
let gltf = gltf::Gltf::open(path)?;
|
||||
|
||||
let mut use_bin = false;
|
||||
let buffers: Vec<Vec<u8>> = gltf.buffers().map(|b| match b.source() {
|
||||
gltf::buffer::Source::Bin => gltf.blob.as_deref().map(|v| v.to_vec())
|
||||
.ok_or(ModelLoaderError::MissingBin(path.to_string())),
|
||||
gltf::buffer::Source::Bin => {
|
||||
use_bin = true;
|
||||
gltf.blob.as_deref().map(|v| v.to_vec())
|
||||
.ok_or(ModelLoaderError::MissingBin(path.to_string()))
|
||||
},
|
||||
gltf::buffer::Source::Uri(uri) => util::gltf_read_buffer_uri(&parent_path, uri)
|
||||
.map_err(|e| ModelLoaderError::UriDecodingError(e)),
|
||||
}).flatten().collect();
|
||||
|
@ -144,13 +174,21 @@ impl ResourceLoader for ModelLoader {
|
|||
// TODO: Read in multiple scenes
|
||||
let scene = gltf.scenes().next().unwrap();
|
||||
|
||||
// Load the materials
|
||||
let mut context = GltfLoadContext {
|
||||
resource_manager,
|
||||
gltf: &gltf,
|
||||
gltf_path: path,
|
||||
gltf_parent_path: &parent_path,
|
||||
buffers: &buffers,
|
||||
};
|
||||
|
||||
let materials: Vec<Material> = gltf.materials()
|
||||
.map(|mat| Material::from_gltf(resource_manager, &parent_path, mat)).collect();
|
||||
.map(|mat| Material::from_gltf(&mut context, mat)).collect();
|
||||
|
||||
let meshes: Vec<Mesh> = scene.nodes()
|
||||
.map(|node| self.process_node(&buffers, &materials, node))
|
||||
.flatten().collect();
|
||||
debug!("Loaded {} meshes, and {} materials from '{}'", meshes.len(), materials.len(), path);
|
||||
|
||||
Ok(Arc::new(Resource::with_data(path, Model::new(meshes))))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{fs::File, io::{BufReader, Read}, collections::hash_map::DefaultHasher, hash::{Hash, Hasher}};
|
||||
|
||||
use crate::{Texture, ResHandle, ResourceManager, util};
|
||||
use crate::{Texture, ResHandle, ResourceManager, util, loader::model::GltfLoadContext};
|
||||
|
||||
/// PBR metallic roughness
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -159,10 +159,11 @@ impl Material {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_source(resource_manager: &mut ResourceManager, gltf_rel_path: &str, src: gltf::image::Source) -> Result<Vec<u8>, util::UriReadError> {
|
||||
fn read_source(context: &mut GltfLoadContext, src: gltf::image::Source) -> Result<Vec<u8>, util::UriReadError> {
|
||||
let gltf_rel_path = context.gltf_parent_path;
|
||||
// TODO: Don't copy sources
|
||||
match src {
|
||||
gltf::image::Source::View { view, mime_type } => {
|
||||
gltf::image::Source::View { view, mime_type: _ } => {
|
||||
let buf = view.buffer();
|
||||
let src = buf.source();
|
||||
|
||||
|
@ -170,7 +171,12 @@ impl Material {
|
|||
let len = view.length();
|
||||
|
||||
match src {
|
||||
gltf::buffer::Source::Bin => todo!("Read material source from gltf Bin"),
|
||||
gltf::buffer::Source::Bin => {
|
||||
let mut b = context.gltf.blob.clone().unwrap();
|
||||
b.drain(0..offset);
|
||||
b.truncate(len);
|
||||
Ok(b)
|
||||
},
|
||||
gltf::buffer::Source::Uri(uri) => {
|
||||
util::gltf_read_buffer_uri(gltf_rel_path, uri)
|
||||
.map(|mut buf| {
|
||||
|
@ -181,23 +187,23 @@ impl Material {
|
|||
}
|
||||
}
|
||||
},
|
||||
gltf::image::Source::Uri { uri, mime_type } => {
|
||||
gltf::image::Source::Uri { uri, mime_type: _ } => {
|
||||
util::gltf_read_buffer_uri(gltf_rel_path, uri)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn load_texture(resource_manager: &mut ResourceManager, gltf_rel_path: &str, texture_info: gltf::texture::Info<'_>) -> ResHandle<Texture> {
|
||||
fn load_texture(context: &mut GltfLoadContext, texture_info: gltf::texture::Info<'_>) -> ResHandle<Texture> {
|
||||
// TODO: texture_info.tex_coord()
|
||||
let tex = texture_info.texture();
|
||||
let img = tex.source();
|
||||
let src = img.source();
|
||||
|
||||
let buf = Material::read_source(resource_manager, gltf_rel_path, src).unwrap();
|
||||
let buf = Material::read_source(context, src).unwrap();
|
||||
let buflen = buf.len();
|
||||
let mime_type = infer::get(&buf).expect("Failed to get file type").mime_type();
|
||||
|
||||
resource_manager.load_bytes::<Texture>(&uuid::Uuid::new_v4().to_string(), mime_type,
|
||||
context.resource_manager.load_bytes::<Texture>(&uuid::Uuid::new_v4().to_string(), mime_type,
|
||||
buf, 0, buflen).unwrap()
|
||||
}
|
||||
|
||||
|
@ -205,21 +211,17 @@ impl Material {
|
|||
///
|
||||
/// `gltf_rel_path`: The relative path of the gltf file,
|
||||
/// e.g. gltf model path is "resource/models/player.gltf", the relative path would be "resource/models/"
|
||||
pub fn from_gltf(resource_manager: &mut ResourceManager, gltf_rel_path: &str, gltf_mat: gltf::Material) -> Self {
|
||||
pub(crate) fn from_gltf(context: &mut GltfLoadContext, gltf_mat: gltf::Material) -> Self {
|
||||
let pbr_rough = gltf_mat.pbr_metallic_roughness();
|
||||
let base_color = pbr_rough.base_color_factor().into();
|
||||
let metallic = pbr_rough.metallic_factor();
|
||||
let roughness = pbr_rough.roughness_factor();
|
||||
|
||||
let base_color_texture = pbr_rough.base_color_texture()
|
||||
.map(|info| Material::load_texture(resource_manager, gltf_rel_path, info));
|
||||
.map(|info| Material::load_texture(context, info));
|
||||
|
||||
let metallic_roughness_texture = pbr_rough.metallic_roughness_texture()
|
||||
.map(|info| Material::load_texture(resource_manager, gltf_rel_path, info));
|
||||
|
||||
/* let base_color_texture = if let Some(base_tex_info) = pbr_rough.base_color_texture() {
|
||||
Some(Material::load_texture(resource_manager, gltf_rel_path, base_tex_info))
|
||||
} else { None }; */
|
||||
.map(|info| Material::load_texture(context, info));
|
||||
|
||||
Material {
|
||||
name: gltf_mat.name()
|
||||
|
|
|
@ -77,13 +77,25 @@ pub enum MeshVertexAttribute {
|
|||
Other(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, edict::Component)]
|
||||
#[derive(Clone, edict::Component)]
|
||||
pub struct Mesh {
|
||||
pub uuid: uuid::Uuid,
|
||||
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
||||
pub indices: Option<MeshIndices>,
|
||||
material: Option<Material>,
|
||||
}
|
||||
|
||||
impl Default for Mesh {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
uuid: uuid::Uuid::new_v4(),
|
||||
attributes: Default::default(),
|
||||
indices: Default::default(),
|
||||
material: Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn add_attribute(&mut self, attribute: MeshVertexAttribute, data: VertexAttributeData) {
|
||||
self.attributes.insert(attribute, data);
|
||||
|
|
|
@ -19,20 +19,23 @@ pub enum UriReadError {
|
|||
///
|
||||
/// * `containing_path`: The path of the containing folder of the buffers "parent",
|
||||
/// the parent being where this buffer is defined in,
|
||||
/// i.e. parent="resources/models/player.gltf", containing="reousrce/models"
|
||||
/// i.e. parent="resources/models/player.gltf", containing="resource/models"
|
||||
pub(crate) fn gltf_read_buffer_uri(containing_path: &str, uri: &str) -> Result<Vec<u8>, UriReadError> {
|
||||
let uri = uri.strip_prefix("data").ok_or(UriReadError::None)?;
|
||||
let (mime, data) = uri.split_once(",").ok_or(UriReadError::None)?;
|
||||
|
||||
let (_mime, is_base64) = match mime.strip_suffix(";base64") {
|
||||
Some(mime) => (mime, true),
|
||||
None => (mime, false),
|
||||
};
|
||||
|
||||
if is_base64 {
|
||||
base64::engine::general_purpose::STANDARD.decode(data).map_err(|e| UriReadError::Base64Decode(e))
|
||||
if let Some((mime, data)) = uri.strip_prefix("data")
|
||||
.and_then(|uri| uri.split_once(",")) {
|
||||
let (_mime, is_base64) = match mime.strip_suffix(";base64") {
|
||||
Some(mime) => (mime, true),
|
||||
None => (mime, false),
|
||||
};
|
||||
|
||||
if is_base64 {
|
||||
base64::engine::general_purpose::STANDARD.decode(data)
|
||||
.map_err(|e| UriReadError::Base64Decode(e))
|
||||
} else {
|
||||
Ok(data.as_bytes().to_vec())
|
||||
}
|
||||
} else {
|
||||
let full_path = format!("{containing_path}/{data}");
|
||||
let full_path = format!("{containing_path}/{uri}");
|
||||
std::fs::read(&full_path).map_err(|e| UriReadError::IoError(e))
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 5.6 KiB |
|
@ -0,0 +1 @@
|
|||
nightly
|
|
@ -297,7 +297,7 @@ impl Game {
|
|||
.with(fmt::layer().with_writer(stdout_layer))
|
||||
.with(filter::Targets::new()
|
||||
.with_target("lyra_engine", Level::TRACE)
|
||||
.with_target("wgpu_core", Level::INFO)
|
||||
.with_target("wgpu_core", Level::WARN)
|
||||
.with_default(Level::DEBUG))
|
||||
.init();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![feature(hash_extract_if)]
|
||||
|
||||
pub mod game;
|
||||
pub mod render;
|
||||
pub mod input_event;
|
||||
|
|
|
@ -2,48 +2,23 @@ use edict::EntityId;
|
|||
|
||||
use crate::math::Transform;
|
||||
|
||||
//use super::mesh::Mesh;
|
||||
use lyra_resource::Mesh;
|
||||
|
||||
pub struct RenderJob {
|
||||
mesh: Mesh,
|
||||
entity: EntityId,
|
||||
pub entity: EntityId,
|
||||
pub shader_id: u64,
|
||||
pub mesh_buffer_id: uuid::Uuid,
|
||||
|
||||
transform: Transform,
|
||||
last_transform: Option<Transform>, // TODO: render interpolation
|
||||
pub transform: Transform,
|
||||
pub last_transform: Option<Transform>, // TODO: render interpolation
|
||||
}
|
||||
|
||||
impl RenderJob {
|
||||
pub fn new(mesh: Mesh, entity: EntityId, transform: Transform, last_transform: Option<Transform>) -> Self {
|
||||
pub fn new(entity: EntityId, shader_id: u64, mesh_buffer_id: uuid::Uuid, transform: Transform, last_transform: Option<Transform>) -> Self {
|
||||
Self {
|
||||
mesh,
|
||||
entity,
|
||||
shader_id,
|
||||
mesh_buffer_id,
|
||||
transform,
|
||||
last_transform,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mesh(&self)-> &Mesh {
|
||||
&self.mesh
|
||||
}
|
||||
|
||||
pub fn entity(&self)-> EntityId {
|
||||
self.entity
|
||||
}
|
||||
|
||||
pub fn transform(&self)-> &Transform {
|
||||
&self.transform
|
||||
}
|
||||
|
||||
pub fn set_transform(&mut self, transform: Transform){
|
||||
self.transform = transform;
|
||||
}
|
||||
|
||||
pub fn last_transform(&self)-> Option<&Transform> {
|
||||
self.last_transform.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_last_transform(&mut self, last_transform: Transform){
|
||||
self.last_transform = Some(last_transform);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ use crate::ecs::components::camera::CameraComponent;
|
|||
use crate::ecs::components::mesh::MeshComponent;
|
||||
use crate::ecs::components::model::ModelComponent;
|
||||
use crate::ecs::components::transform::TransformComponent;
|
||||
use crate::math::Transform;
|
||||
|
||||
use super::camera::RenderCamera;
|
||||
use super::desc_buf_lay::DescVertexBufferLayout;
|
||||
|
@ -68,13 +69,15 @@ struct TransformBuffers {
|
|||
|
||||
impl TransformBuffers {
|
||||
/// Update an entity's buffer with the new transform. Will panic if the entity isn't stored
|
||||
fn update_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4) {
|
||||
fn update_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4) -> TransformBufferIndices {
|
||||
let indices = self.not_updated.remove(&entity)
|
||||
.or_else(|| self.just_updated.remove(&entity))
|
||||
.expect("Use 'insert_entity' for new entities");
|
||||
self.just_updated.insert(entity, indices);
|
||||
|
||||
let (_, buffer, _) = self.buffer_bindgroups.get(indices.buffer_index).unwrap();
|
||||
queue.write_buffer(buffer, indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64, bytemuck::bytes_of(&transform));
|
||||
indices
|
||||
}
|
||||
|
||||
/// Insert a new entity into the buffer, returns where it was stored.
|
||||
|
@ -104,6 +107,22 @@ impl TransformBuffers {
|
|||
indices
|
||||
}
|
||||
|
||||
/// Update or insert an entities transform
|
||||
fn update_or_insert<TFn>(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform_fn: TFn) -> TransformBufferIndices
|
||||
where TFn: Fn() -> glam::Mat4
|
||||
{
|
||||
if self.contains(entity) {
|
||||
self.update_entity(queue, limits, entity, transform_fn())
|
||||
} else {
|
||||
self.insert_entity(queue, limits, entity, transform_fn())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the entity's transform is stored (does not mean its up-to-date).
|
||||
fn contains(&self, entity: EntityId) -> bool {
|
||||
self.not_updated.contains_key(&entity) || self.just_updated.contains_key(&entity)
|
||||
}
|
||||
|
||||
/// Collect the dead entities, mark entities and not updated for next updates.
|
||||
fn tick(&mut self) {
|
||||
// take the dead entities, these were ones that were not updated this tick
|
||||
|
@ -111,7 +130,6 @@ impl TransformBuffers {
|
|||
.map(|t| t.clone()).collect();
|
||||
self.dead_indices = dead;
|
||||
|
||||
// swap just_updated into not_updated
|
||||
self.not_updated = self.just_updated.clone();
|
||||
self.just_updated.clear();
|
||||
}
|
||||
|
@ -143,7 +161,8 @@ pub struct BasicRenderer {
|
|||
pub render_pipelines: HashMap<u64, Arc<FullRenderPipeline>>,
|
||||
pub render_jobs: VecDeque<RenderJob>,
|
||||
|
||||
buffer_storage: HashMap<EntityId, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
|
||||
mesh_buffers: HashMap<uuid::Uuid, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
|
||||
entity_meshes: HashMap<EntityId, uuid::Uuid>,
|
||||
|
||||
transform_buffers: TransformBuffers,
|
||||
transform_bind_group_layout: BindGroupLayout,
|
||||
|
@ -205,7 +224,7 @@ impl BasicRenderer {
|
|||
false => surface_caps.present_modes[0]
|
||||
}; */
|
||||
|
||||
println!("present mode: {:?}", present_mode);
|
||||
debug!("present mode: {:?}", present_mode);
|
||||
|
||||
let surface_format = surface_caps.formats.iter()
|
||||
.copied()
|
||||
|
@ -380,7 +399,8 @@ impl BasicRenderer {
|
|||
},
|
||||
render_pipelines: HashMap::new(),
|
||||
render_jobs: VecDeque::new(),
|
||||
buffer_storage: HashMap::new(),
|
||||
mesh_buffers: HashMap::new(),
|
||||
entity_meshes: HashMap::new(),
|
||||
|
||||
render_limits,
|
||||
transform_buffers,
|
||||
|
@ -405,17 +425,16 @@ impl BasicRenderer {
|
|||
s
|
||||
}
|
||||
|
||||
fn update_mesh_buffers(&mut self, entity: EntityId, mesh: &Mesh) {
|
||||
if let Some(buffers) = self.buffer_storage.get_mut(&entity) {
|
||||
fn update_mesh_buffers(&mut self, _entity: EntityId, mesh: &Mesh) {
|
||||
if let Some(buffers) = self.mesh_buffers.get_mut(&mesh.uuid) {
|
||||
// check if the buffer sizes dont match. If they dont, completely remake the buffers
|
||||
let vertices = mesh.position().unwrap();
|
||||
if buffers.buffer_vertex.count() != vertices.len() {
|
||||
drop(buffers);
|
||||
debug!("Recreating buffers for mesh");
|
||||
debug!("Recreating buffers for mesh {}", mesh.uuid.to_string());
|
||||
let (vert, idx) = self.create_vertex_index_buffers(mesh);
|
||||
|
||||
// have to re-get buffers because of borrow checker
|
||||
let buffers = self.buffer_storage.get_mut(&entity).unwrap();
|
||||
let buffers = self.mesh_buffers.get_mut(&mesh.uuid).unwrap();
|
||||
buffers.buffer_indices = idx;
|
||||
buffers.buffer_vertex = vert;
|
||||
|
||||
|
@ -448,13 +467,11 @@ impl BasicRenderer {
|
|||
let tex_coords: Vec<glam::Vec2> = mesh.tex_coords().cloned()
|
||||
.unwrap_or_else(|| vec![glam::Vec2::new(0.0, 0.0); positions.len()]);
|
||||
|
||||
debug!("Pos count: {}, tex coords count: {}", positions.len(), tex_coords.len());
|
||||
assert!(positions.len() == tex_coords.len());
|
||||
|
||||
let vertex_inputs: Vec<Vertex> = std::iter::zip(positions, tex_coords.into_iter())
|
||||
.map(|(v, t)| Vertex::new(v.clone(), t))
|
||||
.collect();
|
||||
println!("Vertex inputs: {:?}", vertex_inputs.as_slice());
|
||||
|
||||
let vertex_buffer = self.device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
|
@ -565,6 +582,28 @@ impl BasicRenderer {
|
|||
buffers.next_indices = indices;
|
||||
indices
|
||||
}
|
||||
|
||||
/// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed.
|
||||
fn process_mesh(&mut self, entity: EntityId, transform: Transform, mesh: &Mesh) -> bool {
|
||||
let indices = self.transform_buffers.update_or_insert(&self.queue, &self.render_limits,
|
||||
entity, || transform.calculate_mat4());
|
||||
|
||||
if self.mesh_buffers.contains_key(&mesh.uuid) {
|
||||
false
|
||||
} else {
|
||||
// check if the transform buffers need to be expanded
|
||||
if self.transform_buffers.should_expand() {
|
||||
self.expand_transform_buffers();
|
||||
}
|
||||
|
||||
// create the mesh's buffers
|
||||
let buffers = self.create_mesh_buffers(mesh, indices);
|
||||
self.mesh_buffers.insert(mesh.uuid, buffers);
|
||||
self.entity_meshes.insert(entity, mesh.uuid);
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for BasicRenderer {
|
||||
|
@ -574,37 +613,20 @@ impl Renderer for BasicRenderer {
|
|||
let mut alive_entities = HashSet::new();
|
||||
|
||||
for (entity, model, model_epoch, transform) in main_world.query::<(Entities, &ModelComponent, EpochOf<ModelComponent>, &TransformComponent)>().iter() {
|
||||
let model = model.data.as_ref().unwrap().as_ref();
|
||||
let model_mesh = model.meshes.first().unwrap();
|
||||
|
||||
// Create the render job and push it to the queue
|
||||
let job = RenderJob::new(model_mesh.clone(), entity, transform.transform, None);
|
||||
self.render_jobs.push_back(job);
|
||||
|
||||
alive_entities.insert(entity);
|
||||
|
||||
if self.buffer_storage.get(&entity).is_none() {
|
||||
// check if the transform buffers need to be expanded
|
||||
if self.transform_buffers.should_expand() {
|
||||
self.expand_transform_buffers();
|
||||
let model = model.data.as_ref().unwrap().as_ref();
|
||||
|
||||
for mesh in model.meshes.iter() {
|
||||
if !self.process_mesh(entity, transform.transform, mesh) {
|
||||
if model_epoch == last_epoch {
|
||||
self.update_mesh_buffers(entity, mesh);
|
||||
}
|
||||
}
|
||||
|
||||
// insert transform into buffers
|
||||
let indices = self.transform_buffers.insert_entity(&self.queue, &self.render_limits,
|
||||
entity, transform.transform.calculate_mat4());
|
||||
|
||||
// create the mesh's buffers
|
||||
let buffers = self.create_mesh_buffers(model_mesh, indices);
|
||||
self.buffer_storage.insert(entity, buffers);
|
||||
} else {
|
||||
// update entity transforms
|
||||
self.transform_buffers.update_entity(&self.queue, &self.render_limits,
|
||||
entity, transform.transform.calculate_mat4());
|
||||
|
||||
// if the model was updated, update its buffers
|
||||
if model_epoch == last_epoch {
|
||||
self.update_mesh_buffers(entity, model_mesh);
|
||||
}
|
||||
let shader = mesh.material().shader_uuid.unwrap_or(0);
|
||||
let job = RenderJob::new(entity, shader, mesh.uuid, transform.transform, None);
|
||||
self.render_jobs.push_back(job);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -617,8 +639,12 @@ impl Renderer for BasicRenderer {
|
|||
|
||||
// when buffer storage length does not match the amount of iterated entities,
|
||||
// remove all dead entities, and their buffers, if they weren't iterated over
|
||||
if self.buffer_storage.len() != alive_entities.len() {
|
||||
self.buffer_storage.retain(|e, _| alive_entities.contains(e));
|
||||
if self.mesh_buffers.len() != alive_entities.len() {
|
||||
let removed_entities: Vec<uuid::Uuid> = self.entity_meshes
|
||||
.extract_if(|e, _| !alive_entities.contains(e))
|
||||
.map(|(_, v)| v)
|
||||
.collect();
|
||||
self.mesh_buffers.retain(|u, _| !removed_entities.contains(u));
|
||||
}
|
||||
|
||||
if let Some(camera) = main_world.query_mut::<(&mut CameraComponent,)>().into_iter().next() {
|
||||
|
@ -663,13 +689,12 @@ impl Renderer for BasicRenderer {
|
|||
|
||||
// Pop off jobs from the queue as they're being processed
|
||||
while let Some(job) = self.render_jobs.pop_front() {
|
||||
if let Some(pipeline) = self.render_pipelines.get(&job.mesh().material().shader_uuid.unwrap_or(0)) {
|
||||
if let Some(pipeline) = self.render_pipelines.get(&job.shader_id) {
|
||||
// specify to use this pipeline
|
||||
render_pass.set_pipeline(pipeline.get_wgpu_pipeline());
|
||||
|
||||
// get the mesh (containing vertices) and the buffers from storage
|
||||
let mesh = job.mesh();
|
||||
let buffers = self.buffer_storage.get(&job.entity()).unwrap();
|
||||
let buffers = self.mesh_buffers.get(&job.mesh_buffer_id).unwrap();
|
||||
|
||||
// Bind the optional texture
|
||||
if let Some(tex) = buffers.texture_bindgroup.as_ref() {
|
||||
|
@ -695,13 +720,11 @@ impl Renderer for BasicRenderer {
|
|||
render_pass.set_index_buffer(indices.buffer().slice(..), idx_type.clone());
|
||||
render_pass.draw_indexed(0..indices_len, 0, 0..1);
|
||||
} else {
|
||||
let vertices = mesh.position().unwrap();
|
||||
let vertex_count = buffers.buffer_vertex.count();
|
||||
|
||||
render_pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
|
||||
render_pass.draw(0..vertices.len() as u32, 0..1);
|
||||
render_pass.draw(0..vertex_count as u32, 0..1);
|
||||
}
|
||||
} else {
|
||||
warn!("Failure to find RenderPipeline with shader id of '{}'!", job.mesh().material().shader_uuid.unwrap_or(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue