Starting to support textures

This commit is contained in:
Thomas Forgione 2018-02-26 14:59:32 +01:00
parent 80b397d3ec
commit b25dddaa9c
No known key found for this signature in database
GPG Key ID: C75CD416BD1FFCE1
7 changed files with 201 additions and 27 deletions

View File

@ -6,6 +6,7 @@ authors = ["Thomas Forgione <thomas@tforgione.fr>"]
[dependencies]
num = "*"
glium = "*"
image = "*"
verbose-log = { git = "https://gitea.tforgione.fr/dash-3d/verbose-log" }
[[bin]]

View File

@ -1,8 +1,11 @@
#version 140
in vec2 v_tex_coords;
out vec4 color;
uniform sampler2D tex;
void main() {
color = vec4(1.0, 0.0, 0.0, 1.0);
color = texture(tex, v_tex_coords);
}

View File

@ -1,7 +1,14 @@
#version 140
in vec3 vertex;
in vec2 tex_coords;
uniform mat4 perspective;
uniform mat4 view;
out vec2 v_tex_coords;
void main() {
gl_Position = vec4(vertex, 1.0);
v_tex_coords = tex_coords;
gl_Position = perspective * view * vec4(vertex, 1.0);
}

View File

@ -1,4 +1,5 @@
extern crate num;
extern crate image;
#[macro_use] extern crate verbose_log;
#[macro_use] extern crate glium;

View File

@ -10,12 +10,12 @@ use math::bounding_box::BoundingBox3;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vertex {
vertex: [f64; 3],
tex_coord: [f64; 2],
normal: [f64; 3],
vertex: [f64; 3],
tex_coords: [f64; 2],
normal: [f64; 3],
}
implement_vertex!(Vertex, vertex, tex_coord, normal);
implement_vertex!(Vertex, vertex, tex_coords, normal);
#[derive(Copy, Clone, PartialEq)]
/// The indices needed for each vertex of a face.
@ -170,9 +170,9 @@ impl Part {
for face in &self.faces {
for &&v in &[&face.a, &face.b, &face.c] {
shape.push(Vertex {
vertex: vertices[v.vertex].into(),
tex_coord: tex_coords[v.texture_coordinate.unwrap()].into(),
normal: normals[v.normal.unwrap()].into(),
vertex: vertices[v.vertex].into(),
tex_coords: tex_coords[v.texture_coordinate.unwrap()].into(),
normal: normals[v.normal.unwrap()].into(),
});
}
}

View File

@ -6,33 +6,41 @@ use glium::glutin;
use glium::glutin::{
EventsLoop,
WindowBuilder,
ContextBuilder,
};
use glium::glutin::Event;
use glium::glutin::WindowEvent;
use glium::glutin::VirtualKeyCode;
use model_converter::parser::parse;
use model_converter::renderer::Renderer;
use model_converter::math::vector::Vector3;
use model_converter::parser::{parse, parse_into_model};
use model_converter::renderer::{Camera, Renderer};
fn main() {
let mut model = parse("./assets/models/toonlink/link.mtl").unwrap();
parse_into_model("./assets/models/toonlink/link.obj", &mut model).unwrap();
let mut events_loop = EventsLoop::new();
let window = WindowBuilder::new();
let context = ContextBuilder::new();
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = Display::new(window, context, &events_loop).unwrap();
let mut closed = false;
let model = parse("./assets/models/toonlink/link.obj").unwrap();
let mut renderer = Renderer::new(display);
renderer.add_model(&model);
let camera = Camera::new(
Vector3::new(50.0, 0.0, 25.0),
Vector3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
);
while !closed {
let mut target = renderer.draw();
renderer.render(&mut target);
renderer.render(&camera, &mut target);
target.finish().unwrap();

View File

@ -1,3 +1,8 @@
use glium::draw_parameters::DepthTest;
use glium::texture::{
RawImage2d,
Texture2d,
};
use glium::index::{
NoIndices,
PrimitiveType
@ -7,14 +12,98 @@ use glium::{
Display,
VertexBuffer,
Frame,
DrawParameters,
Depth,
};
use image;
use model::{Model, Vertex};
use math::vector::Vector3;
pub struct RenderMaterial {
texture: Option<Texture2d>,
}
impl RenderMaterial {
pub fn new() -> RenderMaterial {
RenderMaterial {
texture: None
}
}
pub fn from_texture_name(path: &str, display: &Display) -> RenderMaterial {
let image = image::open(path);
if let Ok(image) = image {
let image = image.to_rgba();
let dim = image.dimensions();
let image = RawImage2d::from_raw_rgba_reversed(&image.into_raw(), dim);
RenderMaterial {
texture: Texture2d::new(display, image).ok()
}
} else {
RenderMaterial {
texture: None
}
}
}
}
pub struct Camera {
position: Vector3<f32>,
target: Vector3<f32>,
up: Vector3<f32>,
}
impl Camera {
pub fn new(position: Vector3<f32>, target: Vector3<f32>, up: Vector3<f32>) -> Camera {
Camera {
position: position,
target: target,
up: up,
}
}
pub fn get_view_matrix(&self) -> [[f32; 4]; 4] {
let f = {
let f = self.target - self.position;
let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2];
let len = len.sqrt();
[f[0] / len, f[1] / len, f[2] / len]
};
let s = [self.up[1] * f[2] - self.up[2] * f[1],
self.up[2] * f[0] - self.up[0] * f[2],
self.up[0] * f[1] - self.up[1] * f[0]];
let s_norm = {
let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2];
let len = len.sqrt();
[s[0] / len, s[1] / len, s[2] / len]
};
let u = [f[1] * s_norm[2] - f[2] * s_norm[1],
f[2] * s_norm[0] - f[0] * s_norm[2],
f[0] * s_norm[1] - f[1] * s_norm[0]];
let p = [-self.position[0] * s_norm[0] - self.position[1] * s_norm[1] - self.position[2] * s_norm[2],
-self.position[0] * u[0] - self.position[1] * u[1] - self.position[2] * u[2],
-self.position[0] * f[0] - self.position[1] * f[1] - self.position[2] * f[2]];
[
[s_norm[0], u[0], f[0], 0.0],
[s_norm[1], u[1], f[1], 0.0],
[s_norm[2], u[2], f[2], 0.0],
[p[0], p[1], p[2], 1.0],
]
}
}
pub struct Renderer<'a> {
display: Display,
program: Program,
models: Vec<(&'a Model, Vec<VertexBuffer<Vertex>>)>,
models: Vec<(&'a Model, Vec<(RenderMaterial, VertexBuffer<Vertex>)>)>,
}
impl<'a> Renderer<'a> {
@ -34,12 +123,47 @@ impl<'a> Renderer<'a> {
}
}
pub fn get_perspective_matrix(&self, dimensions: (u32, u32)) -> [[f32; 4]; 4] {
let (width, height) = dimensions;
let aspect_ratio = height as f32 / width as f32;
let fov = 3.141592 / 3.0;
let zfar = 1024.0;
let znear = 0.1;
use num::Float;
let f = 1.0 / (fov / 2.0).tan();
[
[f * aspect_ratio , 0.0, 0.0 , 0.0],
[ 0.0 , f , 0.0 , 0.0],
[ 0.0 , 0.0, (zfar+znear)/(zfar-znear) , 1.0],
[ 0.0 , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0],
]
}
pub fn add_model(&mut self, model: &'a Model) {
let mut buffers = vec![];
for part in &model.parts {
let material = if let Some(ref material_name) = part.material_name {
if let Some(material) = model.materials.get(material_name) {
if let Some(path) = material.textures.get("map_Kd") {
RenderMaterial::from_texture_name(path, &self.display)
} else {
RenderMaterial::new()
}
} else {
RenderMaterial::new()
}
} else {
RenderMaterial::new()
};
let shape = part.build_shape(&model.vertices, &model.texture_coordinates, &model.normals);
buffers.push(VertexBuffer::new(&self.display, &shape).unwrap());
buffers.push((material, VertexBuffer::new(&self.display, &shape).unwrap()));
}
self.models.push((model, buffers));
@ -49,19 +173,49 @@ impl<'a> Renderer<'a> {
self.display.draw()
}
pub fn render(&self, target: &mut Frame) {
pub fn render(&self, camera: &Camera, target: &mut Frame) {
use glium::Surface;
target.clear_color(0.0, 0.0, 0.0, 1.0);
target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);
let params = DrawParameters {
depth: Depth {
test: DepthTest::IfLess,
write: true,
.. Default::default()
},
.. Default::default()
};
for &(_, ref buffers) in &self.models {
for buffer in buffers {
target.draw(
buffer,
NoIndices(PrimitiveType::TrianglesList),
&self.program,
&uniform!(),
&Default::default(),
).unwrap();
for &(ref material, ref buffer) in buffers {
let perspective = self.get_perspective_matrix(target.get_dimensions());
let view = camera.get_view_matrix();
if let &Some(ref texture) = &material.texture {
target.draw(
buffer,
NoIndices(PrimitiveType::TrianglesList),
&self.program,
&uniform!(
tex: texture,
perspective: perspective,
view: view,
),
&params,
).unwrap();
} else {
target.draw(
buffer,
NoIndices(PrimitiveType::TrianglesList),
&self.program,
&uniform!(
perspective: perspective,
view: view,
),
&params,
).unwrap();
};
}
}
}