Skip to content

Commit

Permalink
Fix instanced mesh per vertex shading + reuse shader code between Ins…
Browse files Browse the repository at this point in the history
…tancedMeshProgram and MeshProgram
  • Loading branch information
asny committed Mar 12, 2021
1 parent 4232f74 commit d2d3780
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 120 deletions.
94 changes: 9 additions & 85 deletions src/object/instanced_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ use crate::math::*;
use crate::definition::*;
use crate::core::*;
use crate::camera::*;
use crate::object::mesh::*;

///
/// A shader program used for rendering one or more instances of a [InstancedMesh](InstancedMesh). It has a fixed vertex shader and
/// customizable fragment shader for custom lighting. Use this in combination with [render](InstancedMesh::render).
///
pub struct InstancedMeshProgram {
program: Program,
use_normals: bool,
use_uvs: bool,
mesh_program: MeshProgram,
}

impl InstancedMeshProgram {
Expand All @@ -20,70 +19,15 @@ impl InstancedMeshProgram {
/// its normal by `in vec3 nor;`, its uv coordinates by `in vec2 uvs;` and its per vertex color by `in vec4 col;` to the shader source code.
///
pub fn new(context: &Context, fragment_shader_source: &str) -> Result<Self, Error> {
let use_positions = fragment_shader_source.find("in vec3 pos;").is_some();
let use_normals = fragment_shader_source.find("in vec3 nor;").is_some();
let use_uvs = fragment_shader_source.find("in vec2 uvs;").is_some();
let vertex_shader_source = &format!("
layout (std140) uniform Camera
{{
mat4 viewProjection;
mat4 view;
mat4 projection;
vec3 position;
float padding;
}} camera;
uniform mat4 modelMatrix;
in vec3 position;
in vec4 row1;
in vec4 row2;
in vec4 row3;
{} // Positions out
{} // Normals in/out
{} // UV coordinates in/out
void main()
{{
mat4 transform;
transform[0] = vec4(row1.x, row2.x, row3.x, 0.0);
transform[1] = vec4(row1.y, row2.y, row3.y, 0.0);
transform[2] = vec4(row1.z, row2.z, row3.z, 0.0);
transform[3] = vec4(row1.w, row2.w, row3.w, 1.0);
vec4 worldPosition = modelMatrix * transform * vec4(position, 1.);
gl_Position = camera.viewProjection * worldPosition;
{} // Position
{} // Normal
{} // UV coordinates
}}
",
if use_positions {"out vec3 pos;"} else {""},
if use_normals {
"uniform mat4 normalMatrix;
in vec3 normal;
out vec3 nor;"
} else {""},
if use_uvs {
"in vec2 uv_coordinates;
out vec2 uvs;"
} else {""},
if use_positions {"pos = worldPosition.xyz;"} else {""},
if use_normals { "nor = mat3(normalMatrix) * normal;" } else {""},
if use_uvs { "uvs = uv_coordinates;" } else {""}
);

let program = Program::from_source(context, vertex_shader_source, fragment_shader_source)?;
Ok(Self {program, use_normals, use_uvs})
Ok(Self {mesh_program: MeshProgram::new_internal(context, fragment_shader_source, true)?})
}
}

impl std::ops::Deref for InstancedMeshProgram {
type Target = Program;

fn deref(&self) -> &Program {
&self.program
&self.mesh_program
}
}

Expand Down Expand Up @@ -162,14 +106,7 @@ impl InstancedMesh
let program = unsafe {
if PROGRAM_PER_VERTEX_COLOR.is_none()
{
PROGRAM_PER_VERTEX_COLOR = Some(InstancedMeshProgram::new(&self.context,"
in vec4 col;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = col/255.0;
}
")?);
PROGRAM_PER_VERTEX_COLOR = Some(InstancedMeshProgram::new(&self.context,include_str!("shaders/mesh_vertex_color.frag"))?);
}
PROGRAM_PER_VERTEX_COLOR.as_ref().unwrap()
};
Expand All @@ -187,13 +124,7 @@ impl InstancedMesh
let program = unsafe {
if PROGRAM_COLOR.is_none()
{
PROGRAM_COLOR = Some(InstancedMeshProgram::new(&self.context, "
uniform vec4 color;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = color;
}")?);
PROGRAM_COLOR = Some(InstancedMeshProgram::new(&self.context, include_str!("shaders/mesh_color.frag"))?);
}
PROGRAM_COLOR.as_ref().unwrap()
};
Expand All @@ -215,14 +146,7 @@ impl InstancedMesh
let program = unsafe {
if PROGRAM_TEXTURE.is_none()
{
PROGRAM_TEXTURE = Some(InstancedMeshProgram::new(&self.context, "
uniform sampler2D tex;
in vec2 uvs;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = texture(tex, vec2(uvs.x, 1.0 - uvs.y));
}")?);
PROGRAM_TEXTURE = Some(InstancedMeshProgram::new(&self.context, include_str!("shaders/mesh_texture.frag"))?);
}
PROGRAM_TEXTURE.as_ref().unwrap()
};
Expand Down Expand Up @@ -251,12 +175,12 @@ impl InstancedMesh
program.use_uniform_block(camera.matrix_buffer(), "Camera");

program.use_attribute_vec3(&self.position_buffer, "position")?;
if program.use_uvs {
if program.mesh_program.use_uvs {
let uv_buffer = self.uv_buffer.as_ref().ok_or(
Error::FailedToCreateMesh {message: "The mesh shader program needs uv coordinates, but the mesh does not have any.".to_string()})?;
program.use_attribute_vec2(uv_buffer, "uv_coordinates")?;
}
if program.use_normals {
if program.mesh_program.use_normals {
let normal_buffer = self.normal_buffer.as_ref().ok_or(
Error::FailedToCreateMesh {message: "The mesh shader program needs normals, but the mesh does not have any. Consider calculating the normals on the CPUMesh.".to_string()})?;
program.use_uniform_mat4("normalMatrix", &transformation.invert().unwrap().transpose())?;
Expand Down
51 changes: 24 additions & 27 deletions src/object/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use crate::camera::*;
///
pub struct MeshProgram {
program: Program,
use_normals: bool,
use_uvs: bool,
use_colors: bool,
pub(in crate::object) use_normals: bool,
pub(in crate::object) use_uvs: bool,
pub(in crate::object) use_colors: bool
}

impl MeshProgram {
Expand All @@ -22,6 +22,10 @@ impl MeshProgram {
/// its normal by `in vec3 nor;`, its uv coordinates by `in vec2 uvs;` and its per vertex color by `in vec4 col;` to the shader source code.
///
pub fn new(context: &Context, fragment_shader_source: &str) -> Result<Self, Error> {
Self::new_internal(context, fragment_shader_source, false)
}

pub(in crate::object) fn new_internal(context: &Context, fragment_shader_source: &str, instanced: bool) -> Result<Self, Error> {
let use_positions = fragment_shader_source.find("in vec3 pos;").is_some();
let use_normals = fragment_shader_source.find("in vec3 nor;").is_some();
let use_uvs = fragment_shader_source.find("in vec2 uvs;").is_some();
Expand All @@ -39,21 +43,27 @@ impl MeshProgram {
uniform mat4 modelMatrix;
in vec3 position;
{} // Instancing
{} // Positions out
{} // Normals in/out
{} // UV coordinates in/out
{} // Colors in/out
void main()
{{
vec4 worldPosition = modelMatrix * vec4(position, 1.);
mat4 local2World = modelMatrix;
{} // Instancing
vec4 worldPosition = local2World * vec4(position, 1.);
gl_Position = camera.viewProjection * worldPosition;
{} // Position
{} // Normal
{} // UV coordinates
{} // Colors
}}
",
if instanced {"in vec4 row1;
in vec4 row2;
in vec4 row3;"} else {""},
if use_positions {"out vec3 pos;"} else {""},
if use_normals {
"uniform mat4 normalMatrix;
Expand All @@ -68,6 +78,13 @@ impl MeshProgram {
"in vec4 color;
out vec4 col;"
} else {""},
if instanced {"
mat4 transform;
transform[0] = vec4(row1.x, row2.x, row3.x, 0.0);
transform[1] = vec4(row1.y, row2.y, row3.y, 0.0);
transform[2] = vec4(row1.z, row2.z, row3.z, 0.0);
transform[3] = vec4(row1.w, row2.w, row3.w, 1.0);
local2World *= transform;"} else {""},
if use_positions {"pos = worldPosition.xyz;"} else {""},
if use_normals { "nor = mat3(normalMatrix) * normal;" } else {""},
if use_uvs { "uvs = uv_coordinates;" } else {""},
Expand Down Expand Up @@ -150,14 +167,7 @@ impl Mesh {
let program = unsafe {
if PROGRAM_PER_VERTEX_COLOR.is_none()
{
PROGRAM_PER_VERTEX_COLOR = Some(MeshProgram::new(&self.context,"
in vec4 col;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = col/255.0;
}
")?);
PROGRAM_PER_VERTEX_COLOR = Some(MeshProgram::new(&self.context,include_str!("shaders/mesh_vertex_color.frag"))?);
}
PROGRAM_PER_VERTEX_COLOR.as_ref().unwrap()
};
Expand All @@ -175,13 +185,7 @@ impl Mesh {
let program = unsafe {
if PROGRAM_COLOR.is_none()
{
PROGRAM_COLOR = Some(MeshProgram::new(&self.context, "
uniform vec4 color;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = color;
}")?);
PROGRAM_COLOR = Some(MeshProgram::new(&self.context, include_str!("shaders/mesh_color.frag"))?);
}
PROGRAM_COLOR.as_ref().unwrap()
};
Expand All @@ -203,14 +207,7 @@ impl Mesh {
let program = unsafe {
if PROGRAM_TEXTURE.is_none()
{
PROGRAM_TEXTURE = Some(MeshProgram::new(&self.context, "
uniform sampler2D tex;
in vec2 uvs;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = texture(tex, vec2(uvs.x, 1.0 - uvs.y));
}")?);
PROGRAM_TEXTURE = Some(MeshProgram::new(&self.context, include_str!("shaders/mesh_texture.frag"))?);
}
PROGRAM_TEXTURE.as_ref().unwrap()
};
Expand Down
9 changes: 9 additions & 0 deletions src/object/shaders/mesh_color.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

uniform vec4 color;

layout (location = 0) out vec4 outColor;

void main()
{
outColor = color;
}
11 changes: 11 additions & 0 deletions src/object/shaders/mesh_texture.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

uniform sampler2D tex;

in vec2 uvs;

layout (location = 0) out vec4 outColor;

void main()
{
outColor = texture(tex, vec2(uvs.x, 1.0 - uvs.y));
}
9 changes: 9 additions & 0 deletions src/object/shaders/mesh_vertex_color.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

in vec4 col;

layout (location = 0) out vec4 outColor;

void main()
{
outColor = col/255.0;
}
4 changes: 0 additions & 4 deletions src/phong/deferred_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ impl PhongDeferredMesh {

pub fn new(context: &Context, cpu_mesh: &CPUMesh, material: &PhongMaterial) -> Result<Self, Error>
{
if cpu_mesh.normals.is_none() {
Err(Error::FailedToCreateMesh {message:
"Cannot create a mesh without normals. Consider calling compute_normals on the CPUMesh before creating the mesh.".to_string()})?
}
let mesh = Mesh::new(context, cpu_mesh)?;
unsafe {MESH_COUNT += 1;}
Ok(Self {
Expand Down
4 changes: 0 additions & 4 deletions src/phong/forward_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ impl PhongForwardMesh
{
pub fn new(context: &Context, cpu_mesh: &CPUMesh, material: &PhongMaterial) -> Result<Self, Error>
{
if cpu_mesh.normals.is_none() {
Err(Error::FailedToCreateMesh {message:
"Cannot create a mesh without normals. Consider calling compute_normals on the CPUMesh before creating the mesh.".to_string()})?
}
let mesh = Mesh::new(context, cpu_mesh)?;
unsafe {
MESH_COUNT += 1;
Expand Down

0 comments on commit d2d3780

Please sign in to comment.