mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Example on how to draw using custom mesh and shader (#1565)
I was looking into "lower level" rendering and I saw no example on how to do that. Yet, I think it's something relevant to show, so I set up a simple example on how to do that. I hope it's welcome. I'm not confident about the code and a review is definitely nice to have, especially because there are a few things that are not great. Specifically, I think it would be nice to see how to render with a completely custom set of attributes (position and color, in this case), but I couldn't manage to get it working without normals and uv. It makes sense if bevy Meshes need these two attributes, but I'm not sure about it. Co-authored-by: Alessandro Re <ale@ale-re.net> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
9186c4c8d2
commit
6ce57c85d6
3 changed files with 142 additions and 0 deletions
|
@ -97,6 +97,10 @@ path = "examples/hello_world.rs"
|
||||||
name = "contributors"
|
name = "contributors"
|
||||||
path = "examples/2d/contributors.rs"
|
path = "examples/2d/contributors.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "mesh"
|
||||||
|
path = "examples/2d/mesh.rs"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "many_sprites"
|
name = "many_sprites"
|
||||||
path = "examples/2d/many_sprites.rs"
|
path = "examples/2d/many_sprites.rs"
|
||||||
|
|
137
examples/2d/mesh.rs
Normal file
137
examples/2d/mesh.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
use bevy::{
|
||||||
|
prelude::*,
|
||||||
|
render::{
|
||||||
|
pipeline::{PipelineDescriptor, RenderPipeline},
|
||||||
|
shader::{ShaderStage, ShaderStages},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::build()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_startup_system(star.system())
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn star(
|
||||||
|
mut commands: Commands,
|
||||||
|
// We will add a new Mesh for the star being created
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
// A pipeline will be added with custom shaders
|
||||||
|
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
|
||||||
|
// Access to add new shaders
|
||||||
|
mut shaders: ResMut<Assets<Shader>>,
|
||||||
|
) {
|
||||||
|
// We first create a pipeline, which is the sequence of steps that are
|
||||||
|
// needed to get to pixels on the screen starting from a description of the
|
||||||
|
// geometries in the scene. Pipelines have fixed steps, which sometimes can
|
||||||
|
// be turned off (for instance, depth and stencil tests) and programmable
|
||||||
|
// steps, the vertex and fragment shaders, that we can customize writing
|
||||||
|
// shader programs.
|
||||||
|
|
||||||
|
let pipeline_handle = pipelines.add(PipelineDescriptor::default_config(ShaderStages {
|
||||||
|
// Vertex shaders are run once for every vertex in the mesh.
|
||||||
|
// Each vertex can have attributes associated to it (e.g. position,
|
||||||
|
// color, texture mapping). The output of a shader is per-vertex.
|
||||||
|
vertex: shaders.add(Shader::from_glsl(ShaderStage::Vertex, VERTEX_SHADER)),
|
||||||
|
// Fragment shaders are run for each pixel belonging to a triangle on
|
||||||
|
// the screen. Their output is per-pixel.
|
||||||
|
fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Let's define the mesh for the object we want to draw: a nice star.
|
||||||
|
// We will specify here what kind of topology is used to define the mesh,
|
||||||
|
// that is, how triangles are built from the vertices. We will use a
|
||||||
|
// triangle list, meaning that each vertex of the triangle has to be
|
||||||
|
// specified.
|
||||||
|
let mut star = Mesh::new(bevy::render::pipeline::PrimitiveTopology::TriangleList);
|
||||||
|
|
||||||
|
// Vertices need to have a position attribute. We will use the following
|
||||||
|
// vertices (I hope you can spot the star in the schema).
|
||||||
|
//
|
||||||
|
// 1
|
||||||
|
//
|
||||||
|
// 10 2
|
||||||
|
// 9 0 3
|
||||||
|
// 8 4
|
||||||
|
// 6
|
||||||
|
// 7 5
|
||||||
|
//
|
||||||
|
// These vertices are specificed in 3D space.
|
||||||
|
let mut v_pos = vec![[0.0, 0.0, 0.0]];
|
||||||
|
for i in 0..10 {
|
||||||
|
// Angle of each vertex is 1/10 of TAU, plus PI/2 for positioning vertex 0
|
||||||
|
let a = std::f32::consts::FRAC_PI_2 - i as f32 * std::f32::consts::TAU / 10.0;
|
||||||
|
// Radius of internal vertices (2, 4, 6, 8, 10) is 100, it's 200 for external
|
||||||
|
let r = (1 - i % 2) as f32 * 100.0 + 100.0;
|
||||||
|
// Add the vertex coordinates
|
||||||
|
v_pos.push([r * a.cos(), r * a.sin(), 0.0]);
|
||||||
|
}
|
||||||
|
// Set the position attribute
|
||||||
|
star.set_attribute(Mesh::ATTRIBUTE_POSITION, v_pos);
|
||||||
|
// And a RGB color attribute as well
|
||||||
|
let mut v_color = vec![[0.0, 0.0, 0.0]];
|
||||||
|
v_color.extend_from_slice(&[[1.0, 1.0, 0.0]; 10]);
|
||||||
|
star.set_attribute("Vertex_Color", v_color);
|
||||||
|
|
||||||
|
// Now, we specify the indices of the vertex that are going to compose the
|
||||||
|
// triangles in our star. Vertices in triangles have to be specified in CCW
|
||||||
|
// winding (that will be the front face, colored). Since we are using
|
||||||
|
// triangle list, we will specify each triangle as 3 vertices
|
||||||
|
// First triangle: 0, 2, 1
|
||||||
|
// Second triangle: 0, 3, 2
|
||||||
|
// Third triangle: 0, 4, 3
|
||||||
|
// etc
|
||||||
|
// Last triangle: 0, 1, 10
|
||||||
|
let mut indices = vec![0, 1, 10];
|
||||||
|
for i in 2..=10 {
|
||||||
|
indices.extend_from_slice(&[0, i, i - 1]);
|
||||||
|
}
|
||||||
|
star.set_indices(Some(bevy::render::mesh::Indices::U32(indices)));
|
||||||
|
|
||||||
|
// We can now spawn the entities for the star and the camera
|
||||||
|
commands.spawn_bundle(MeshBundle {
|
||||||
|
mesh: meshes.add(star),
|
||||||
|
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::new(
|
||||||
|
pipeline_handle,
|
||||||
|
)]),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
commands
|
||||||
|
// And use an orthographic projection
|
||||||
|
.spawn_bundle(OrthographicCameraBundle::new_2d());
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERTEX_SHADER: &str = r"
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 Vertex_Position;
|
||||||
|
layout(location = 1) in vec3 Vertex_Color;
|
||||||
|
|
||||||
|
layout(location = 1) out vec3 v_Color;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform CameraViewProj {
|
||||||
|
mat4 ViewProj;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform Transform {
|
||||||
|
mat4 Model;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
v_Color = Vertex_Color;
|
||||||
|
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
const FRAGMENT_SHADER: &str = r"
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 1) in vec3 v_Color;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_Target;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
o_Target = vec4(v_Color, 1.0);
|
||||||
|
}
|
||||||
|
";
|
|
@ -73,6 +73,7 @@ Example | Main | Description
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
`contributors` | [`2d/contributors.rs`](./2d/contributors.rs) | Displays each contributor as a bouncy bevy-ball!
|
`contributors` | [`2d/contributors.rs`](./2d/contributors.rs) | Displays each contributor as a bouncy bevy-ball!
|
||||||
`many_sprites` | [`2d/many_sprites.rs`](./2d/many_sprites.rs) | Displays many sprites in a grid arragement! Used for performance testing.
|
`many_sprites` | [`2d/many_sprites.rs`](./2d/many_sprites.rs) | Displays many sprites in a grid arragement! Used for performance testing.
|
||||||
|
`mesh` | [`2d/mesh.rs`](./2d/mesh.rs) | Renders a custom mesh
|
||||||
`sprite` | [`2d/sprite.rs`](./2d/sprite.rs) | Renders a sprite
|
`sprite` | [`2d/sprite.rs`](./2d/sprite.rs) | Renders a sprite
|
||||||
`sprite_sheet` | [`2d/sprite_sheet.rs`](./2d/sprite_sheet.rs) | Renders an animated sprite
|
`sprite_sheet` | [`2d/sprite_sheet.rs`](./2d/sprite_sheet.rs) | Renders an animated sprite
|
||||||
`text2d` | [`2d/text2d.rs`](./2d/text2d.rs) | Generates text in 2d
|
`text2d` | [`2d/text2d.rs`](./2d/text2d.rs) | Generates text in 2d
|
||||||
|
|
Loading…
Reference in a new issue