library: render: mesh: add OBJ loading
This commit is contained in:
parent
a0d7d5e590
commit
0368edbd74
|
@ -28,6 +28,7 @@ rand = "0.7"
|
|||
rayon = "1.3.0"
|
||||
serde_yaml = "0.8"
|
||||
structopt = "0.3"
|
||||
tobj = "0.1"
|
||||
|
||||
[dependencies.nalgebra]
|
||||
version = "0.20.0"
|
||||
|
|
|
@ -9,7 +9,7 @@ use serde::Deserialize;
|
|||
#[serde(rename_all = "lowercase")]
|
||||
#[allow(missing_docs)]
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub enum MaterialEnum {
|
||||
#[serde(rename = "uniform")]
|
||||
UniformMaterial,
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::Point2D;
|
|||
use serde::Deserialize;
|
||||
|
||||
/// Represent a material which interpolates between three points.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub struct TriangleMaterial {
|
||||
/// The diffuse components.
|
||||
diffuse: [LinearColor; 3],
|
||||
|
|
|
@ -1,11 +1,97 @@
|
|||
use super::Object;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use nalgebra::Unit;
|
||||
|
||||
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.
|
||||
#[serde(try_from = "Wavefront")]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub struct Mesh {
|
||||
/// The shapes composing the mesh
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use beevee::{
|
|||
use serde::Deserialize;
|
||||
|
||||
/// An object being rendered in the scene.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub struct Object {
|
||||
/// The `Object`'s physical shape
|
||||
pub shape: ShapeEnum,
|
||||
|
|
|
@ -328,6 +328,7 @@ impl From<SerializedScene> for Scene {
|
|||
.flatten()
|
||||
.collect();
|
||||
scene.objects.append(&mut flattened_meshes);
|
||||
|
||||
Scene::new(
|
||||
scene.camera,
|
||||
scene.lights,
|
||||
|
|
|
@ -14,7 +14,7 @@ use serde::Deserialize;
|
|||
#[serde(rename_all = "lowercase")]
|
||||
#[allow(missing_docs)]
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub enum ShapeEnum {
|
||||
Sphere,
|
||||
Triangle,
|
||||
|
|
|
@ -9,7 +9,7 @@ use serde::Deserialize;
|
|||
#[serde(rename_all = "lowercase")]
|
||||
#[allow(missing_docs)]
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub enum TextureEnum {
|
||||
#[serde(rename = "uniform")]
|
||||
UniformTexture,
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::Point2D;
|
|||
use serde::Deserialize;
|
||||
|
||||
/// Represent a texture which interpolates between three points.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub struct TriangleTexture {
|
||||
/// The texture at each point
|
||||
textures: [UniformTexture; 3],
|
||||
|
|
Loading…
Reference in a new issue