Simple normal map implementation
This commit is contained in:
BIN
models/plane.glb
BIN
models/plane.glb
Binary file not shown.
@@ -15,13 +15,14 @@ layout(binding = 2) uniform sampler2D normal_tex;
|
|||||||
layout(location = 0) in vec2 tex_coords;
|
layout(location = 0) in vec2 tex_coords;
|
||||||
layout(location = 1) in vec3 normal_wld;
|
layout(location = 1) in vec3 normal_wld;
|
||||||
layout(location = 2) in vec3 position_wld;
|
layout(location = 2) in vec3 position_wld;
|
||||||
|
layout(location = 3) in mat3 tbn;
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// vec3 normal_cam_u = normalize(normal_wld); // TODO
|
|
||||||
vec3 normal_cam_u = texture(normal_tex, tex_coords).rgb;
|
vec3 normal_cam_u = texture(normal_tex, tex_coords).rgb;
|
||||||
normal_cam_u = normalize(normal_cam_u * 2.0 - 1.0);
|
normal_cam_u = normal_cam_u * 2.0 - 1.0;
|
||||||
|
normal_cam_u = normalize(tbn * normal_cam_u);
|
||||||
vec3 light_direction_cam_u = normalize(ubo.light_position - position_wld);
|
vec3 light_direction_cam_u = normalize(ubo.light_position - position_wld);
|
||||||
|
|
||||||
float ambient_strength = 0.1;
|
float ambient_strength = 0.1;
|
||||||
|
|||||||
@@ -16,21 +16,35 @@ layout(binding = 0) uniform ObjectUniformData {
|
|||||||
layout(location = 0) in vec3 position;
|
layout(location = 0) in vec3 position;
|
||||||
layout(location = 1) in vec2 uv;
|
layout(location = 1) in vec2 uv;
|
||||||
layout(location = 2) in vec3 normal;
|
layout(location = 2) in vec3 normal;
|
||||||
layout(location = 3) in ivec4 bone_index;
|
layout(location = 3) in vec4 tangent;
|
||||||
layout(location = 4) in vec4 bone_weight;
|
layout(location = 4) in ivec4 bone_index;
|
||||||
|
layout(location = 5) in vec4 bone_weight;
|
||||||
|
|
||||||
layout(location = 0) out vec2 tex_coords;
|
layout(location = 0) out vec2 tex_coords;
|
||||||
layout(location = 1) out vec3 normal_wld;
|
layout(location = 1) out vec3 normal_wld;
|
||||||
layout(location = 2) out vec3 position_wld;
|
layout(location = 2) out vec3 position_wld;
|
||||||
|
layout(location = 3) out mat3 tbn;
|
||||||
|
|
||||||
out gl_PerVertex {
|
out gl_PerVertex {
|
||||||
vec4 gl_Position;
|
vec4 gl_Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
// Vertex position
|
||||||
gl_Position = ubo.projection * ubo.view * push.model * vec4(position, 1.0);
|
gl_Position = ubo.projection * ubo.view * push.model * vec4(position, 1.0);
|
||||||
|
position_wld = vec3(push.model * vec4(position, 1.0));
|
||||||
|
|
||||||
|
// Just interpolate UV coords, no transformation needed
|
||||||
tex_coords = uv;
|
tex_coords = uv;
|
||||||
|
|
||||||
position_wld = vec3(push.model * vec4(position, 1.0));
|
// This should probably be in object space? idk
|
||||||
normal_wld = vec3(mat3(transpose(inverse(push.model))) * normal);
|
normal_wld = vec3(mat3(transpose(inverse(push.model))) * normal);
|
||||||
|
|
||||||
|
// Tangent->object space matrix
|
||||||
|
vec3 tangent3 = vec3(tangent.xy, 1.0);
|
||||||
|
vec3 bitangent = -cross(tangent3, normal_wld);
|
||||||
|
vec3 t = normalize(vec3(push.model * vec4(tangent3, 0.0)));
|
||||||
|
vec3 b = normalize(vec3(push.model * vec4(bitangent, 0.0)));
|
||||||
|
vec3 n = normalize(vec3(push.model * vec4(normal_wld, 0.0)));
|
||||||
|
tbn = mat3(t, b, n);
|
||||||
}
|
}
|
||||||
10
src/main.rs
10
src/main.rs
@@ -104,11 +104,11 @@ fn _matrix_vector_mul(matrix: &Matrix4<f32>, vector: &Vector3<f32>) -> Vector3<f
|
|||||||
|
|
||||||
impl TestGame {
|
impl TestGame {
|
||||||
fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) {
|
fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) {
|
||||||
let cube = self.add_from_gltf(renderer, "models/box.glb");
|
// let cube = self.add_from_gltf(renderer, "models/box.glb");
|
||||||
cube.get_game_object(renderer).unwrap().position = vec3(3.0, 4.0, 5.0);
|
// cube.get_game_object(renderer).unwrap().position = vec3(3.0, 4.0, 5.0);
|
||||||
|
//
|
||||||
let sphere = self.add_from_gltf(renderer, "models/sphere.glb");
|
// let sphere = self.add_from_gltf(renderer, "models/sphere.glb");
|
||||||
sphere.get_game_object(renderer).unwrap().position = vec3(0.0, 0.0, 0.0);
|
// sphere.get_game_object(renderer).unwrap().position = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
let plane = self.add_from_gltf(renderer, "models/plane.glb");
|
let plane = self.add_from_gltf(renderer, "models/plane.glb");
|
||||||
plane.get_game_object(renderer).unwrap().position = vec3(0.0, -1.0, 0.0);
|
plane.get_game_object(renderer).unwrap().position = vec3(0.0, -1.0, 0.0);
|
||||||
|
|||||||
40
src/mesh.rs
40
src/mesh.rs
@@ -1,9 +1,10 @@
|
|||||||
use crate::vulkan::Vertex;
|
|
||||||
|
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use gltf::mesh::util::{ReadPositions, ReadTexCoords, ReadNormals, ReadJoints, ReadWeights};
|
|
||||||
use gltf::Error;
|
use gltf::Error;
|
||||||
|
use gltf::mesh::util::{ReadJoints, ReadNormals, ReadPositions, ReadTangents, ReadTexCoords, ReadWeights};
|
||||||
|
|
||||||
use crate::mesh::LoadError::{GltfError, MeshDataMissing, NoIndices};
|
use crate::mesh::LoadError::{GltfError, MeshDataMissing, NoIndices};
|
||||||
|
use crate::vulkan::Vertex;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoadError {
|
pub enum LoadError {
|
||||||
@@ -52,9 +53,16 @@ pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<(Vec<CPUMesh>, V
|
|||||||
let texture_index = primitive.material().pbr_metallic_roughness().base_color_texture().map(|tex_info| tex_info.texture().index());
|
let texture_index = primitive.material().pbr_metallic_roughness().base_color_texture().map(|tex_info| tex_info.texture().index());
|
||||||
let normal_map_index = primitive.material().normal_texture().map(|tex_info| tex_info.texture().index());
|
let normal_map_index = primitive.material().normal_texture().map(|tex_info| tex_info.texture().index());
|
||||||
|
|
||||||
|
|
||||||
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
|
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
|
||||||
let indices = reader.read_indices().ok_or(NoIndices)?;
|
let indices = reader.read_indices().ok_or(NoIndices)?;
|
||||||
let vertices_result = create_vertices(reader.read_positions(), reader.read_tex_coords(0), reader.read_normals(), reader.read_joints(0), reader.read_weights(0));
|
let vertices_result = create_vertices(
|
||||||
|
reader.read_positions(),
|
||||||
|
reader.read_tex_coords(0),
|
||||||
|
reader.read_normals(),
|
||||||
|
reader.read_tangents(),
|
||||||
|
reader.read_joints(0),
|
||||||
|
reader.read_weights(0));
|
||||||
let vertices = vertices_result?;
|
let vertices = vertices_result?;
|
||||||
let cpu_mesh = CPUMesh {
|
let cpu_mesh = CPUMesh {
|
||||||
vertices,
|
vertices,
|
||||||
@@ -90,18 +98,21 @@ pub fn load_mesh(mesh_path: &str, print_status: bool) -> Result<(Vec<CPUMesh>, V
|
|||||||
fn create_vertices(positions: Option<ReadPositions>,
|
fn create_vertices(positions: Option<ReadPositions>,
|
||||||
tex_coords: Option<ReadTexCoords>,
|
tex_coords: Option<ReadTexCoords>,
|
||||||
normals: Option<ReadNormals>,
|
normals: Option<ReadNormals>,
|
||||||
|
tangents: Option<ReadTangents>,
|
||||||
joints: Option<ReadJoints>,
|
joints: Option<ReadJoints>,
|
||||||
weights: Option<ReadWeights>)
|
weights: Option<ReadWeights>)
|
||||||
-> Result<Vec<Vertex>, String> {
|
-> Result<Vec<Vertex>, String> {
|
||||||
match (positions, tex_coords, normals, joints, weights) {
|
match (positions, tex_coords, normals, tangents, joints, weights) {
|
||||||
(Some(positions),
|
(Some(positions),
|
||||||
Some(tex_coords),
|
Some(tex_coords),
|
||||||
Some(normals),
|
Some(normals),
|
||||||
|
Some(tangents),
|
||||||
Some(joints),
|
Some(joints),
|
||||||
Some(weights)) => {
|
Some(weights)) => {
|
||||||
Ok(positions
|
Ok(positions
|
||||||
.zip(tex_coords.into_f32())
|
.zip(tex_coords.into_f32())
|
||||||
.zip(normals)
|
.zip(normals)
|
||||||
|
.zip(tangents)
|
||||||
.zip(joints.into_u16().map(|arr| {
|
.zip(joints.into_u16().map(|arr| {
|
||||||
let mut casted_joints: [i32; 4] = [0; 4];
|
let mut casted_joints: [i32; 4] = [0; 4];
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
@@ -110,10 +121,11 @@ fn create_vertices(positions: Option<ReadPositions>,
|
|||||||
casted_joints
|
casted_joints
|
||||||
}))
|
}))
|
||||||
.zip(weights.into_f32())
|
.zip(weights.into_f32())
|
||||||
.map(|((((p, t), n), i), w)| Vertex {
|
.map(|(((((p, t), n), ta), i), w)| Vertex {
|
||||||
position: p,
|
position: p,
|
||||||
uv: t,
|
uv: t,
|
||||||
normal: n,
|
normal: n,
|
||||||
|
tangent: ta,
|
||||||
bone_index: i,
|
bone_index: i,
|
||||||
bone_weight: w
|
bone_weight: w
|
||||||
}).collect())
|
}).collect())
|
||||||
@@ -121,22 +133,26 @@ fn create_vertices(positions: Option<ReadPositions>,
|
|||||||
(Some(positions),
|
(Some(positions),
|
||||||
Some(tex_coords),
|
Some(tex_coords),
|
||||||
Some(normals),
|
Some(normals),
|
||||||
|
Some(tangents),
|
||||||
None, None) => {
|
None, None) => {
|
||||||
Ok(positions
|
Ok(positions
|
||||||
.zip(tex_coords.into_f32())
|
.zip(tex_coords.into_f32())
|
||||||
.zip(normals)
|
.zip(normals)
|
||||||
.map(|((p, t), n)| Vertex {
|
.zip(tangents)
|
||||||
|
.map(|(((p, t), n), ta)| Vertex {
|
||||||
position: p,
|
position: p,
|
||||||
uv: t,
|
uv: t,
|
||||||
normal: n,
|
normal: n,
|
||||||
|
tangent: ta,
|
||||||
bone_index: [-1; 4],
|
bone_index: [-1; 4],
|
||||||
bone_weight: [0.0; 4]
|
bone_weight: [0.0; 4]
|
||||||
}).collect())
|
}).collect())
|
||||||
},
|
},
|
||||||
(None, _, _, _, _) => Err("Vertex positions missing!".to_string()),
|
(None, _, _, _, _, _) => Err("Vertex positions missing!".to_string()),
|
||||||
(_, None, _, _, _) => Err("Tex coords missing!".to_string()),
|
(_, None, _, _, _, _) => Err("Tex coords missing!".to_string()),
|
||||||
(_, _, None, _, _) => Err("Normals missing!".to_string()),
|
(_, _, None, _, _, _) => Err("Normals missing!".to_string()),
|
||||||
(_, _, _, Some(_), None) => Err("Bone indices exist, but bone weights are missing!".to_string()),
|
(_, _, _, None, _, _) => Err("Tangents missing!".to_string()),
|
||||||
(_, _, _, None, Some(_)) => Err("Bone weights exist, but bone incides are missing!".to_string()),
|
(_, _, _, _, Some(_), None) => Err("Bone indices exist, but bone weights are missing!".to_string()),
|
||||||
|
(_, _, _, _, None, Some(_)) => Err("Bone weights exist, but bone incides are missing!".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,8 +30,8 @@ use winit::window::{Window, WindowBuilder};
|
|||||||
use line_vs::ty::LinePushConstants;
|
use line_vs::ty::LinePushConstants;
|
||||||
use vs::ty::PushConstants;
|
use vs::ty::PushConstants;
|
||||||
|
|
||||||
use crate::mesh::CPUMesh;
|
|
||||||
use crate::gameobject::{GameObject, GameObjectHandle};
|
use crate::gameobject::{GameObject, GameObjectHandle};
|
||||||
|
use crate::mesh::CPUMesh;
|
||||||
|
|
||||||
const VALIDATION_LAYERS: &[&str] = &[
|
const VALIDATION_LAYERS: &[&str] = &[
|
||||||
];
|
];
|
||||||
@@ -41,10 +41,11 @@ pub struct Vertex {
|
|||||||
pub position: [f32; 3],
|
pub position: [f32; 3],
|
||||||
pub uv: [f32; 2],
|
pub uv: [f32; 2],
|
||||||
pub normal: [f32; 3],
|
pub normal: [f32; 3],
|
||||||
|
pub tangent: [f32; 4],
|
||||||
pub bone_index: [i32; 4],
|
pub bone_index: [i32; 4],
|
||||||
pub bone_weight: [f32; 4],
|
pub bone_weight: [f32; 4],
|
||||||
}
|
}
|
||||||
vulkano::impl_vertex!(Vertex, position, uv, normal, bone_index, bone_weight);
|
vulkano::impl_vertex!(Vertex, position, uv, normal, tangent, bone_index, bone_weight);
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct LinePoint {
|
pub struct LinePoint {
|
||||||
|
|||||||
Reference in New Issue
Block a user