mesh.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // ┏┳┓┏━╸┏━┓╻ ╻ ╻┏━┓
  2. // ┃┃┃┣╸ ┗━┓┣━┫ ┃┃ ┃
  3. // ╹ ╹┗━╸┗━┛╹ ╹ ╹┗━┛
  4. use std::fs::File;
  5. use std::io::BufReader;
  6. use std::io::BufRead;
  7. use std::collections::HashMap;
  8. use std::path::Path;
  9. use crate::geometry::Vec3;
  10. use crate::geometry::Ray;
  11. /** Data structure for a single triangle face. */
  12. pub struct Face {
  13. /** Triangle coordinates indexed inside mesh */
  14. v: [usize; 3],
  15. /** Triangle normals for each vertex */
  16. n: [usize; 3],
  17. /** Texture coordinates */
  18. tex: [usize; 3],
  19. /** Center point. Needed for BVH construction */
  20. pub center: Vec3,
  21. /** Surface Area */
  22. pub area: f32
  23. }
  24. impl Face {
  25. pub fn from(m: &Mesh, t: &Vec<[usize; 3]>) -> Face {
  26. let mut face = Face {
  27. v: [t[0][0] - 1, t[1][0] - 1, t[2][0] - 1],
  28. n: [t[0][1] - 1, t[1][1] - 1, t[2][1] - 1],
  29. tex: [t[0][2] - 1, t[1][2] - 1, t[2][2] - 1],
  30. center: Vec3::new(0.0, 0.0, 0.0),
  31. area: 0.0
  32. };
  33. // Calculate centroid
  34. face.center.x = face.v.iter().map(|i| m.vertices[*i].x).sum::<f32>() / 3.0;
  35. face.center.y = face.v.iter().map(|i| m.vertices[*i].y).sum::<f32>() / 3.0;
  36. face.center.z = face.v.iter().map(|i| m.vertices[*i].z).sum::<f32>() / 3.0;
  37. // Calculate surface area
  38. let ab = m.vertices[face.v[1]] - m.vertices[face.v[0]];
  39. let ac = m.vertices[face.v[2]] - m.vertices[face.v[0]];
  40. face.area = ab.cross(ac).length() / 2.0;
  41. return face;
  42. }
  43. }
  44. #[derive(Copy,Clone,Debug)]
  45. pub struct Material {
  46. pub color: Vec3,
  47. pub roughness: f32,
  48. pub metallic: f32,
  49. }
  50. impl Material {
  51. pub fn new() -> Material {
  52. return Material {
  53. color: Vec3::new(0.0, 0.0, 0.0),
  54. roughness: 0.2,
  55. metallic: 0.0,
  56. }
  57. }
  58. }
  59. pub struct Mesh {
  60. pub name: String,
  61. pub vertices: Vec<Vec3>,
  62. pub normals: Vec<Vec3>,
  63. pub texture_coordinates: Vec<Vec3>,
  64. pub faces: Vec<Face>,
  65. pub material: Material
  66. }
  67. fn parse_vec3<'a>(it: &mut impl Iterator<Item = &'a str>) -> Option<Vec3> {
  68. let x = it.next()?.parse::<f32>().ok()?;
  69. let y = it.next()?.parse::<f32>().ok()?;
  70. let z = it.next()?.parse::<f32>().ok()?;
  71. return Some(Vec3::new(x,y,z));
  72. }
  73. fn parse_uv<'a>(a: &mut impl Iterator<Item = &'a str>) -> Option<Vec3> {
  74. let x = a.next()?.parse::<f32>().ok()?;
  75. let y = a.next()?.parse::<f32>().ok()?;
  76. return Some(Vec3::new(x,y, 0.0));
  77. }
  78. fn parse_triple(a: &str) -> Option<[usize; 3]> {
  79. let v : Vec<usize> = a.split("/")
  80. .map(|idx| idx.parse::<usize>().ok())
  81. .collect::<Option<Vec<usize>>>()?;
  82. if v.len() != 3 {
  83. return None;
  84. } else {
  85. return Some([v[0], v[1], v[2]]);
  86. }
  87. }
  88. /* Parses a line into individual arguments.
  89. * Returns None if the line is empty.
  90. */
  91. fn parse_line<'a>(line: &'a mut String) -> Option<impl Iterator<Item = &'a str>> {
  92. let whitespace_offset = line.find(char::is_alphanumeric).unwrap_or(0);
  93. let comment_offset = line.find('#').unwrap_or(line.len());
  94. if whitespace_offset >= comment_offset {
  95. // Line is factually empty except for whitespace and commentary.
  96. return None;
  97. }
  98. // Remove comments
  99. let instruction = &line[whitespace_offset..comment_offset];
  100. // Skip if line is empty
  101. if instruction.is_empty() {
  102. return None;
  103. }
  104. return Some(instruction.split(' '));
  105. }
  106. pub fn read_mtllib(path: &str) -> HashMap<String, Material> {
  107. let mut library = HashMap::new();
  108. let file = File::open(path).expect("Could not open mtllib");
  109. let reader = BufReader::new(file);
  110. let mut name = String::default();
  111. for (line_counter, l) in reader.lines().enumerate() {
  112. let mut line = l.expect("Failed to read line from file");
  113. let result = parse_line(&mut line);
  114. if result.is_none() {
  115. // Empty line
  116. continue;
  117. }
  118. let mut arguments = result.unwrap();
  119. let command = arguments.next()
  120. .expect(format!("Line {} does not contain a command", line_counter).as_str());
  121. let error_msg = format!("Invalid instruction in line {} (missing newmtl?)", line_counter);
  122. match command {
  123. "newmtl" => {
  124. name = String::from(arguments.next().expect("Expected name in newmtl instruction"));
  125. println!("Creating material {}", name);
  126. library.insert(name.clone(), Material::new());
  127. println!("Have '{}'", name);
  128. },
  129. "Kd" => {
  130. println!("Contained: {}", library.keys().next().unwrap_or(&String::from("NONE")));
  131. println!("Have '{}'", name);
  132. let mtl = library.get_mut(&name).expect(error_msg.as_str());
  133. let color = parse_vec3(&mut arguments).expect("Unable to parse color vector");
  134. mtl.color = color;
  135. },
  136. _ => {}
  137. }
  138. }
  139. return library;
  140. }
  141. impl Mesh {
  142. pub fn load(obj_path: &str) -> Vec<Mesh> {
  143. let mut objects : Vec<Mesh> = Vec::new();
  144. let file = File::open(obj_path).expect("Could not open OBJ file");
  145. let reader = BufReader::new(file);
  146. let mut mtllib : HashMap<String, Material> = HashMap::default();
  147. let default_material = Material::new();
  148. // Points to last created object
  149. let mut object_count : usize = 0;
  150. for (line_counter, l) in reader.lines().enumerate() {
  151. let mut line = l.expect("Could not read line from file");
  152. let result= parse_line(&mut line);
  153. // Handle empty line
  154. if result.is_none() {
  155. continue;
  156. }
  157. let mut arguments = result.unwrap();
  158. let instruction_code = arguments.next().expect(
  159. format!("Did not find instruction code in line {}'", line_counter).as_str());
  160. match instruction_code {
  161. "o" => {
  162. let name = arguments.next().expect(format!("Missing name argument in line {}", line_counter).as_str());
  163. // Construct new mesh to work on.
  164. objects.push(Mesh {
  165. name: String::from(name),
  166. vertices: Vec::new(),
  167. normals: Vec::new(),
  168. texture_coordinates: Vec::new(),
  169. faces: Vec::new(),
  170. material: default_material
  171. });
  172. },
  173. "v" | "vn" => {
  174. let o : &mut Mesh = objects.last_mut().expect("Vertices added before object was constructed");
  175. let coords = parse_vec3(&mut arguments).expect(
  176. format!("Could not parse coords in line {}", line_counter).as_str()
  177. );
  178. if instruction_code == "v" {
  179. o.vertices.push(coords);
  180. } else {
  181. o.normals.push(coords);
  182. }
  183. }
  184. "vt" => {
  185. let o : &mut Mesh = objects.last_mut().expect("Texture coordinates added before object was constructed");
  186. let coords = parse_uv(&mut arguments).expect(
  187. format!("Could not parse uv coords in line {}", line_counter).as_str()
  188. );
  189. o.texture_coordinates.push(coords);
  190. }
  191. "f" => {
  192. let o : &mut Mesh = objects.last_mut().expect("Face added before object was constructed");
  193. let error_msg = format!("Could not parse face in line {}", line_counter);
  194. let t : Vec<[usize; 3]> = arguments
  195. .map(|x| parse_triple(x))
  196. .collect::<Option<Vec<[usize; 3]>>>()
  197. .expect(&error_msg);
  198. if t.len() != 3 {
  199. panic!("{}", error_msg);
  200. }
  201. let face = Face::from(&o, &t);
  202. o.faces.push(face);
  203. }
  204. "mtllib" => {
  205. let filename = arguments.next().expect(format!("Missing filename in line {}", line_counter).as_str());
  206. let basedir = Path::new(obj_path).parent().expect("Could not find parent directory of obj file");
  207. mtllib = read_mtllib(basedir.join(filename).to_str().expect("Could not construct path to mtl lib"));
  208. }
  209. "usemtl" => {
  210. let o : &mut Mesh = objects.last_mut().expect("Face added before object was constructed");
  211. let material_name = String::from(arguments.next().expect("No material name specified"));
  212. o.material = *mtllib.get(&material_name).expect("Material not found in library");
  213. }
  214. _ => {}
  215. }
  216. }
  217. // Print message with number of objects and total number of faces
  218. let total_faces : usize = objects.iter()
  219. .map(|o| o.faces.len())
  220. .sum();
  221. let object_names = objects.iter()
  222. .map(|o| o.name.clone())
  223. .collect::<Vec<String>>()
  224. .join(",");
  225. println!("Read {} objects ({}) with a total of {} faces.", objects.len(), object_names, total_faces);
  226. return objects;
  227. }
  228. pub fn face_coords(&self, f: &Face) -> [&Vec3; 3] {
  229. return [
  230. &self.vertices[f.v[0]],
  231. &self.vertices[f.v[1]],
  232. &self.vertices[f.v[2]]
  233. ];
  234. }
  235. }