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"
|
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"
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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],
|
||||||
|
|
|
@ -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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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],
|
||||||
|
|
Loading…
Reference in a new issue