library: render: mesh: scale, rotate, & translate

The scaling factor is the same on all axis, to avoid having angles
changed which would mess with the normals too much.
This commit is contained in:
Bruno BELANYI 2020-03-27 00:54:31 +01:00
parent 2d624c517f
commit 15381d4bbd
2 changed files with 45 additions and 20 deletions

View file

@ -1,7 +1,7 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use std::path::PathBuf; use std::path::PathBuf;
use nalgebra::Unit; use nalgebra::{Similarity3, Unit};
use serde::Deserialize; use serde::Deserialize;
@ -27,6 +27,12 @@ pub struct Mesh {
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
pub(crate) struct Wavefront { pub(crate) struct Wavefront {
pub obj_file: PathBuf, pub obj_file: PathBuf,
#[serde(default = "crate::serialize::vector::zeros")]
translation: Vector,
#[serde(default = "crate::serialize::vector::zeros")]
rotation: Vector,
#[serde(default = "crate::serialize::coefficient::default_identity")]
scale: f32,
} }
impl TryFrom<Wavefront> for Mesh { impl TryFrom<Wavefront> for Mesh {
@ -37,6 +43,10 @@ impl TryFrom<Wavefront> for Mesh {
let (models, materials) = load_obj(&wavefront.obj_file)?; let (models, materials) = load_obj(&wavefront.obj_file)?;
// The object to world transformation matrix
let transform =
Similarity3::new(wavefront.translation, wavefront.rotation, wavefront.scale);
for model in models { for model in models {
let mesh = &model.mesh; let mesh = &model.mesh;
@ -49,29 +59,39 @@ impl TryFrom<Wavefront> for Mesh {
mesh.indices[i * 3 + 2] as usize, mesh.indices[i * 3 + 2] as usize,
); );
// FIXME: world-to-object transformations needed let pos_a = transform * Point::from_slice(&mesh.positions[(a * 3)..(a * 3 + 2)]);
let pos_a = Point::from_slice(&mesh.positions[(a * 3)..(a * 3 + 2)]); let pos_b = transform * Point::from_slice(&mesh.positions[(b * 3)..(b * 3 + 2)]);
let pos_b = Point::from_slice(&mesh.positions[(b * 3)..(b * 3 + 2)]); let pos_c = transform * Point::from_slice(&mesh.positions[(c * 3)..(c * 3 + 2)]);
let pos_c = Point::from_slice(&mesh.positions[(c * 3)..(c * 3 + 2)]);
let triangle: ShapeEnum = if mesh.normals.is_empty() { let triangle: ShapeEnum = if mesh.normals.is_empty() {
Triangle::new(pos_a, pos_b, pos_c).into() Triangle::new(pos_a, pos_b, pos_c).into()
} else { } else {
let norm_a = Unit::new_normalize(Vector::new( // We apply the (arguably useless) scaling to the vectors in case it is
mesh.normals[a * 3], // negative, which would invert their direction
mesh.normals[a * 3 + 1], let norm_a = {
mesh.normals[a * 3 + 2], let vec = Vector::new(
)); mesh.normals[a * 3],
let norm_b = Unit::new_normalize(Vector::new( mesh.normals[a * 3 + 1],
mesh.normals[b * 3], mesh.normals[a * 3 + 2],
mesh.normals[b * 3 + 1], );
mesh.normals[b * 3 + 2], Unit::new_normalize(transform * vec)
)); };
let norm_c = Unit::new_normalize(Vector::new( let norm_b = {
mesh.normals[c * 3], let vec = Vector::new(
mesh.normals[c * 3 + 1], mesh.normals[b * 3],
mesh.normals[c * 3 + 2], mesh.normals[b * 3 + 1],
)); mesh.normals[b * 3 + 2],
);
Unit::new_normalize(transform * vec)
};
let norm_c = {
let vec = Vector::new(
mesh.normals[c * 3],
mesh.normals[c * 3 + 1],
mesh.normals[c * 3 + 2],
);
Unit::new_normalize(transform * vec)
};
InterpolatedTriangle::new(pos_a, pos_b, pos_c, norm_a, norm_b, norm_c).into() InterpolatedTriangle::new(pos_a, pos_b, pos_c, norm_a, norm_b, norm_c).into()
}; };

View file

@ -14,3 +14,8 @@ where
let v: Vector = Deserialize::deserialize(deserializer)?; let v: Vector = Deserialize::deserialize(deserializer)?;
Ok(Unit::new_normalize(v)) Ok(Unit::new_normalize(v))
} }
/// Return a vector containing all zeros.
pub fn zeros() -> Vector {
Vector::new(0., 0., 0.)
}