library: render: mesh: add OBJ loading

This commit is contained in:
Antoine Martin 2020-03-26 20:55:42 +01:00 committed by Bruno BELANYI
parent a0d7d5e590
commit 0368edbd74
9 changed files with 96 additions and 8 deletions

View file

@ -28,6 +28,7 @@ rand = "0.7"
rayon = "1.3.0" rayon = "1.3.0"
serde_yaml = "0.8" serde_yaml = "0.8"
structopt = "0.3" structopt = "0.3"
tobj = "0.1"
[dependencies.nalgebra] [dependencies.nalgebra]
version = "0.20.0" version = "0.20.0"

View file

@ -9,7 +9,7 @@ use serde::Deserialize;
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
#[allow(missing_docs)] #[allow(missing_docs)]
#[enum_dispatch::enum_dispatch] #[enum_dispatch::enum_dispatch]
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub enum MaterialEnum { pub enum MaterialEnum {
#[serde(rename = "uniform")] #[serde(rename = "uniform")]
UniformMaterial, UniformMaterial,

View file

@ -4,7 +4,7 @@ use crate::Point2D;
use serde::Deserialize; use serde::Deserialize;
/// Represent a material which interpolates between three points. /// Represent a material which interpolates between three points.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct TriangleMaterial { pub struct TriangleMaterial {
/// The diffuse components. /// The diffuse components.
diffuse: [LinearColor; 3], diffuse: [LinearColor; 3],

View file

@ -1,11 +1,97 @@
use super::Object; use std::convert::TryFrom;
use std::path::PathBuf;
use nalgebra::Unit;
use serde::Deserialize; use serde::Deserialize;
use tobj::{self, load_obj};
use super::Object;
use crate::{
core::{LightProperties, LinearColor},
material::UniformMaterial,
shape::InterpolatedTriangle,
texture::UniformTexture,
Point, Vector,
};
/// Represent a mesh of objects. /// Represent a mesh of objects.
#[serde(try_from = "Wavefront")]
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
pub struct Mesh { pub struct Mesh {
/// The shapes composing the mesh /// The shapes composing the mesh
pub(crate) shapes: Vec<Object>, pub(crate) shapes: Vec<Object>,
} }
// FIXME: wavefront mesh deserialized in mesh #[derive(Debug, PartialEq, Deserialize)]
pub(crate) struct Wavefront {
pub obj_file: PathBuf,
}
impl TryFrom<Wavefront> for Mesh {
type Error = tobj::LoadError;
fn try_from(wavefront: Wavefront) -> Result<Mesh, Self::Error> {
let mut shapes = Vec::new();
let (models, _materials) = load_obj(&wavefront.obj_file)?;
for model in models {
let mesh = &model.mesh;
// mesh.indices contains all vertices. Each group of 3 vertices
// is a triangle, so we iterate over indices 3 by 3.
for i in 0..(mesh.indices.len() / 3) {
let (a, b, c) = (
mesh.indices[i * 3] as usize,
mesh.indices[i * 3 + 1] as usize,
mesh.indices[i * 3 + 2] as usize,
);
// FIXME: world-to-object transformations needed
let pos_a = Point::from_slice(&mesh.positions[(a * 3)..(a * 3 + 2)]);
let pos_b = Point::from_slice(&mesh.positions[(b * 3)..(b * 3 + 2)]);
let pos_c = Point::from_slice(&mesh.positions[(c * 3)..(c * 3 + 2)]);
// FIXME: normals could be empty
let norm_a = Unit::new_normalize(Vector::new(
mesh.normals[a * 3],
mesh.normals[a * 3 + 1],
mesh.normals[a * 3 + 2],
));
let norm_b = Unit::new_normalize(Vector::new(
mesh.normals[b * 3],
mesh.normals[b * 3 + 1],
mesh.normals[b * 3 + 2],
));
let norm_c = Unit::new_normalize(Vector::new(
mesh.normals[c * 3],
mesh.normals[c * 3 + 1],
mesh.normals[c * 3 + 2],
));
let t = InterpolatedTriangle::new(pos_a, pos_b, pos_c, norm_a, norm_b, norm_c);
// FIXME: handle material
if let Some(_) = mesh.material_id {
} else {
// FIXME: should we accept this, and use a default
// Material, or throw a LoadError
shapes.push(Object::new(
t.into(),
UniformMaterial::new(LightProperties::new(
LinearColor::new(1.0, 0.0, 0.0),
LinearColor::new(0.0, 0.0, 0.0),
None,
))
.into(),
UniformTexture::new(LinearColor::new(0.5, 0.5, 0.5)).into(),
));
}
}
}
Ok(Mesh { shapes })
}
}

View file

@ -12,7 +12,7 @@ use beevee::{
use serde::Deserialize; use serde::Deserialize;
/// An object being rendered in the scene. /// An object being rendered in the scene.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct Object { pub struct Object {
/// The `Object`'s physical shape /// The `Object`'s physical shape
pub shape: ShapeEnum, pub shape: ShapeEnum,

View file

@ -328,6 +328,7 @@ impl From<SerializedScene> for Scene {
.flatten() .flatten()
.collect(); .collect();
scene.objects.append(&mut flattened_meshes); scene.objects.append(&mut flattened_meshes);
Scene::new( Scene::new(
scene.camera, scene.camera,
scene.lights, scene.lights,

View file

@ -14,7 +14,7 @@ use serde::Deserialize;
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
#[allow(missing_docs)] #[allow(missing_docs)]
#[enum_dispatch::enum_dispatch] #[enum_dispatch::enum_dispatch]
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub enum ShapeEnum { pub enum ShapeEnum {
Sphere, Sphere,
Triangle, Triangle,

View file

@ -9,7 +9,7 @@ use serde::Deserialize;
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
#[allow(missing_docs)] #[allow(missing_docs)]
#[enum_dispatch::enum_dispatch] #[enum_dispatch::enum_dispatch]
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub enum TextureEnum { pub enum TextureEnum {
#[serde(rename = "uniform")] #[serde(rename = "uniform")]
UniformTexture, UniformTexture,

View file

@ -4,7 +4,7 @@ use crate::Point2D;
use serde::Deserialize; use serde::Deserialize;
/// Represent a texture which interpolates between three points. /// Represent a texture which interpolates between three points.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct TriangleTexture { pub struct TriangleTexture {
/// The texture at each point /// The texture at each point
textures: [UniformTexture; 3], textures: [UniformTexture; 3],