From a4878227908687ab961c2bdf4c0ab2a343ca5f18 Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Fri, 15 Jun 2018 17:36:51 +0200 Subject: [PATCH] Added support for Kd --- assets/shaders/shader.frag | 3 ++- src/model/material.rs | 5 ++++ src/parser/mod.rs | 41 +++++++++++++++++++--------- src/parser/mtl.rs | 14 +++++++++- src/parser/obj.rs | 55 +++++++++++++++++++------------------- src/renderer.rs | 8 ++++++ 6 files changed, 84 insertions(+), 42 deletions(-) diff --git a/assets/shaders/shader.frag b/assets/shaders/shader.frag index 1751f9e..bdebc2f 100644 --- a/assets/shaders/shader.frag +++ b/assets/shaders/shader.frag @@ -1,6 +1,7 @@ #version 140 uniform sampler2D tex; +uniform vec3 diffuse; in vec3 v_normal; in vec2 v_tex_coords; @@ -18,7 +19,7 @@ void main() { vec4 factor = vec4(ambientLight + lambertComponent, 1.0); - color = factor * texture(tex, v_tex_coords); + color = factor * vec4(diffuse, 1.0) * texture(tex, v_tex_coords); if (color.a < 0.05) { discard; diff --git a/src/model/material.rs b/src/model/material.rs index 25e1fdc..dd65134 100644 --- a/src/model/material.rs +++ b/src/model/material.rs @@ -1,6 +1,7 @@ //! This module contains everything related to materials. use std::collections::HashMap; +use math::vector::Vector3; /// A 3D material. #[derive(Clone)] @@ -9,6 +10,9 @@ pub struct Material { /// The name of the material. pub name: String, + /// The diffuse color of the material. + pub diffuse: Vector3, + /// Map linking each texture map to its file path. pub textures: HashMap, @@ -24,6 +28,7 @@ impl Material { pub fn new(name: &str) -> Material { Material { name: name.to_owned(), + diffuse: Vector3::new(1.0, 1.0, 1.0), textures: HashMap::new(), unknown_instructions: vec![], } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2021ba7..fc1f916 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -49,7 +49,7 @@ pub enum Element { Texture(String, String), /// Change the main color of the current material. - Color(Vector3), + Diffuse(Vector3), /// An unknown material instruction that will be copied into the mtl file. UnknownMaterialInstruction(String), @@ -102,11 +102,10 @@ pub enum ParserError { /// String is the name of the material that is already defined. MaterialAlreadyExists(String, usize, String), - /// Texture arrived before creating a material. + /// Some material information arrived before creating a material. /// /// usize is the line. - /// String is the path to the texture. - NoMaterialExist(String, usize, String), + NoMaterialExist(String, usize), /// Something weird happened OtherError(String), @@ -174,8 +173,8 @@ impl fmt::Display for ParserError { write!(f, "Index out of bound in {}:{}:\n\tsize is {} but got {}", p, l, i, s), ParserError::MaterialAlreadyExists(ref p, l, ref n) => write!(f, "Redecralation of material in {}:{}:\n\t{} already exists", p, n, l), - ParserError::NoMaterialExist(ref p, l, ref n) => - write!(f, "Missing material in {}:{}\n\tNo material were defined, can't set {} as textuure", p, l, n), + ParserError::NoMaterialExist(ref p, l) => + write!(f, "Missing material in {}:{}\n\tNo material were defined, can't set attribute", p, l), ParserError::OtherError(ref p) => write!(f, "Something weird happened in {}...", p), } @@ -268,7 +267,7 @@ impl Parser for LP { Element::Texture(texture_name, texture_path) => { if current_material_name.is_none() { - return Err(ParserError::NoMaterialExist(path.to_owned(), num, texture_path)); + return Err(ParserError::NoMaterialExist(path.to_owned(), num)); } let material_name = current_material_name.as_ref().unwrap().clone(); @@ -276,18 +275,16 @@ impl Parser for LP { let current_material = model.materials.get_mut(&material_name); if current_material.is_none() { - return Err(ParserError::NoMaterialExist(path.to_owned(), num, texture_path)) + return Err(ParserError::NoMaterialExist(path.to_owned(), num)) } let current_material = current_material.unwrap(); current_material.textures.insert(texture_name, texture_path); }, - Element::Color(_) => (), - - Element::UnknownMaterialInstruction(s) => { + Element::Diffuse(v) => { if current_material_name.is_none() { - return Err(ParserError::NoMaterialExist(path.to_owned(), num, s)); + return Err(ParserError::NoMaterialExist(path.to_owned(), num)); } let material_name = current_material_name.as_ref().unwrap().clone(); @@ -295,7 +292,25 @@ impl Parser for LP { let current_material = model.materials.get_mut(&material_name); if current_material.is_none() { - return Err(ParserError::NoMaterialExist(path.to_owned(), num, s)) + return Err(ParserError::NoMaterialExist(path.to_owned(), num)); + } + + let current_material = current_material.unwrap(); + + current_material.diffuse = v; + }, + + Element::UnknownMaterialInstruction(s) => { + if current_material_name.is_none() { + return Err(ParserError::NoMaterialExist(path.to_owned(), num)); + } + + let material_name = current_material_name.as_ref().unwrap().clone(); + + let current_material = model.materials.get_mut(&material_name); + + if current_material.is_none() { + return Err(ParserError::NoMaterialExist(path.to_owned(), num)) } current_material.unwrap().add_unknown_instruction(s); diff --git a/src/parser/mtl.rs b/src/parser/mtl.rs index d269361..73575f9 100644 --- a/src/parser/mtl.rs +++ b/src/parser/mtl.rs @@ -3,6 +3,9 @@ use std::path::PathBuf; use parser::{Element, ParserError, LineParser}; +use parser::obj::parse_values; + +use math::vector::Vector3; /// Wavefront material file format parser. pub struct MtlParser { @@ -21,7 +24,7 @@ impl MtlParser { } impl LineParser for MtlParser { - fn parse_line(&mut self, _line_number: usize, line: &str, path: &str) -> Result { + fn parse_line(&mut self, line_number: usize, line: &str, path: &str) -> Result { let mut root = PathBuf::from(path); root.pop(); @@ -40,6 +43,15 @@ impl LineParser for MtlParser { // Starts a new material "newmtl" => Ok(Element::NewMaterial(split.nth(0).unwrap().to_owned())), + "Kd" => { + let values = parse_values(line_number, line, path, 3)?; + Ok(Element::Diffuse(Vector3::new( + values[0] as f32, + values[1] as f32, + values[2] as f32, + ))) + }, + map if map.starts_with("map_") => { let mut full_path = root.clone(); diff --git a/src/parser/obj.rs b/src/parser/obj.rs index e0b25c0..cfa25fc 100644 --- a/src/parser/obj.rs +++ b/src/parser/obj.rs @@ -4,6 +4,31 @@ use parser::{Element, ParserError, LineParser}; use math::vector::{Vector2, Vector3}; use model::face::{FaceVertex, Face}; +/// Parses a certain number of value in a line, and returns a Vec containing the values. +/// +/// Will return an error if the number of values expected is incorrect. +pub fn parse_values(line_number: usize, line: &str, path: &str, number_of_values: usize) -> Result, ParserError> { + + let mut split = line.split_whitespace(); + split.next(); + + let mut ret = vec![]; + + for elt in split { + if let Ok(value) = elt.parse::() { + ret.push(value); + } else { + return Err(ParserError::ParseNumberError(path.to_owned(), line_number, elt.to_owned())); + } + } + if ret.len() == number_of_values { + Ok(ret) + } else { + Err(ParserError::IncorrectNumberOfParameters(path.to_owned(), line_number, number_of_values, ret.len())) + } +} + + /// The wavefront OBJ format parser. pub struct ObjParser { @@ -18,30 +43,6 @@ impl ObjParser { } } - /// Parses a certain number of value in a line, and returns a Vec containing the values. - /// - /// Will return an error if the number of values expected is incorrect. - fn parse_values(&self, line_number: usize, line: &str, path: &str, number_of_values: usize) -> Result, ParserError> { - - let mut split = line.split_whitespace(); - split.next(); - - let mut ret = vec![]; - - for elt in split { - if let Ok(value) = elt.parse::() { - ret.push(value); - } else { - return Err(ParserError::ParseNumberError(path.to_owned(), line_number, elt.to_owned())); - } - } - if ret.len() == number_of_values { - Ok(ret) - } else { - Err(ParserError::IncorrectNumberOfParameters(path.to_owned(), line_number, number_of_values, ret.len())) - } - } - /// Parses an obj vertex line. /// /// ``` @@ -54,7 +55,7 @@ impl ObjParser { /// ``` pub fn parse_vertex(&self, line_number: usize, line: &str, path: &str) -> Result { - let values = self.parse_values(line_number, line, path, 3)?; + let values = parse_values(line_number, line, path, 3)?; Ok(Element::Vertex(Vector3::::new( values[0], values[1], @@ -74,7 +75,7 @@ impl ObjParser { /// ``` pub fn parse_texture_coordinate(&self, line_number: usize, line: &str, path: &str) -> Result { - let values = self.parse_values(line_number, line, path, 2)?; + let values = parse_values(line_number, line, path, 2)?; Ok(Element::TextureCoordinate(Vector2::::new( values[0], values[1], @@ -93,7 +94,7 @@ impl ObjParser { /// ``` pub fn parse_normal(&self, line_number: usize, line: &str, path: &str) -> Result { - let values = self.parse_values(line_number, line, path, 3)?; + let values = parse_values(line_number, line, path, 3)?; Ok(Element::Normal(Vector3::::new( values[0], values[1], diff --git a/src/renderer.rs b/src/renderer.rs index 548f937..1983b09 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -19,6 +19,7 @@ use scene::Scene; use camera::RenderCamera; use model::{Vertex, Part, Model}; +use math::vector::Vector3; /// Image data stored as RGBA. pub struct RgbaImageData { @@ -142,6 +143,12 @@ impl Renderer { if let &Some(ref buffer) = part.vertex_buffer() { + let diffuse = if let Some(ref name) = part.material_name { + model.materials.get(name).unwrap().diffuse + } else { + Vector3::new(1.0, 1.0, 1.0) + }; + let texture = self.get_texture_of_part(&model, part); let texture = if let Some(texture) = texture { @@ -155,6 +162,7 @@ impl Renderer { NoIndices(PrimitiveType::TrianglesList), &self.program, &uniform!( + diffuse: Into::<[f32; 3]>::into(diffuse), tex: texture, perspective: Into::<[[f32; 4]; 4]>::into(perspective), view: Into::<[[f32; 4]; 4]>::into(view),