render: use left-handed coordinate system and y-up

This commit is contained in:
Carter Anderson 2020-06-24 15:29:10 -07:00
parent 4ba2f72572
commit 75429f4639
24 changed files with 185 additions and 120 deletions

Binary file not shown.

View file

@ -1,6 +1,6 @@
{
"asset" : {
"generator" : "Khronos glTF Blender I/O v1.1.46",
"generator" : "Khronos glTF Blender I/O v1.2.75",
"version" : "2.0"
},
"scene" : 0,
@ -37,63 +37,63 @@
{
"bufferView" : 0,
"componentType" : 5126,
"count" : 1968,
"count" : 3321,
"max" : [
1.3671875,
0.8515625,
0.984375
1.325934886932373,
0.9392361640930176,
0.8223199844360352
],
"min" : [
-1.3671875,
-0.8515625,
-0.984375
-1.325934886932373,
-0.9704862236976624,
-0.7782661318778992
],
"type" : "VEC3"
},
{
"bufferView" : 1,
"componentType" : 5126,
"count" : 1968,
"count" : 3321,
"type" : "VEC3"
},
{
"bufferView" : 2,
"componentType" : 5126,
"count" : 1968,
"count" : 3321,
"type" : "VEC2"
},
{
"bufferView" : 3,
"componentType" : 5123,
"count" : 2904,
"count" : 11808,
"type" : "SCALAR"
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 23616,
"byteLength" : 39852,
"byteOffset" : 0
},
{
"buffer" : 0,
"byteLength" : 39852,
"byteOffset" : 39852
},
{
"buffer" : 0,
"byteLength" : 26568,
"byteOffset" : 79704
},
{
"buffer" : 0,
"byteLength" : 23616,
"byteOffset" : 23616
},
{
"buffer" : 0,
"byteLength" : 15744,
"byteOffset" : 47232
},
{
"buffer" : 0,
"byteLength" : 5808,
"byteOffset" : 62976
"byteOffset" : 106272
}
],
"buffers" : [
{
"byteLength" : 68784,
"byteLength" : 129888,
"uri" : "Monkey.bin"
}
]

View file

@ -6,7 +6,7 @@ pub trait FaceToward {
impl FaceToward for Mat4 {
fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self {
let forward = (eye - center).normalize();
let forward = (center - eye).normalize();
let right = up.cross(forward).normalize();
let up = forward.cross(right);
Mat4::from_cols(

View file

@ -17,7 +17,7 @@ pub const FORWARD_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
pub fn build_forward_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
PipelineDescriptor {
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
front_face: FrontFace::Cw,
cull_mode: CullMode::Back,
depth_bias: 0,
depth_bias_slope_scale: 0.0,

View file

@ -17,8 +17,7 @@ pub struct PerspectiveProjection {
impl CameraProjection for PerspectiveProjection {
fn get_projection_matrix(&self) -> Mat4 {
let projection = Mat4::perspective_rh_gl(self.fov, self.aspect_ratio, self.near, self.far);
projection
Mat4::perspective_lh(self.fov, self.aspect_ratio, self.near, self.far)
}
fn update(&mut self, width: usize, height: usize) {
self.aspect_ratio = width as f32 / height as f32;
@ -56,15 +55,14 @@ pub struct OrthographicProjection {
impl CameraProjection for OrthographicProjection {
fn get_projection_matrix(&self) -> Mat4 {
let projection = Mat4::orthographic_rh(
Mat4::orthographic_lh(
self.left,
self.right,
self.bottom,
self.top,
self.near,
self.far,
);
projection
)
}
fn update(&mut self, width: usize, height: usize) {
match self.window_origin {
@ -93,8 +91,8 @@ impl Default for OrthographicProjection {
right: 0.0,
bottom: 0.0,
top: 0.0,
near: -1.0,
far: 0.1,
near: 0.0,
far: 1000.0,
window_origin: WindowOrigin::Center,
}
}

View file

@ -249,6 +249,17 @@ pub mod shape {
pub struct Quad {
pub size: Vec2,
pub flip: bool,
}
impl Quad {
pub fn new(size: Vec2) -> Self {
Self { size, flip: false }
}
pub fn flipped(size: Vec2) -> Self {
Self { size, flip: true }
}
}
impl From<Quad> for Mesh {
@ -260,28 +271,53 @@ pub mod shape {
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 vertices = if quad.flip {
[
(
[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],
),
]
} else {
[
(
[south_east.x(), south_east.y(), 0.0],
[0.0, 0.0, 1.0],
[1.0, 1.0],
),
(
[north_east.x(), north_east.y(), 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0],
),
(
[north_west.x(), north_west.y(), 0.0],
[0.0, 0.0, 1.0],
[0.0, 0.0],
),
(
[south_west.x(), south_west.y(), 0.0],
[0.0, 0.0, 1.0],
[0.0, 1.0],
),
]
};
let indices = vec![0, 2, 1, 0, 3, 2];
@ -312,10 +348,51 @@ pub mod shape {
impl From<Plane> for Mesh {
fn from(plane: Plane) -> Self {
Quad {
size: Vec2::new(plane.size, plane.size),
let extent = plane.size / 2.0;
let vertices = [
(
[extent, 0.0, -extent],
[0.0, 1.0, 0.0],
[1.0, 1.0],
),
(
[extent, 0.0, extent],
[0.0, 1.0, 0.0],
[1.0, 0.0],
),
(
[-extent, 0.0, extent],
[0.0, 1.0, 0.0],
[0.0, 0.0],
),
(
[-extent, 0.0, -extent],
[0.0, 1.0, 0.0],
[0.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::TriangleList,
attributes: vec![
VertexAttribute::position(positions),
VertexAttribute::normal(normals),
VertexAttribute::uv(uvs),
],
indices: Some(indices),
}
.into()
}
}
}

View file

@ -72,7 +72,7 @@ impl PipelineDescriptor {
sample_mask: !0,
alpha_to_coverage_enabled: false,
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
front_face: FrontFace::Cw,
cull_mode: CullMode::Back,
depth_bias: 0,
depth_bias_slope_scale: 0.0,

View file

@ -74,7 +74,7 @@ pub enum FrontFace {
impl Default for FrontFace {
fn default() -> Self {
FrontFace::Ccw
FrontFace::Cw
}
}

View file

@ -50,9 +50,8 @@ impl AppPlugin for SpritePlugin {
let mut meshes = resources.get_mut::<Assets<Mesh>>().unwrap();
meshes.set(
QUAD_HANDLE,
Mesh::from(shape::Quad {
size: Vec2::new(1.0, 1.0),
}),
// Use a flipped quad because the camera is facing "forward" but quads should face backward
Mesh::from(shape::Quad::flipped(Vec2::new(1.0, 1.0))),
);
let mut color_materials = resources.get_mut::<Assets<ColorMaterial>>().unwrap();

View file

@ -21,7 +21,7 @@ pub const SPRITE_SHEET_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
pub fn build_sprite_sheet_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
PipelineDescriptor {
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
front_face: FrontFace::Cw,
cull_mode: CullMode::None,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
@ -66,7 +66,7 @@ pub fn build_sprite_sheet_pipeline(shaders: &mut Assets<Shader>) -> PipelineDesc
pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
PipelineDescriptor {
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
front_face: FrontFace::Cw,
cull_mode: CullMode::None,
depth_bias: 0,
depth_bias_slope_scale: 0.0,

View file

@ -10,11 +10,6 @@ impl Rotation {
pub fn identity() -> Self {
Self(Quat::identity())
}
#[inline(always)]
pub fn from_euler_angles(yaw: f32, pitch: f32, roll: f32) -> Self {
Self(Quat::from_rotation_ypr(yaw, pitch, roll))
}
}
impl Default for Rotation {

View file

@ -14,7 +14,7 @@ pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
pub fn build_ui_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
PipelineDescriptor {
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,
front_face: FrontFace::Cw,
cull_mode: CullMode::None,
depth_bias: 0,
depth_bias_slope_scale: 0.0,

View file

@ -6,7 +6,7 @@ use bevy_window::Windows;
use glam::Vec2;
use legion::{prelude::*, systems::SubWorld};
pub const UI_Z_STEP: f32 = 0.0001;
pub const UI_Z_STEP: f32 = 0.001;
pub fn ui_update_system() -> Box<dyn Schedulable> {
SystemBuilder::new("ui_update")
@ -20,7 +20,7 @@ pub fn ui_update_system() -> Box<dyn Schedulable> {
let mut window_quad = Quad {
size: Vec2::new(window.width as f32, window.height as f32),
position: Vec2::new(0.0, 0.0),
z_index: 0.0,
z_index: 999.0,
};
for entity in node_query
.iter_entities(world)
@ -57,7 +57,7 @@ fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_quad: Quad) -
return Some(Quad {
size: quad.size,
position: quad.position - quad.size / 2.0,
z_index: quad.z_index + UI_Z_STEP,
z_index: quad.z_index - UI_Z_STEP,
});
}
}
@ -69,6 +69,6 @@ fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_quad: Quad) -
fn process_child_result(_parent_result: Quad, child_result: Quad) -> Quad {
// "earlier" children are sorted behind "later" children
let mut result = child_result.clone();
result.z_index += UI_Z_STEP;
result.z_index -= UI_Z_STEP;
result
}

View file

@ -40,20 +40,20 @@ fn setup(
.add_entity(MeshEntity {
mesh: cube_handle,
material: cube_material_handle,
translation: Translation::new(0.0, 0.0, 1.0),
translation: Translation::new(0.0, 1.0, 0.0),
..Default::default()
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
translation: Translation::new(4.0, 5.0, -4.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(3.0, 5.0, 8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -34,15 +34,15 @@ fn setup(
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
translation: Translation::new(4.0, 5.0, 4.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(2.0, -6.0, 2.0),
Vec3::new(-2.0, 2.0, 6.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -48,7 +48,7 @@ fn setup(
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
translation: Translation::new(4.0, 5.0, -4.0),
..Default::default()
})
// camera
@ -56,7 +56,7 @@ fn setup(
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(5.0, 10.0, 10.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -64,9 +64,9 @@ fn setup(
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(3.0, 5.0, -8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});
@ -85,9 +85,9 @@ fn setup(
mesh: cube_handle,
material: spawned_material_handle,
translation: Translation::new(
rng.gen_range(-50.0, 50.0),
rng.gen_range(-50.0, 50.0),
0.0,
rng.gen_range(-50.0, 50.0),
),
..Default::default()
});

View file

@ -24,9 +24,10 @@ fn setup(
// create a new quad mesh. this is what we will apply the texture to
let quad_width = 8.0;
let quad_handle = meshes.add(Mesh::from(shape::Quad {
size: Vec2::new(quad_width, quad_width * aspect),
}));
let quad_handle = meshes.add(Mesh::from(shape::Quad::new(Vec2::new(
quad_width,
quad_width * aspect,
))));
// this material renders the texture normally
let material_handle = materials.add(StandardMaterial {
@ -58,8 +59,8 @@ fn setup(
.add_entity(MeshEntity {
mesh: quad_handle,
material: material_handle,
translation: Translation::new(0.0, -1.5, 0.0),
rotation: Rotation::from_euler_angles(0.0, std::f32::consts::PI / 3.0, 0.0),
translation: Translation::new(0.0, 0.0, -1.5),
rotation: Rotation(Quat::from_rotation_x(std::f32::consts::PI / 5.0)),
draw: Draw {
is_transparent: true,
..Default::default()
@ -71,7 +72,7 @@ fn setup(
mesh: quad_handle,
material: red_material_handle,
translation: Translation::new(0.0, 0.0, 0.0),
rotation: Rotation::from_euler_angles(0.0, std::f32::consts::PI / 3.0, 0.0),
rotation: Rotation(Quat::from_rotation_x(std::f32::consts::PI / 5.0)),
draw: Draw {
is_transparent: true,
..Default::default()
@ -82,8 +83,8 @@ fn setup(
.add_entity(MeshEntity {
mesh: quad_handle,
material: blue_material_handle,
translation: Translation::new(0.0, 1.5, 0.0),
rotation: Rotation::from_euler_angles(0.0, std::f32::consts::PI / 3.0, 0.0),
translation: Translation::new(0.0, 0.0, 1.5),
rotation: Rotation(Quat::from_rotation_x(std::f32::consts::PI / 5.0)),
draw: Draw {
is_transparent: true,
..Default::default()
@ -93,9 +94,9 @@ fn setup(
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, -8.0, 5.0),
Vec3::new(3.0, 5.0, -8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -64,7 +64,7 @@ fn setup(
shaded: false,
..Default::default()
}),
translation: Translation::new(0.0, 0.0, 3.0),
translation: Translation::new(0.0, 3.0, 0.0),
..Default::default()
})
.add_entity(MeshEntity {
@ -73,21 +73,16 @@ fn setup(
shaded: false,
..Default::default()
}),
translation: Translation::new(0.0, 0.0, -3.0),
translation: Translation::new(0.0, -3.0, 0.0),
..Default::default()
})
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(5.0, 10.0, 10.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -30,15 +30,15 @@ fn setup(
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
translation: Translation::new(4.0, 5.0, 4.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(3.0, 5.0, 8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -67,15 +67,15 @@ fn setup(
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
translation: Translation::new(4.0, 5.0, 4.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(0.0, -10.0, 3.0),
Vec3::new(0.0, 3.0, 10.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -42,15 +42,15 @@ fn setup(
})
// light
.add_entity(LightEntity {
translation: Translation::new(4.0, -4.0, 5.0),
translation: Translation::new(4.0, 5.0, 4.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(2.0, -6.0, 2.0),
Vec3::new(2.0, 2.0, 6.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -104,9 +104,9 @@ fn setup(
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(3.0, 5.0, -8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});

View file

@ -82,7 +82,7 @@ fn setup(
});
// Create a blue material, which uses our "always_blue" shader def
let red_material = materials.add(MyMaterial {
let blue_material = materials.add(MyMaterial {
color: Color::rgb(0.0, 0.0, 0.0),
always_blue: true,
});
@ -140,16 +140,16 @@ fn setup(
..Default::default()
},
)]),
material: red_material,
material: blue_material,
translation: Translation::new(2.0, 0.0, 0.0),
..Default::default()
})
// camera
.add_entity(PerspectiveCameraEntity {
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(3.0, 5.0, -8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});