From 649ffebb7ffcc3d373d4f02e3683d2d5f043f047 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 19 Apr 2020 10:08:47 -0700 Subject: [PATCH] New Mesh implementation (adapts to arbitrary vertex descriptors). Initial gltf model loading. --- .vscode/launch.json | 3 + Cargo.toml | 4 +- bevy_asset/Cargo.toml | 3 +- bevy_asset/src/gltf.rs | 15 - bevy_asset/src/lib.rs | 3 - bevy_derive/src/lib.rs | 4 +- bevy_gltf/Cargo.toml | 12 + bevy_gltf/src/lib.rs | 91 ++++ bevy_render/Cargo.toml | 3 +- .../draw_targets/ui_draw_target.rs | 22 +- bevy_render/src/lib.rs | 2 +- bevy_render/src/mesh.rs | 390 +++++++++++++----- bevy_render/src/pipeline/pipeline_layout.rs | 2 +- .../pipeline/pipelines/forward/forward.frag | 4 +- .../pipeline/pipelines/forward/forward.vert | 12 +- .../pipelines/forward_flat/forward_flat.frag | 2 +- .../pipelines/forward_flat/forward_flat.vert | 12 +- bevy_render/src/pipeline/pipelines/ui/ui.vert | 8 +- .../src/pipeline/vertex_buffer_descriptor.rs | 6 +- .../camera_resource_provider.rs | 2 +- .../mesh_resource_provider.rs | 16 +- bevy_render/src/shader/shader.rs | 1 + bevy_render/src/shader/shader_reflect.rs | 4 +- .../src/shader/uniforms/local_to_world.rs | 10 +- bevy_render/src/vertex.rs | 61 +-- bevy_wgpu/src/wgpu_renderer.rs | 2 +- .../example_plugin/src/lib.rs | 2 +- examples/entity_builder_comparison.rs | 4 +- examples/input_keyboard.rs | 2 +- examples/instancing.rs | 4 +- examples/load_model.rs | 6 +- examples/parenting.rs | 2 +- examples/scene.rs | 4 +- examples/shader_custom_material.rs | 2 +- examples/shader_defs.rs | 2 +- examples/spawner.rs | 4 +- examples/startup_system.rs | 2 +- examples/texture.rs | 2 +- examples/ui.rs | 2 +- src/lib.rs | 2 + src/prelude.rs | 2 +- 41 files changed, 487 insertions(+), 249 deletions(-) delete mode 100644 bevy_asset/src/gltf.rs create mode 100644 bevy_gltf/Cargo.toml create mode 100644 bevy_gltf/src/lib.rs diff --git a/.vscode/launch.json b/.vscode/launch.json index 1864975ab0..501e86d3e7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,6 +9,7 @@ "type": "lldb", "request": "launch", "name": "Debug unit tests in library 'bevy'", + "sourceLanguages": ["rust"], "cargo": { "args": [ "test", @@ -28,6 +29,7 @@ "type": "lldb", "request": "launch", "name": "Build and launch example", + "sourceLanguages": ["rust"], "cargo": { "args": [ "build", @@ -46,6 +48,7 @@ "type": "lldb", "request": "launch", "name": "Launch example", + "sourceLanguages": ["rust"], "cargo": { "args": [ "run", diff --git a/Cargo.toml b/Cargo.toml index c47044b792..8b2c060775 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,12 @@ edition = "2018" [features] default = ["headless", "wgpu", "winit"] -headless = ["asset", "core", "derive", "diagnostic", "input", "render", "serialization", "transform", "ui", "window"] +headless = ["asset", "core", "derive", "diagnostic", "gltf", "input", "render", "serialization", "transform", "ui", "window"] asset = ["bevy_asset"] core = ["bevy_core"] derive = ["bevy_derive"] diagnostic = ["bevy_diagnostic"] +gltf = ["bevy_gltf"] input = ["bevy_input"] render = ["bevy_render"] serialization = ["bevy_serialization"] @@ -27,6 +28,7 @@ bevy_asset = { path = "bevy_asset", optional = true } bevy_core = { path = "bevy_core", optional = true } bevy_derive = { path = "bevy_derive", optional = true } bevy_diagnostic = { path = "bevy_diagnostic", optional = true } +bevy_gltf = { path = "bevy_gltf", optional = true } bevy_input = { path = "bevy_input", optional = true } bevy_render = { path = "bevy_render", optional = true } bevy_serialization = { path = "bevy_serialization", optional = true } diff --git a/bevy_asset/Cargo.toml b/bevy_asset/Cargo.toml index da2f9379b5..a3f43e63f8 100644 --- a/bevy_asset/Cargo.toml +++ b/bevy_asset/Cargo.toml @@ -5,5 +5,4 @@ authors = ["Carter Anderson "] edition = "2018" [dependencies] -bevy_core = { path = "../bevy_core" } -gltf = "0.14.0" \ No newline at end of file +bevy_core = { path = "../bevy_core" } \ No newline at end of file diff --git a/bevy_asset/src/gltf.rs b/bevy_asset/src/gltf.rs deleted file mode 100644 index 1257d44567..0000000000 --- a/bevy_asset/src/gltf.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::{boxed::Box, error::Error, fs, io}; - -// use crate::render::Mesh; - -pub fn load_gltf(path: &str) -> Result<(), Box> { - println!("{}", path); - let file = fs::File::open(&path)?; - let reader = io::BufReader::new(file); - let gltf = gltf::Gltf::from_reader(reader)?; - for scene in gltf.scenes() { - for _mesh in scene.nodes() {} - } - - Ok(()) -} diff --git a/bevy_asset/src/lib.rs b/bevy_asset/src/lib.rs index 4e106365ef..ff2b1d8aac 100644 --- a/bevy_asset/src/lib.rs +++ b/bevy_asset/src/lib.rs @@ -1,6 +1,3 @@ -mod gltf; - -pub use self::gltf::load_gltf; use bevy_core::bytes::GetBytes; use std::{ fmt::Debug, diff --git a/bevy_derive/src/lib.rs b/bevy_derive/src/lib.rs index dc6e8cc585..693142d9fc 100644 --- a/bevy_derive/src/lib.rs +++ b/bevy_derive/src/lib.rs @@ -387,7 +387,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { format!("{}", name) }; let descriptor = VertexAttributeDescriptor { - name: formatted_name, + name: formatted_name.into(), offset, format: *format, shader_location, @@ -400,7 +400,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { #bevy_render_path::pipeline::VertexBufferDescriptor { attributes: vertex_attribute_descriptors, - name: #struct_name_string.to_string(), + name: #struct_name_string.into(), step_mode: #bevy_render_path::pipeline::InputStepMode::Instance, stride: offset, } diff --git a/bevy_gltf/Cargo.toml b/bevy_gltf/Cargo.toml new file mode 100644 index 0000000000..340d5744f0 --- /dev/null +++ b/bevy_gltf/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "bevy_gltf" +version = "0.1.0" +authors = ["Carter Anderson "] +edition = "2018" + +[dependencies] +bevy_asset = { path = "../bevy_asset" } +bevy_render = { path = "../bevy_render" } + +gltf = "0.15.2" +thiserror = "1.0" \ No newline at end of file diff --git a/bevy_gltf/src/lib.rs b/bevy_gltf/src/lib.rs new file mode 100644 index 0000000000..fde298a562 --- /dev/null +++ b/bevy_gltf/src/lib.rs @@ -0,0 +1,91 @@ +use bevy_render::{ + mesh::{Mesh, VertexAttribute, VertexAttributeValues}, + pipeline::state_descriptors::PrimitiveTopology, +}; +use gltf::{buffer::Source, iter, mesh::Mode}; +use std::{fs, io, path::Path}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum GltfError { + #[error("Unsupported primitive mode.")] + UnsupportedPrimitive { mode: Mode }, + #[error("Invalid GLTF file.")] + Gltf(#[from] gltf::Error), + #[error("Failed to load file.")] + Io(#[from] io::Error), + #[error("Binary buffers not supported yet.")] + BinaryBuffersUnsupported, +} + +fn get_primitive_topology(mode: Mode) -> Result { + match mode { + Mode::Points => Ok(PrimitiveTopology::PointList), + Mode::Lines => Ok(PrimitiveTopology::LineList), + Mode::LineStrip => Ok(PrimitiveTopology::LineStrip), + Mode::Triangles => Ok(PrimitiveTopology::TriangleList), + Mode::TriangleStrip => Ok(PrimitiveTopology::TriangleStrip), + mode @ _ => Err(GltfError::UnsupportedPrimitive { mode }), + } +} + +pub fn load_gltf(path: &str) -> Result, GltfError> { + let path: &Path = path.as_ref(); + let file = fs::File::open(&path)?; + let reader = io::BufReader::new(file); + let gltf = gltf::Gltf::from_reader(reader)?; + let buffer_data = load_buffers(gltf.buffers(), path)?; + for scene in gltf.scenes() { + for node in scene.nodes() { + return Ok(Some(load_node(&buffer_data, &node, 1)?)); + } + } + + Ok(None) +} + +fn load_node(buffer_data: &[Vec], node: &gltf::Node, depth: i32) -> Result { + if let Some(mesh) = node.mesh() { + for primitive in mesh.primitives() { + let reader = primitive.reader(|buffer| Some(&buffer_data[buffer.index()])); + let primitive_topology = get_primitive_topology(primitive.mode())?; + let mut mesh = Mesh::new(primitive_topology); + reader + .read_positions() + .map(|v| VertexAttribute { + name: "position".into(), + values: VertexAttributeValues::Float3(v.collect()), + }) + .map(|vertex_attribute| mesh.attributes.push(vertex_attribute)); + + // let indices = reader.read_indices().unwrap(); + return Ok(mesh); + } + } + println!(); + + for child in node.children() { + return Ok(load_node(buffer_data, &child, depth + 1)?); + } + + panic!("failed to find mesh") +} + +fn load_buffers(buffers: iter::Buffers, path: &Path) -> Result>, GltfError> { + let mut buffer_data = Vec::new(); + for buffer in buffers { + match buffer.source() { + Source::Uri(uri) => { + if uri.starts_with("data:") { + } else { + let buffer_path = path.parent().unwrap().join(uri); + let buffer_bytes = fs::read(buffer_path)?; + buffer_data.push(buffer_bytes); + } + } + Source::Bin => return Err(GltfError::BinaryBuffersUnsupported), + } + } + + Ok(buffer_data) +} diff --git a/bevy_render/Cargo.toml b/bevy_render/Cargo.toml index 14897bd1e5..23f4198ccf 100644 --- a/bevy_render/Cargo.toml +++ b/bevy_render/Cargo.toml @@ -28,4 +28,5 @@ zerocopy = "0.3" bitflags = "1.0" # TODO: replace once_cell with std equivalent if/when this lands: https://github.com/rust-lang/rfcs/pull/2788 once_cell = "1.3.1" -downcast-rs = "1.1.1" \ No newline at end of file +downcast-rs = "1.1.1" +thiserror = "1.0" \ No newline at end of file diff --git a/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs b/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs index 1388f60814..e6605e3c78 100644 --- a/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs +++ b/bevy_render/src/draw_target/draw_targets/ui_draw_target.rs @@ -1,6 +1,6 @@ use crate::{ draw_target::DrawTarget, - mesh::{Mesh, MeshType}, + mesh::{shape::Quad, Mesh}, pass::RenderPass, pipeline::PipelineDescriptor, render_resource::{ @@ -83,24 +83,36 @@ impl DrawTarget for UiDrawTarget { return; } - let quad = Mesh::load(MeshType::Quad { + let quad = Mesh::from(Quad { size: glam::vec2(1.0, 1.0), }); + let vertex_buffer_bytes = quad.get_vertex_buffer_bytes( + pipeline_descriptor + .get_layout() + .unwrap() + .vertex_buffer_descriptors + .first() + .as_ref() + .unwrap(), + ).unwrap(); self.mesh_vertex_buffer = Some(render_context.resources_mut().create_buffer_with_data( BufferInfo { buffer_usage: BufferUsage::VERTEX, ..Default::default() }, - quad.vertices.as_bytes(), + &vertex_buffer_bytes, )); + + let index_buffer_bytes = quad.get_index_buffer_bytes(pipeline_descriptor.index_format).unwrap(); self.mesh_index_buffer = Some(render_context.resources_mut().create_buffer_with_data( BufferInfo { buffer_usage: BufferUsage::INDEX, ..Default::default() }, - quad.indices.as_bytes(), + &index_buffer_bytes, )); - self.mesh_index_length = quad.indices.len(); + + self.mesh_index_length = quad.indices.as_ref().unwrap().len(); let global_render_resource_assignments = resources.get::().unwrap(); diff --git a/bevy_render/src/lib.rs b/bevy_render/src/lib.rs index c0c6c9b781..b101772e52 100644 --- a/bevy_render/src/lib.rs +++ b/bevy_render/src/lib.rs @@ -6,10 +6,10 @@ pub mod render_graph; pub mod render_graph_2; pub mod renderer_2; pub mod shader; +pub mod vertex; mod color; mod light; -mod vertex; pub use camera::*; pub use color::*; diff --git a/bevy_render/src/mesh.rs b/bevy_render/src/mesh.rs index 0d208ff55e..31d403be74 100644 --- a/bevy_render/src/mesh.rs +++ b/bevy_render/src/mesh.rs @@ -1,126 +1,310 @@ -use crate::{render_resource::AssetBatchers, Renderable, Vertex}; +use crate::{ + pipeline::{ + state_descriptors::{IndexFormat, PrimitiveTopology}, + VertexBufferDescriptor, VertexFormat, + }, + render_resource::AssetBatchers, + Renderable, Vertex, +}; use bevy_asset::{Asset, Handle}; use glam::*; use legion::prelude::*; +use std::borrow::Cow; +use thiserror::Error; +use zerocopy::AsBytes; pub const VERTEX_BUFFER_ASSET_INDEX: usize = 0; pub const INDEX_BUFFER_ASSET_INDEX: usize = 1; - -pub enum MeshType { - Cube, - Plane { size: f32 }, - Quad { size: Vec2 }, +#[derive(Clone, Debug)] +pub enum VertexAttributeValues { + Float(Vec), + Float2(Vec<[f32; 2]>), + Float3(Vec<[f32; 3]>), + Float4(Vec<[f32; 4]>), } -pub struct Mesh { - pub vertices: Vec, - pub indices: Vec, -} +impl VertexAttributeValues { + pub fn len(&self) -> usize { + match *self { + VertexAttributeValues::Float(ref values) => values.len(), + VertexAttributeValues::Float2(ref values) => values.len(), + VertexAttributeValues::Float3(ref values) => values.len(), + VertexAttributeValues::Float4(ref values) => values.len(), + } + } -impl Asset for Mesh { - fn load(descriptor: MeshType) -> Self { - let (vertices, indices) = match descriptor { - MeshType::Cube => create_cube(), - MeshType::Plane { size } => create_plane(size), - MeshType::Quad { size } => create_quad(size), - }; - - Mesh { vertices, indices } + // TODO: add vertex format as parameter here and perform type conversions + pub fn get_bytes(&self) -> &[u8] { + match *self { + VertexAttributeValues::Float(ref values) => values.as_bytes(), + VertexAttributeValues::Float2(ref values) => values.as_bytes(), + VertexAttributeValues::Float3(ref values) => values.as_bytes(), + VertexAttributeValues::Float4(ref values) => values.as_bytes(), + } } } -pub fn create_quad_from_vertices( - north_west: Vec2, - north_east: Vec2, - south_west: Vec2, - south_east: Vec2, -) -> (Vec, Vec) { - let vertex_data = [ - Vertex::from(( - [south_west.x(), south_west.y(), 0.0], - [0.0, 0.0, 1.0], - [0.0, 1.0], - )), - Vertex::from(( - [north_west.x(), north_west.y(), 0.0], - [0.0, 0.0, 1.0], - [0.0, 0.0], - )), - Vertex::from(( - [north_east.x(), north_east.y(), 0.0], - [0.0, 0.0, 1.0], - [1.0, 0.0], - )), - Vertex::from(( - [south_east.x(), south_east.y(), 0.0], - [0.0, 0.0, 1.0], - [1.0, 1.0], - )), - ]; - - let index_data: &[u16] = &[0, 2, 1, 0, 3, 2]; - return (vertex_data.to_vec(), index_data.to_vec()); +impl From<&VertexAttributeValues> for VertexFormat { + fn from(values: &VertexAttributeValues) -> Self { + match values { + VertexAttributeValues::Float(_) => VertexFormat::Float, + VertexAttributeValues::Float2(_) => VertexFormat::Float2, + VertexAttributeValues::Float3(_) => VertexFormat::Float3, + VertexAttributeValues::Float4(_) => VertexFormat::Float4, + } + } } -pub fn create_quad(dimensions: Vec2) -> (Vec, Vec) { - let extent_x = dimensions.x() / 2.0; - let extent_y = dimensions.y() / 2.0; - create_quad_from_vertices( - vec2(-extent_x, extent_y), - vec2(extent_x, extent_y), - vec2(-extent_x, -extent_y), - vec2(extent_x, -extent_y), - ) +#[derive(Debug)] +pub struct VertexAttribute { + pub name: Cow<'static, str>, + pub values: VertexAttributeValues, } -pub fn create_cube() -> (Vec, Vec) { - let vertex_data = [ - // top (0, 0, 1) - Vertex::from(([-1, -1, 1], [0, 0, 1], [0, 0])), - Vertex::from(([1, -1, 1], [0, 0, 1], [1, 0])), - Vertex::from(([1, 1, 1], [0, 0, 1], [1, 1])), - Vertex::from(([-1, 1, 1], [0, 0, 1], [0, 1])), - // bottom (0, 0, -1) - Vertex::from(([-1, 1, -1], [0, 0, -1], [1, 0])), - Vertex::from(([1, 1, -1], [0, 0, -1], [0, 0])), - Vertex::from(([1, -1, -1], [0, 0, -1], [0, 1])), - Vertex::from(([-1, -1, -1], [0, 0, -1], [1, 1])), - // right (1, 0, 0) - Vertex::from(([1, -1, -1], [1, 0, 0], [0, 0])), - Vertex::from(([1, 1, -1], [1, 0, 0], [1, 0])), - Vertex::from(([1, 1, 1], [1, 0, 0], [1, 1])), - Vertex::from(([1, -1, 1], [1, 0, 0], [0, 1])), - // left (-1, 0, 0) - Vertex::from(([-1, -1, 1], [-1, 0, 0], [1, 0])), - Vertex::from(([-1, 1, 1], [-1, 0, 0], [0, 0])), - Vertex::from(([-1, 1, -1], [-1, 0, 0], [0, 1])), - Vertex::from(([-1, -1, -1], [-1, 0, 0], [1, 1])), - // front (0, 1, 0) - Vertex::from(([1, 1, -1], [0, 1, 0], [1, 0])), - Vertex::from(([-1, 1, -1], [0, 1, 0], [0, 0])), - Vertex::from(([-1, 1, 1], [0, 1, 0], [0, 1])), - Vertex::from(([1, 1, 1], [0, 1, 0], [1, 1])), - // back (0, -1, 0) - Vertex::from(([1, -1, 1], [0, -1, 0], [0, 0])), - Vertex::from(([-1, -1, 1], [0, -1, 0], [1, 0])), - Vertex::from(([-1, -1, -1], [0, -1, 0], [1, 1])), - Vertex::from(([1, -1, -1], [0, -1, 0], [0, 1])), - ]; +impl VertexAttribute { + pub const POSITION: &'static str = "position"; + pub const NORMAL: &'static str = "normal"; + pub const UV: &'static str = "uv"; - let index_data: &[u16] = &[ - 0, 1, 2, 2, 3, 0, // top - 4, 5, 6, 6, 7, 4, // bottom - 8, 9, 10, 10, 11, 8, // right - 12, 13, 14, 14, 15, 12, // left - 16, 17, 18, 18, 19, 16, // front - 20, 21, 22, 22, 23, 20, // back - ]; + pub fn position(positions: Vec<[f32; 3]>) -> Self { + VertexAttribute { + name: Self::POSITION.into(), + values: VertexAttributeValues::Float3(positions), + } + } - (vertex_data.to_vec(), index_data.to_vec()) + pub fn normal(normals: Vec<[f32; 3]>) -> Self { + VertexAttribute { + name: Self::NORMAL.into(), + values: VertexAttributeValues::Float3(normals), + } + } + + pub fn uv(uvs: Vec<[f32; 2]>) -> Self { + VertexAttribute { + name: Self::UV.into(), + values: VertexAttributeValues::Float2(uvs), + } + } } -pub fn create_plane(size: f32) -> (Vec, Vec) { - create_quad(vec2(size, size)) +#[derive(Error, Debug)] +pub enum MeshToVertexBufferError { + #[error("VertexBufferDescriptor requires a VertexBufferAttribute this Mesh does not contain.")] + MissingVertexAttribute { attribute_name: Cow<'static, str> }, + #[error("Mesh VertexAttribute VertexFormat is incompatible with VertexBufferDescriptor VertexAttribute VertexFormat.")] + IncompatibleVertexAttributeFormat { + attribute_name: Cow<'static, str>, + descriptor_format: VertexFormat, + mesh_format: VertexFormat, + }, +} + +#[derive(Debug)] +pub struct Mesh { + pub primitive_topology: PrimitiveTopology, + pub attributes: Vec, + pub indices: Option>, +} + +impl Mesh { + pub fn new(primitive_topology: PrimitiveTopology) -> Self { + Mesh { + primitive_topology, + attributes: Vec::new(), + indices: None, + } + } + + pub fn get_vertex_buffer_bytes( + &self, + vertex_buffer_descriptor: &VertexBufferDescriptor, + ) -> Result, MeshToVertexBufferError> { + let length = self.attributes.first().map(|a| a.values.len()).unwrap_or(0); + let mut bytes = vec![0; vertex_buffer_descriptor.stride as usize * length]; + + for vertex_attribute in vertex_buffer_descriptor.attributes.iter() { + match self + .attributes + .iter() + .find(|a| VertexFormat::from(&a.values) == vertex_attribute.format) + { + Some(mesh_attribute) => { + let attribute_bytes = mesh_attribute.values.get_bytes(); + let attribute_size = vertex_attribute.format.get_size() as usize; + for (i, vertex_slice) in attribute_bytes.chunks(attribute_size).enumerate() { + let vertex_offset = vertex_buffer_descriptor.stride as usize * i; + let attribute_offset = vertex_offset + vertex_attribute.offset as usize; + bytes[attribute_offset..attribute_offset + attribute_size] + .copy_from_slice(vertex_slice); + } + } + None => { + return Err(MeshToVertexBufferError::MissingVertexAttribute { + attribute_name: vertex_attribute.name.clone(), + }) + } + } + } + + Ok(bytes) + } + + pub fn get_index_buffer_bytes(&self, index_format: IndexFormat) -> Option> { + self.indices.as_ref().map(|indices| match index_format { + IndexFormat::Uint16 => indices + .iter() + .map(|i| *i as u16) + .collect::>() + .as_bytes() + .to_vec(), + IndexFormat::Uint32 => indices.as_bytes().to_vec(), + }) + } +} + +pub mod shape { + use super::{Mesh, VertexAttribute}; + use crate::pipeline::state_descriptors::PrimitiveTopology; + use glam::*; + + pub struct Cube; + + impl From for Mesh { + fn from(_: Cube) -> Self { + let vertices = &[ + // top (0., 0., 1.) + ([-1., -1., 1.], [0., 0., 1.], [0., 0.]), + ([1., -1., 1.], [0., 0., 1.], [1., 0.]), + ([1., 1., 1.], [0., 0., 1.], [1., 1.]), + ([-1., 1., 1.], [0., 0., 1.], [0., 1.]), + // bottom (0., 0., -1.) + ([-1., 1., -1.], [0., 0., -1.], [1., 0.]), + ([1., 1., -1.], [0., 0., -1.], [0., 0.]), + ([1., -1., -1.], [0., 0., -1.], [0., 1.]), + ([-1., -1., -1.], [0., 0., -1.], [1., 1.]), + // right (1., 0., 0.) + ([1., -1., -1.], [1., 0., 0.], [0., 0.]), + ([1., 1., -1.], [1., 0., 0.], [1., 0.]), + ([1., 1., 1.], [1., 0., 0.], [1., 1.]), + ([1., -1., 1.], [1., 0., 0.], [0., 1.]), + // left (-1., 0., 0.) + ([-1., -1., 1.], [-1., 0., 0.], [1., 0.]), + ([-1., 1., 1.], [-1., 0., 0.], [0., 0.]), + ([-1., 1., -1.], [-1., 0., 0.], [0., 1.]), + ([-1., -1., -1.], [-1., 0., 0.], [1., 1.]), + // front (0., 1., 0.) + ([1., 1., -1.], [0., 1., 0.], [1., 0.]), + ([-1., 1., -1.], [0., 1., 0.], [0., 0.]), + ([-1., 1., 1.], [0., 1., 0.], [0., 1.]), + ([1., 1., 1.], [0., 1., 0.], [1., 1.]), + // back (0., -1., 0.) + ([1., -1., 1.], [0., -1., 0.], [0., 0.]), + ([-1., -1., 1.], [0., -1., 0.], [1., 0.]), + ([-1., -1., -1.], [0., -1., 0.], [1., 1.]), + ([1., -1., -1.], [0., -1., 0.], [0., 1.]), + ]; + + let mut positions = Vec::new(); + let mut normals = Vec::new(); + let mut uvs = Vec::new(); + for (position, normal, uv) in vertices.iter() { + positions.push(position.clone()); + normals.push(normal.clone()); + uvs.push(uv.clone()); + } + + let indices = vec![ + 0, 1, 2, 2, 3, 0, // top + 4, 5, 6, 6, 7, 4, // bottom + 8, 9, 10, 10, 11, 8, // right + 12, 13, 14, 14, 15, 12, // left + 16, 17, 18, 18, 19, 16, // front + 20, 21, 22, 22, 23, 20, // back + ]; + + Mesh { + primitive_topology: PrimitiveTopology::TriangleStrip, + attributes: vec![ + VertexAttribute::position(positions), + VertexAttribute::normal(normals), + VertexAttribute::uv(uvs), + ], + indices: Some(indices), + } + } + } + + pub struct Quad { + pub size: Vec2, + } + + impl From for Mesh { + fn from(quad: Quad) -> Self { + let extent_x = quad.size.x() / 2.0; + let extent_y = quad.size.y() / 2.0; + + let north_west = vec2(-extent_x, extent_y); + let north_east = vec2(extent_x, extent_y); + let south_west = vec2(-extent_x, -extent_y); + let south_east = vec2(extent_x, -extent_y); + let vertices = &[ + ( + [south_west.x(), south_west.y(), 0.0], + [0.0, 0.0, 1.0], + [0.0, 1.0], + ), + ( + [north_west.x(), north_west.y(), 0.0], + [0.0, 0.0, 1.0], + [0.0, 0.0], + ), + ( + [north_east.x(), north_east.y(), 0.0], + [0.0, 0.0, 1.0], + [1.0, 0.0], + ), + ( + [south_east.x(), south_east.y(), 0.0], + [0.0, 0.0, 1.0], + [1.0, 1.0], + ), + ]; + + let indices = vec![0, 2, 1, 0, 3, 2]; + + let mut positions = Vec::new(); + let mut normals = Vec::new(); + let mut uvs = Vec::new(); + for (position, normal, uv) in vertices.iter() { + positions.push(position.clone()); + normals.push(normal.clone()); + uvs.push(uv.clone()); + } + + Mesh { + primitive_topology: PrimitiveTopology::TriangleStrip, + attributes: vec![ + VertexAttribute::position(positions), + VertexAttribute::normal(normals), + VertexAttribute::uv(uvs), + ], + indices: Some(indices), + } + } + } + + pub struct Plane { + pub size: f32, + } + + impl From for Mesh { + fn from(plane: Plane) -> Self { + Quad { + size: Vec2::new(plane.size, plane.size) + }.into() + } + } } pub fn mesh_batcher_system() -> Box { diff --git a/bevy_render/src/pipeline/pipeline_layout.rs b/bevy_render/src/pipeline/pipeline_layout.rs index 31f65ea811..b5219adb56 100644 --- a/bevy_render/src/pipeline/pipeline_layout.rs +++ b/bevy_render/src/pipeline/pipeline_layout.rs @@ -83,7 +83,7 @@ pub struct UniformProperty { #[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum UniformPropertyType { - // TODO: Add all types here + // TODO: Use VertexFormat here Int, Float, UVec4, diff --git a/bevy_render/src/pipeline/pipelines/forward/forward.frag b/bevy_render/src/pipeline/pipelines/forward/forward.frag index ee94bb29ee..302ba05210 100644 --- a/bevy_render/src/pipeline/pipelines/forward/forward.frag +++ b/bevy_render/src/pipeline/pipelines/forward/forward.frag @@ -8,7 +8,7 @@ struct Light { vec4 color; }; -layout(location = 0) in vec4 v_Position; +layout(location = 0) in vec3 v_Position; layout(location = 1) in vec3 v_Normal; layout(location = 2) in vec2 v_Uv; @@ -46,7 +46,7 @@ void main() { for (int i=0; i, pub stride: u64, pub step_mode: InputStepMode, pub attributes: Vec, @@ -37,7 +37,7 @@ pub enum InputStepMode { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct VertexAttributeDescriptor { - pub name: String, + pub name: Cow<'static, str>, pub offset: u64, pub format: VertexFormat, pub shader_location: u32, diff --git a/bevy_render/src/render_resource/resource_providers/camera_resource_provider.rs b/bevy_render/src/render_resource/resource_providers/camera_resource_provider.rs index c1cfabf6ab..b23771c8a9 100644 --- a/bevy_render/src/render_resource/resource_providers/camera_resource_provider.rs +++ b/bevy_render/src/render_resource/resource_providers/camera_resource_provider.rs @@ -18,7 +18,7 @@ pub fn camera_resource_provider_system(resources: &mut Resources) -> Box(); - SystemBuilder::new("mesh_resource_provider") + SystemBuilder::new("camera_resource_provider") .read_resource::() // TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same .write_resource::() diff --git a/bevy_render/src/render_resource/resource_providers/mesh_resource_provider.rs b/bevy_render/src/render_resource/resource_providers/mesh_resource_provider.rs index b89a039275..f65cd4d08a 100644 --- a/bevy_render/src/render_resource/resource_providers/mesh_resource_provider.rs +++ b/bevy_render/src/render_resource/resource_providers/mesh_resource_provider.rs @@ -1,6 +1,6 @@ use crate::{ mesh::{self, Mesh}, - pipeline::VertexBufferDescriptors, + pipeline::{state_descriptors::IndexFormat, VertexBufferDescriptors}, render_resource::{AssetBatchers, BufferInfo, BufferUsage}, renderer_2::GlobalRenderResourceContext, shader::AsUniforms, @@ -8,17 +8,19 @@ use crate::{ }; use bevy_asset::AssetStorage; use legion::prelude::*; -use zerocopy::AsBytes; pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box { let mut vertex_buffer_descriptors = resources.get_mut::().unwrap(); - vertex_buffer_descriptors.set(Vertex::get_vertex_buffer_descriptor().cloned().unwrap()); + // TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format + let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap(); + let index_format = IndexFormat::Uint16; + vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone()); SystemBuilder::new("mesh_resource_provider") .read_resource::() .read_resource::>() .write_resource::() .build( - |_, _, (render_resource_context, meshes, asset_batchers), _| { + move |_, _, (render_resource_context, meshes, asset_batchers), _| { let render_resources = &render_resource_context.context; if let Some(batches) = asset_batchers.get_handle_batches_mut::() { for batch in batches { @@ -35,20 +37,22 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box VertexAttributeDescriptor { VertexAttributeDescriptor { - name: input_variable.name.clone(), + name: input_variable.name.clone().into(), format: reflect_vertex_format(input_variable.type_description.as_ref().unwrap()), offset: 0, shader_location: input_variable.location, diff --git a/bevy_render/src/shader/uniforms/local_to_world.rs b/bevy_render/src/shader/uniforms/local_to_world.rs index 20a89fbcce..a6dabb3dd3 100644 --- a/bevy_render/src/shader/uniforms/local_to_world.rs +++ b/bevy_render/src/shader/uniforms/local_to_world.rs @@ -19,31 +19,31 @@ static VERTEX_BUFFER_DESCRIPTOR: Lazy = Lazy::new(|| VertexBufferDescriptor { attributes: vec![ VertexAttributeDescriptor { - name: "I_Object_Model_0".to_string(), + name: "I_Object_Model_0".into(), format: VertexFormat::Float4, offset: 0, shader_location: 0, }, VertexAttributeDescriptor { - name: "I_Object_Model_1".to_string(), + name: "I_Object_Model_1".into(), format: VertexFormat::Float4, offset: 16, shader_location: 1, }, VertexAttributeDescriptor { - name: "I_Object_Model_2".to_string(), + name: "I_Object_Model_2".into(), format: VertexFormat::Float4, offset: 32, shader_location: 2, }, VertexAttributeDescriptor { - name: "I_Object_Model_3".to_string(), + name: "I_Object_Model_3".into(), format: VertexFormat::Float4, offset: 48, shader_location: 3, }, ], - name: "Object".to_string(), + name: "Object".into(), step_mode: InputStepMode::Instance, stride: 64, }); diff --git a/bevy_render/src/vertex.rs b/bevy_render/src/vertex.rs index d2b16af302..76d6d76a9e 100644 --- a/bevy_render/src/vertex.rs +++ b/bevy_render/src/vertex.rs @@ -10,64 +10,9 @@ use bevy_derive::Uniforms; #[module(meta = false, bevy_render = "crate")] pub struct Vertex { #[uniform(vertex)] - pub position: [f32; 4], + pub position: [f32; 3], #[uniform(vertex)] - pub normal: [f32; 4], + pub normal: [f32; 3], #[uniform(vertex)] pub uv: [f32; 2], -} - -impl From<([f32; 4], [f32; 4], [f32; 2])> for Vertex { - fn from((position, normal, uv): ([f32; 4], [f32; 4], [f32; 2])) -> Self { - Vertex { - position, - normal, - uv, - } - } -} - -impl From<([f32; 3], [f32; 3], [f32; 2])> for Vertex { - fn from((position, normal, uv): ([f32; 3], [f32; 3], [f32; 2])) -> Self { - Vertex { - position: [position[0], position[1], position[2], 1.0], - normal: [normal[0], normal[1], normal[2], 0.0], - uv, - } - } -} - -impl From<([i8; 4], [i8; 4], [i8; 2])> for Vertex { - fn from((position, normal, uv): ([i8; 4], [i8; 4], [i8; 2])) -> Self { - Vertex { - position: [ - position[0] as f32, - position[1] as f32, - position[2] as f32, - position[3] as f32, - ], - normal: [ - normal[0] as f32, - normal[1] as f32, - normal[2] as f32, - normal[3] as f32, - ], - uv: [uv[0] as f32, uv[1] as f32], - } - } -} - -impl From<([i8; 3], [i8; 3], [i8; 2])> for Vertex { - fn from((position, normal, uv): ([i8; 3], [i8; 3], [i8; 2])) -> Self { - Vertex { - position: [ - position[0] as f32, - position[1] as f32, - position[2] as f32, - 1.0, - ], - normal: [normal[0] as f32, normal[1] as f32, normal[2] as f32, 0.0], - uv: [uv[0] as f32, uv[1] as f32], - } - } -} +} \ No newline at end of file diff --git a/bevy_wgpu/src/wgpu_renderer.rs b/bevy_wgpu/src/wgpu_renderer.rs index c9bb69ed92..19fe0d8562 100644 --- a/bevy_wgpu/src/wgpu_renderer.rs +++ b/bevy_wgpu/src/wgpu_renderer.rs @@ -173,7 +173,7 @@ impl WgpuRenderer { pub fn handle_window_resized_events( &mut self, resources: &Resources, - global_render_resources: &mut WgpuRenderResourceContext, + global_render_resources: &dyn RenderResourceContext, ) { let windows = resources.get::().unwrap(); let window_resized_events = resources.get::>().unwrap(); diff --git a/examples/dynamic_plugin_loading/example_plugin/src/lib.rs b/examples/dynamic_plugin_loading/example_plugin/src/lib.rs index fccddf2e61..4b289f191d 100644 --- a/examples/dynamic_plugin_loading/example_plugin/src/lib.rs +++ b/examples/dynamic_plugin_loading/example_plugin/src/lib.rs @@ -14,7 +14,7 @@ pub fn setup(world: &mut World, resources: &mut Resources) { let mut material_storage = resources .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.4, 0.3), ..Default::default() diff --git a/examples/entity_builder_comparison.rs b/examples/entity_builder_comparison.rs index dbfbeb1fac..1b8f009bcc 100644 --- a/examples/entity_builder_comparison.rs +++ b/examples/entity_builder_comparison.rs @@ -153,8 +153,8 @@ fn setup(world: &mut World, resources: &mut Resources) { let mut material_storage = resources .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); - let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 })); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); + let plane_handle = mesh_storage.add(Mesh::from(shape::Plane { size: 10.0 })); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.3, 0.3), diff --git a/examples/input_keyboard.rs b/examples/input_keyboard.rs index f9524db4bd..660f6dccfe 100644 --- a/examples/input_keyboard.rs +++ b/examples/input_keyboard.rs @@ -61,7 +61,7 @@ fn setup(world: &mut World, resources: &mut Resources) { let mut material_storage = resources .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.4, 0.3), ..Default::default() diff --git a/examples/instancing.rs b/examples/instancing.rs index 8d3d524a9f..d28744eb8c 100644 --- a/examples/instancing.rs +++ b/examples/instancing.rs @@ -33,8 +33,8 @@ fn setup(world: &mut World, resources: &mut Resources) { let mut material_storage = resources .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); - let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 })); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); + let plane_handle = mesh_storage.add(Mesh::from(shape::Plane { size: 10.0 })); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.4, 0.3), ..Default::default() diff --git a/examples/load_model.rs b/examples/load_model.rs index 9e599081d0..7facb3c5f5 100644 --- a/examples/load_model.rs +++ b/examples/load_model.rs @@ -1,6 +1,6 @@ -use bevy::{asset, prelude::*}; +use bevy::{gltf, prelude::*}; fn main() { - asset::load_gltf("examples/assets/Box.gltf").unwrap(); - App::build().add_default_plugins().run(); + let mesh = gltf::load_gltf("examples/assets/Box.gltf").unwrap().unwrap(); + // App::build().add_default_plugins().run(); } diff --git a/examples/parenting.rs b/examples/parenting.rs index cb2522c97b..373d9f4d18 100644 --- a/examples/parenting.rs +++ b/examples/parenting.rs @@ -29,7 +29,7 @@ fn setup(world: &mut World, resources: &mut Resources) { .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.4, 0.3), ..Default::default() diff --git a/examples/scene.rs b/examples/scene.rs index 2a72af61f3..0d11fb793a 100644 --- a/examples/scene.rs +++ b/examples/scene.rs @@ -12,8 +12,8 @@ fn setup(world: &mut World, resources: &mut Resources) { env_logger::init(); // create a cube and a plane mesh let mut mesh_storage = resources.get_mut::>().unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); - let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 })); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); + let plane_handle = mesh_storage.add(Mesh::from(shape::Plane { size: 10.0 })); // create materials for our cube and plane let mut material_storage = resources diff --git a/examples/shader_custom_material.rs b/examples/shader_custom_material.rs index 99e4f94012..a01933b154 100644 --- a/examples/shader_custom_material.rs +++ b/examples/shader_custom_material.rs @@ -87,7 +87,7 @@ fn setup(world: &mut World, resources: &mut Resources) { let pipeline_handle = pipeline_storage.get_named("MyMaterial").unwrap(); let mut mesh_storage = resources.get_mut::>().unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); world .build() diff --git a/examples/shader_defs.rs b/examples/shader_defs.rs index 0222a42243..9eac143a1d 100644 --- a/examples/shader_defs.rs +++ b/examples/shader_defs.rs @@ -103,7 +103,7 @@ fn setup(world: &mut World, resources: &mut Resources) { let pipeline_handle = pipeline_storage.get_named("MyMaterial").unwrap(); let mut mesh_storage = resources.get_mut::>().unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); world .build() diff --git a/examples/spawner.rs b/examples/spawner.rs index a19b1de289..c3c08e66ec 100644 --- a/examples/spawner.rs +++ b/examples/spawner.rs @@ -33,8 +33,8 @@ fn setup(world: &mut World, resources: &mut Resources) { let mut material_storage = resources .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); - let plane_handle = mesh_storage.add(Mesh::load(MeshType::Plane { size: 10.0 })); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); + let plane_handle = mesh_storage.add(Mesh::from(shape::Plane { size: 10.0 })); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.4, 0.3), ..Default::default() diff --git a/examples/startup_system.rs b/examples/startup_system.rs index a6327635fd..3b94da86e4 100644 --- a/examples/startup_system.rs +++ b/examples/startup_system.rs @@ -15,7 +15,7 @@ pub fn startup_system() -> Box { .write_resource::>() .write_resource::>() .build(move |command_buffer, _, (meshes, materials), _| { - let cube_handle = meshes.add(Mesh::load(MeshType::Cube)); + let cube_handle = meshes.add(Mesh::from(shape::Cube)); let cube_material_handle = materials.add(StandardMaterial { albedo: Color::rgb(0.5, 0.4, 0.3), ..Default::default() diff --git a/examples/texture.rs b/examples/texture.rs index 1c7ca8e3f7..53d701149e 100644 --- a/examples/texture.rs +++ b/examples/texture.rs @@ -20,7 +20,7 @@ fn setup(world: &mut World, resources: &mut Resources) { // create a new quad mesh. this is what we will apply the texture to let mut mesh_storage = resources.get_mut::>().unwrap(); let quad_width = 8.0; - let quad_handle = mesh_storage.add(Mesh::load(MeshType::Quad { + let quad_handle = mesh_storage.add(Mesh::from(shape::Quad { size: Vec2::new(quad_width, quad_width * aspect), })); diff --git a/examples/ui.rs b/examples/ui.rs index c9aa9d89e0..a6ff9bc340 100644 --- a/examples/ui.rs +++ b/examples/ui.rs @@ -12,7 +12,7 @@ fn setup(world: &mut World, resources: &mut Resources) { let mut material_storage = resources .get_mut::>() .unwrap(); - let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); + let cube_handle = mesh_storage.add(Mesh::from(shape::Cube)); let cube_material_handle = material_storage.add(StandardMaterial { albedo: Color::rgb(0.5, 0.3, 0.3), ..Default::default() diff --git a/src/lib.rs b/src/lib.rs index 8671c05c70..364b0f5995 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,8 @@ pub use bevy_core as core; pub use bevy_derive as derive; #[cfg(feature = "diagnostic")] pub use bevy_diagnostic as diagnostic; +#[cfg(feature = "gltf")] +pub use bevy_gltf as gltf; #[cfg(feature = "input")] pub use bevy_input as input; #[cfg(feature = "render")] diff --git a/src/prelude.rs b/src/prelude.rs index 0fd411bfc2..3d43401607 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -12,7 +12,7 @@ pub use crate::diagnostic::DiagnosticsPlugin; #[cfg(feature = "render")] pub use crate::render::{ entity::*, - mesh::{Mesh, MeshType}, + mesh::{Mesh, shape}, pipeline::PipelineDescriptor, render_graph::RenderGraph, render_resource::{resource_name, resource_providers::UniformResourceProvider, AssetBatchers},