New Mesh implementation (adapts to arbitrary vertex descriptors). Initial gltf model loading.

This commit is contained in:
Carter Anderson 2020-04-19 10:08:47 -07:00
parent 2aaf23b9fd
commit 649ffebb7f
41 changed files with 487 additions and 249 deletions

3
.vscode/launch.json vendored
View file

@ -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",

View file

@ -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 }

View file

@ -5,5 +5,4 @@ authors = ["Carter Anderson <mcanders1@gmail.com>"]
edition = "2018"
[dependencies]
bevy_core = { path = "../bevy_core" }
gltf = "0.14.0"
bevy_core = { path = "../bevy_core" }

View file

@ -1,15 +0,0 @@
use std::{boxed::Box, error::Error, fs, io};
// use crate::render::Mesh;
pub fn load_gltf(path: &str) -> Result<(), Box<dyn Error>> {
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(())
}

View file

@ -1,6 +1,3 @@
mod gltf;
pub use self::gltf::load_gltf;
use bevy_core::bytes::GetBytes;
use std::{
fmt::Debug,

View file

@ -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,
}

12
bevy_gltf/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "bevy_gltf"
version = "0.1.0"
authors = ["Carter Anderson <mcanders1@gmail.com>"]
edition = "2018"
[dependencies]
bevy_asset = { path = "../bevy_asset" }
bevy_render = { path = "../bevy_render" }
gltf = "0.15.2"
thiserror = "1.0"

91
bevy_gltf/src/lib.rs Normal file
View file

@ -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<PrimitiveTopology, GltfError> {
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<Option<Mesh>, 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<u8>], node: &gltf::Node, depth: i32) -> Result<Mesh, GltfError> {
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<Vec<Vec<u8>>, 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)
}

View file

@ -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"
downcast-rs = "1.1.1"
thiserror = "1.0"

View file

@ -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::<RenderResourceAssignments>().unwrap();

View file

@ -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::*;

View file

@ -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<f32>),
Float2(Vec<[f32; 2]>),
Float3(Vec<[f32; 3]>),
Float4(Vec<[f32; 4]>),
}
pub struct Mesh {
pub vertices: Vec<Vertex>,
pub indices: Vec<u16>,
}
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<MeshType> 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<Vertex>, Vec<u16>) {
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<Vertex>, Vec<u16>) {
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<Vertex>, Vec<u16>) {
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<Vertex>, Vec<u16>) {
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<VertexAttribute>,
pub indices: Option<Vec<u32>>,
}
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<Vec<u8>, 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<Vec<u8>> {
self.indices.as_ref().map(|indices| match index_format {
IndexFormat::Uint16 => indices
.iter()
.map(|i| *i as u16)
.collect::<Vec<u16>>()
.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<Cube> 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<Quad> 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<Plane> for Mesh {
fn from(plane: Plane) -> Self {
Quad {
size: Vec2::new(plane.size, plane.size)
}.into()
}
}
}
pub fn mesh_batcher_system() -> Box<dyn Schedulable> {

View file

@ -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,

View file

@ -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<int(NumLights.x) && i<MAX_LIGHTS; ++i) {
Light light = SceneLights[i];
// compute Lambertian diffuse term
vec3 light_dir = normalize(light.pos.xyz - v_Position.xyz);
vec3 light_dir = normalize(light.pos.xyz - v_Position);
float diffuse = max(0.0, dot(normal, light_dir));
// add light contribution
color += diffuse * light.color.xyz;

View file

@ -1,7 +1,7 @@
#version 450
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in vec4 Vertex_Normal;
layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
# ifdef INSTANCING
@ -11,7 +11,7 @@ layout(location = 5) in vec4 I_Object_Model_2;
layout(location = 6) in vec4 I_Object_Model_3;
# endif
layout(location = 0) out vec4 v_Position;
layout(location = 0) out vec3 v_Position;
layout(location = 1) out vec3 v_Normal;
layout(location = 2) out vec2 v_Uv;
@ -35,8 +35,8 @@ void main() {
);
# endif
v_Normal = mat3(Model) * vec3(Vertex_Normal.xyz);
v_Position = Model * Vertex_Position;
v_Normal = (Model * vec4(Vertex_Normal, 1.0)).xyz;
v_Position = (Model * vec4(Vertex_Position, 1.0)).xyz;
v_Uv = Vertex_Uv;
gl_Position = ViewProj * v_Position;
gl_Position = ViewProj * vec4(v_Position, 1.0);
}

View file

@ -1,6 +1,6 @@
#version 450
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;

View file

@ -1,10 +1,10 @@
#version 450
layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal;
layout(location = 2) in vec2 a_Uv;
layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec4 v_Position;
layout(location = 0) out vec3 v_Position;
layout(location = 1) out vec3 v_Normal;
layout(location = 2) out vec2 v_Uv;
@ -21,7 +21,7 @@ layout(set = 1, binding = 1) uniform StandardMaterial_albedo {
};
void main() {
v_Normal = mat3(Model) * vec3(a_Normal.xyz);
v_Position = Model * a_Pos;
v_Normal = (Model * vec4(Vertex_Normal, 1.0)).xyz;
v_Position = (Model * vec4(Vertex_Position, 1.0)).xyz;
gl_Position = ViewProj * v_Position;
}

View file

@ -1,7 +1,7 @@
#version 450
layout(location = 0) in vec4 Vertex_Position;
layout(location = 1) in vec4 Vertex_Normal;
layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;
layout (location = 3) in vec2 I_Rect_Position;
@ -17,7 +17,7 @@ layout(set = 0, binding = 0) uniform Camera2d {
void main() {
v_Color = I_Rect_Color;
vec4 position = Vertex_Position * vec4(I_Rect_Size, 0.0, 1.0);
vec3 position = Vertex_Position * vec3(I_Rect_Size, 0.0);
position = position + vec4(I_Rect_Position + I_Rect_Size / 2.0, -I_Rect_ZIndex, 0.0);
gl_Position = ViewProj * position;
gl_Position = ViewProj * vec4(position, 1.0);
}

View file

@ -1,9 +1,9 @@
use super::VertexFormat;
use std::collections::HashMap;
use std::{borrow::Cow, collections::HashMap};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VertexBufferDescriptor {
pub name: String,
pub name: Cow<'static, str>,
pub stride: u64,
pub step_mode: InputStepMode,
pub attributes: Vec<VertexAttributeDescriptor>,
@ -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,

View file

@ -18,7 +18,7 @@ pub fn camera_resource_provider_system(resources: &mut Resources) -> Box<dyn Sch
let mut camera_buffer = None;
let mut tmp_buffer = None;
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
SystemBuilder::new("mesh_resource_provider")
SystemBuilder::new("camera_resource_provider")
.read_resource::<GlobalRenderResourceContext>()
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
.write_resource::<RenderResourceAssignments>()

View file

@ -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<dyn Schedulable> {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().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::<GlobalRenderResourceContext>()
.read_resource::<AssetStorage<Mesh>>()
.write_resource::<AssetBatchers>()
.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::<Mesh>() {
for batch in batches {
@ -35,20 +37,22 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
)
} else {
let mesh_asset = meshes.get(&handle).unwrap();
let vertex_bytes = mesh_asset.get_vertex_buffer_bytes(&vertex_buffer_descriptor).unwrap();
// TODO: use a staging buffer here
let vertex_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::VERTEX,
..Default::default()
},
mesh_asset.vertices.as_bytes(),
&vertex_bytes,
);
let index_bytes = mesh_asset.get_index_buffer_bytes(index_format).unwrap();
let index_buffer = render_resources.create_buffer_with_data(
BufferInfo {
buffer_usage: BufferUsage::INDEX,
..Default::default()
},
mesh_asset.indices.as_bytes(),
&index_bytes,
);
render_resources.set_asset_resource(

View file

@ -32,6 +32,7 @@ pub fn glsl_to_spirv(
options.add_macro_definition(shader_def.as_str(), None);
}
}
let binary_result = compiler
.compile_into_spirv(
glsl_source,

View file

@ -98,7 +98,7 @@ impl ShaderLayout {
current_descriptor = Some(VertexBufferDescriptor {
attributes: vec![vertex_attribute_descriptor],
name: current_buffer_name,
name: current_buffer_name.into(),
step_mode: if instance {
InputStepMode::Instance
} else {
@ -142,7 +142,7 @@ fn reflect_vertex_attribute_descriptor(
input_variable: &ReflectInterfaceVariable,
) -> 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,

View file

@ -19,31 +19,31 @@ static VERTEX_BUFFER_DESCRIPTOR: Lazy<VertexBufferDescriptor> =
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,
});

View file

@ -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],
}
}
}
}

View file

@ -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::<Windows>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();

View file

@ -14,7 +14,7 @@ pub fn setup(world: &mut World, resources: &mut Resources) {
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -153,8 +153,8 @@ fn setup(world: &mut World, resources: &mut Resources) {
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.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),

View file

@ -61,7 +61,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -33,8 +33,8 @@ fn setup(world: &mut World, resources: &mut Resources) {
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -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();
}

View file

@ -29,7 +29,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
.get_mut::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -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::<AssetStorage<Mesh>>().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

View file

@ -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::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let cube_handle = mesh_storage.add(Mesh::from(shape::Cube));
world
.build()

View file

@ -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::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
let cube_handle = mesh_storage.add(Mesh::from(shape::Cube));
world
.build()

View file

@ -33,8 +33,8 @@ fn setup(world: &mut World, resources: &mut Resources) {
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -15,7 +15,7 @@ pub fn startup_system() -> Box<dyn Schedulable> {
.write_resource::<AssetStorage<Mesh>>()
.write_resource::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -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::<AssetStorage<Mesh>>().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),
}));

View file

@ -12,7 +12,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
let mut material_storage = resources
.get_mut::<AssetStorage<StandardMaterial>>()
.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()

View file

@ -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")]

View file

@ -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},