https://github.com/glium/glium/blob/master/book/tuto-14-wall.md
간단한 모양이므로 직접 생성
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
}
implement_vertex!(Vertex, position, normal);
let shape = glium::vertex::VertexBuffer::new(&display, &[
Vertex { position: [-1.0, 1.0, 0.0], normal: [0.0, 0.0, -1.0] },
Vertex { position: [ 1.0, 1.0, 0.0], normal: [0.0, 0.0, -1.0] },
Vertex { position: [-1.0, -1.0, 0.0], normal: [0.0, 0.0, -1.0] },
Vertex { position: [ 1.0, -1.0, 0.0], normal: [0.0, 0.0, -1.0] },
]).unwrap();
draw code
target.draw(&shape, glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip), &program,
&uniform! { model: model, view: view, perspective: perspective, u_light: light },
¶ms).unwrap();
전체 코드
#[macro_use]
extern crate glium;
// mod teapot;
fn main() {
#[allow(unused_imports)]
use glium::{glutin, Surface};
let mut event_loop = glutin::event_loop::EventLoop::new();
let wb = glutin::window::WindowBuilder::new();
let cb = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = glium::Display::new(wb, cb, &event_loop).unwrap();
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
}
implement_vertex!(Vertex, position, normal);
let shape = glium::vertex::VertexBuffer::new(
&display,
&[
Vertex {
position: [-1.0, 1.0, 0.0],
normal: [0.0, 0.0, -1.0],
},
Vertex {
position: [1.0, 1.0, 0.0],
normal: [0.0, 0.0, -1.0],
},
Vertex {
position: [-1.0, -1.0, 0.0],
normal: [0.0, 0.0, -1.0],
},
Vertex {
position: [1.0, -1.0, 0.0],
normal: [0.0, 0.0, -1.0],
},
],
)
.unwrap();
let light = [1.4, 0.4, -0.7f32];
let vertex_shader_src = r#"
#version 150
in vec3 position;
in vec3 normal;
out vec3 v_normal;
out vec3 v_position;
uniform mat4 perspective;
uniform mat4 view;
uniform mat4 model;
void main() {
mat4 modelview = view * model;
v_normal = transpose(inverse(mat3(modelview))) * normal;
gl_Position = perspective * modelview * vec4(position, 1.0);
v_position = gl_Position.xyz / gl_Position.w;
}
"#;
let fragment_shader_src = r#"
#version 150
in vec3 v_normal;
in vec3 v_position;
out vec4 color;
uniform vec3 u_light;
const vec3 ambient_color = vec3(0.2, 0.0, 0.0);
const vec3 diffuse_color = vec3(0.6, 0.0, 0.0);
const vec3 specular_color = vec3(1.0, 1.0, 1.0);
void main() {
float diffuse = max(dot(normalize(v_normal), normalize(u_light)), 0.0);
vec3 camera_dir = normalize(-v_position);
vec3 half_direction = normalize(normalize(u_light) + camera_dir);
float specular = pow(max(dot(half_direction, normalize(v_normal)), 0.0), 16.0);
color = vec4(ambient_color + diffuse * diffuse_color + specular * specular_color, 1.0);
}
"#;
let program =
glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
.unwrap();
let params = glium::DrawParameters {
depth: glium::Depth {
test: glium::draw_parameters::DepthTest::IfLess,
write: true,
..Default::default()
},
// backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
..Default::default()
};
let mut t: f32 = -0.5;
event_loop.run(move |event, _, control_flow| {
match event {
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested => {
*control_flow = glutin::event_loop::ControlFlow::Exit;
return;
}
_ => return,
},
glutin::event::Event::NewEvents(cause) => match cause {
glutin::event::StartCause::ResumeTimeReached { .. } => (),
glutin::event::StartCause::Init => (),
_ => return,
},
_ => return,
}
let next_frame_time =
std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
*control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);
t += 0.002;
if t > 0.5 {
t = -0.5;
}
let mut target = display.draw();
target.clear_color_and_depth((0.3, 0.5, 0.7, 1.0), 1.0);
let model = [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0f32]
];
let view = view_matrix(&[0.5, 0.2, -3.0], &[-0.5, -0.2, 3.0], &[0.0, 1.0, 0.0]);
let perspective = {
let (width, height) = target.get_dimensions();
let aspect_ratio = height as f32 / width as f32;
let fov: f32 = 3.141592 / 3.0;
let zfar = 1024.0;
let znear = 0.1;
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],
]
};
target
.draw(
&shape,
glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip),
&program,
&uniform!{model: model, view: view, perspective: perspective, u_light: light},
¶ms,
)
.unwrap();
target.finish().unwrap();
});
}
fn view_matrix(position: &[f32; 3], direction: &[f32; 3], up: &[f32; 3]) -> [[f32; 4]; 4] {
let f = {
let f = direction;
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 = [
up[1] * f[2] - up[2] * f[1],
up[2] * f[0] - up[0] * f[2],
up[0] * f[1] - 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 = [
-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
-position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
-position[0] * f[0] - position[1] * f[1] - 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],
]
}
let image = image::load(Cursor::new(&include_bytes!("../book/tuto-14-diffuse.jpg")),
image::ImageFormat::Jpeg).unwrap().to_rgba8();
let image_dimensions = image.dimensions();
let image = glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dimensions);
let diffuse_texture = glium::texture::SrgbTexture2d::new(&display, image).unwrap();
vertex structure 수정
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
tex_coords: [f32; 2],
}
implement_vertex!(Vertex, position, normal, tex_coords);
vertex shader 수정
in vec2 tex_coords;
out vec2 v_tex_coords; 추가
v_tex_coords = tex_coords;
fragment shader 내용 추가
uniform sampler2D diffuse_tex;
fragment shader 내용 수정
const vec3 ambient_color = vec3(0.2, 0.0, 0.0);
const vec3 diffuse_color = vec3(0.6, 0.0, 0.0);
||
V
vec3 diffuse_color = texture(diffuse_tex, v_tex_coords).rgb;
vec3 ambient_color = diffuse_color * 0.1;
shape 코드 변경
let shape = glium::vertex::VertexBuffer::new(&display, &[
Vertex { position: [-1.0, 1.0, 0.0], normal: [0.0, 0.0, -1.0], tex_coords: [0.0, 1.0] },
Vertex { position: [ 1.0, 1.0, 0.0], normal: [0.0, 0.0, -1.0], tex_coords: [1.0, 1.0] },
Vertex { position: [-1.0, -1.0, 0.0], normal: [0.0, 0.0, -1.0], tex_coords: [0.0, 0.0] },
Vertex { position: [ 1.0, -1.0, 0.0], normal: [0.0, 0.0, -1.0], tex_coords: [1.0, 0.0] },
]).unwrap();
draw code 수정
target.draw(&shape, glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip), &program,
&uniform! { model: model, view: view, perspective: perspective,
u_light: light, diffuse_tex: &diffuse_texture },
¶ms).unwrap();
전체 코드
#[macro_use]
extern crate glium;
extern crate image;
use std::io::Cursor;
// mod teapot;
fn main() {
#[allow(unused_imports)]
use glium::{glutin, Surface};
let mut event_loop = glutin::event_loop::EventLoop::new();
let wb = glutin::window::WindowBuilder::new();
let cb = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = glium::Display::new(wb, cb, &event_loop).unwrap();
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
tex_coords: [f32; 2],
}
implement_vertex!(Vertex, position, normal, tex_coords);
let shape = glium::vertex::VertexBuffer::new(
&display,
&[
Vertex {
position: [-1.0, 1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [0.0, 1.0],
},
Vertex {
position: [1.0, 1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [1.0, 1.0],
},
Vertex {
position: [-1.0, -1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [0.0, 0.0],
},
Vertex {
position: [1.0, -1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [1.0, 0.0],
},
],
)
.unwrap();
let light = [1.4, 0.4, -0.7f32];
let vertex_shader_src = r#"
#version 150
in vec3 position;
in vec3 normal;
in vec2 tex_coords;
out vec3 v_normal;
out vec3 v_position;
out vec2 v_tex_coords;
uniform mat4 perspective;
uniform mat4 view;
uniform mat4 model;
void main() {
v_tex_coords = tex_coords;
mat4 modelview = view * model;
v_normal = transpose(inverse(mat3(modelview))) * normal;
gl_Position = perspective * modelview * vec4(position, 1.0);
v_position = gl_Position.xyz / gl_Position.w;
}
"#;
let fragment_shader_src = r#"
#version 150
in vec3 v_normal;
in vec3 v_position;
in vec2 v_tex_coords;
out vec4 color;
uniform vec3 u_light;
uniform sampler2D diffuse_tex;
vec3 diffuse_color = texture(diffuse_tex, v_tex_coords).rgb;
vec3 ambient_color = diffuse_color * 0.1;
const vec3 specular_color = vec3(1.0, 1.0, 1.0);
void main() {
float diffuse = max(dot(normalize(v_normal), normalize(u_light)), 0.0);
vec3 camera_dir = normalize(-v_position);
vec3 half_direction = normalize(normalize(u_light) + camera_dir);
float specular = pow(max(dot(half_direction, normalize(v_normal)), 0.0), 16.0);
color = vec4(ambient_color + diffuse * diffuse_color + specular * specular_color, 1.0);
}
"#;
let program =
glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
.unwrap();
let params = glium::DrawParameters {
depth: glium::Depth {
test: glium::draw_parameters::DepthTest::IfLess,
write: true,
..Default::default()
},
// backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
..Default::default()
};
let image = image::load(
Cursor::new(&include_bytes!("tuto-14-diffuse.jpg")),
image::ImageFormat::Jpeg,
)
.unwrap()
.to_rgba8();
let image_dimensions = image.dimensions();
let image =
glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dimensions);
let diffuse_texture = glium::texture::SrgbTexture2d::new(&display, image).unwrap();
let mut t: f32 = -0.5;
event_loop.run(move |event, _, control_flow| {
match event {
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested => {
*control_flow = glutin::event_loop::ControlFlow::Exit;
return;
}
_ => return,
},
glutin::event::Event::NewEvents(cause) => match cause {
glutin::event::StartCause::ResumeTimeReached { .. } => (),
glutin::event::StartCause::Init => (),
_ => return,
},
_ => return,
}
let next_frame_time =
std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
*control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);
t += 0.002;
if t > 0.5 {
t = -0.5;
}
let mut target = display.draw();
target.clear_color_and_depth((0.3, 0.5, 0.7, 1.0), 1.0);
let model = [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0f32],
];
let view = view_matrix(&[0.5, 0.2, -3.0], &[-0.5, -0.2, 3.0], &[0.0, 1.0, 0.0]);
let perspective = {
let (width, height) = target.get_dimensions();
let aspect_ratio = height as f32 / width as f32;
let fov: f32 = 3.141592 / 3.0;
let zfar = 1024.0;
let znear = 0.1;
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],
]
};
target
.draw(
&shape,
glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip),
&program,
&uniform! { model: model, view: view, perspective: perspective,
u_light: light, diffuse_tex: &diffuse_texture },
¶ms,
)
.unwrap();
target.finish().unwrap();
});
}
fn view_matrix(position: &[f32; 3], direction: &[f32; 3], up: &[f32; 3]) -> [[f32; 4]; 4] {
let f = {
let f = direction;
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 = [
up[1] * f[2] - up[2] * f[1],
up[2] * f[0] - up[0] * f[2],
up[0] * f[1] - 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 = [
-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
-position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
-position[0] * f[0] - position[1] * f[1] - 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],
]
}
현재까지의 내용은 현실적인 느낌이 적은상태
Normal Mapping을 이용하여 렌더링 품질을 향상 시킬 수 있음
노멀 맵의 각 픽셀은 이 픽셀 위치의 노멀 값을 나타냄
색상을 저장하는 대신 법선을 나타내는 임의의 값을 저장
let image = image::load(Cursor::new(&include_bytes!("../book/tuto-14-normal.png")),
image::PNG).unwrap().to_rgba8();
let image_dimensions = image.dimensions();
let image = glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dimensions);
let normal_map = glium::texture::Texture2d::new(&display, image).unwrap();
fragment shader 코드 변경
#version 140
in vec3 v_normal;
in vec3 v_position;
in vec2 v_tex_coords;
out vec4 color;
uniform vec3 u_light;
uniform sampler2D diffuse_tex;
uniform sampler2D normal_tex;
const vec3 specular_color = vec3(1.0, 1.0, 1.0);
mat3 cotangent_frame(vec3 normal, vec3 pos, vec2 uv) {
vec3 dp1 = dFdx(pos);
vec3 dp2 = dFdy(pos);
vec2 duv1 = dFdx(uv);
vec2 duv2 = dFdy(uv);
vec3 dp2perp = cross(dp2, normal);
vec3 dp1perp = cross(normal, dp1);
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
return mat3(T * invmax, B * invmax, normal);
}
void main() {
vec3 diffuse_color = texture(diffuse_tex, v_tex_coords).rgb;
vec3 ambient_color = diffuse_color * 0.1;
vec3 normal_map = texture(normal_tex, v_tex_coords).rgb;
mat3 tbn = cotangent_frame(v_normal, v_position, v_tex_coords);
vec3 real_normal = normalize(tbn * -(normal_map * 2.0 - 1.0));
float diffuse = max(dot(real_normal, normalize(u_light)), 0.0);
vec3 camera_dir = normalize(-v_position);
vec3 half_direction = normalize(normalize(u_light) + camera_dir);
float specular = pow(max(dot(half_direction, real_normal), 0.0), 16.0);
color = vec4(ambient_color + diffuse * diffuse_color + specular * specular_color, 1.0);
}
draw code 수정
target
.draw(
&shape,
glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip),
&program,
&uniform! { model: model, view: view, perspective: perspective,
u_light: light, diffuse_tex: &diffuse_texture, normal_tex: &normal_map },
¶ms,
)
.unwrap();
전체 코드
#[macro_use]
extern crate glium;
extern crate image;
use std::io::Cursor;
// mod teapot;
fn main() {
#[allow(unused_imports)]
use glium::{glutin, Surface};
let mut event_loop = glutin::event_loop::EventLoop::new();
let wb = glutin::window::WindowBuilder::new();
let cb = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = glium::Display::new(wb, cb, &event_loop).unwrap();
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
tex_coords: [f32; 2],
}
implement_vertex!(Vertex, position, normal, tex_coords);
let shape = glium::vertex::VertexBuffer::new(
&display,
&[
Vertex {
position: [-1.0, 1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [0.0, 1.0],
},
Vertex {
position: [1.0, 1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [1.0, 1.0],
},
Vertex {
position: [-1.0, -1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [0.0, 0.0],
},
Vertex {
position: [1.0, -1.0, 0.0],
normal: [0.0, 0.0, -1.0],
tex_coords: [1.0, 0.0],
},
],
)
.unwrap();
let light = [1.4, 0.4, 0.7f32];
let vertex_shader_src = r#"
#version 150
in vec3 position;
in vec3 normal;
in vec2 tex_coords;
out vec3 v_normal;
out vec3 v_position;
out vec2 v_tex_coords;
uniform mat4 perspective;
uniform mat4 view;
uniform mat4 model;
void main() {
v_tex_coords = tex_coords;
mat4 modelview = view * model;
v_normal = transpose(inverse(mat3(modelview))) * normal;
gl_Position = perspective * modelview * vec4(position, 1.0);
v_position = gl_Position.xyz / gl_Position.w;
}
"#;
let fragment_shader_src = r#"
#version 140
in vec3 v_normal;
in vec3 v_position;
in vec2 v_tex_coords;
out vec4 color;
uniform vec3 u_light;
uniform sampler2D diffuse_tex;
uniform sampler2D normal_tex;
const vec3 specular_color = vec3(1.0, 1.0, 1.0);
mat3 cotangent_frame(vec3 normal, vec3 pos, vec2 uv) {
vec3 dp1 = dFdx(pos);
vec3 dp2 = dFdy(pos);
vec2 duv1 = dFdx(uv);
vec2 duv2 = dFdy(uv);
vec3 dp2perp = cross(dp2, normal);
vec3 dp1perp = cross(normal, dp1);
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
return mat3(T * invmax, B * invmax, normal);
}
void main() {
vec3 diffuse_color = texture(diffuse_tex, v_tex_coords).rgb;
vec3 ambient_color = diffuse_color * 0.1;
vec3 normal_map = texture(normal_tex, v_tex_coords).rgb;
mat3 tbn = cotangent_frame(v_normal, v_position, v_tex_coords);
vec3 real_normal = normalize(tbn * -(normal_map * 2.0 - 1.0));
float diffuse = max(dot(real_normal, normalize(u_light)), 0.0);
vec3 camera_dir = normalize(-v_position);
vec3 half_direction = normalize(normalize(u_light) + camera_dir);
float specular = pow(max(dot(half_direction, real_normal), 0.0), 16.0);
color = vec4(ambient_color + diffuse * diffuse_color + specular * specular_color, 1.0);
}
"#;
let program =
glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
.unwrap();
let params = glium::DrawParameters {
depth: glium::Depth {
test: glium::draw_parameters::DepthTest::IfLess,
write: true,
..Default::default()
},
// backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
..Default::default()
};
let image = image::load(
Cursor::new(&include_bytes!("tuto-14-diffuse.jpg")),
image::ImageFormat::Jpeg,
)
.unwrap()
.to_rgba8();
let image_dimensions = image.dimensions();
let image =
glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dimensions);
let diffuse_texture = glium::texture::SrgbTexture2d::new(&display, image).unwrap();
let image = image::load(
Cursor::new(&include_bytes!("tuto-14-normal.png")),
image::ImageFormat::Png,
)
.unwrap()
.to_rgba8();
let image_dimensions = image.dimensions();
let image =
glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dimensions);
let normal_map = glium::texture::Texture2d::new(&display, image).unwrap();
let mut t: f32 = -0.5;
event_loop.run(move |event, _, control_flow| {
match event {
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested => {
*control_flow = glutin::event_loop::ControlFlow::Exit;
return;
}
_ => return,
},
glutin::event::Event::NewEvents(cause) => match cause {
glutin::event::StartCause::ResumeTimeReached { .. } => (),
glutin::event::StartCause::Init => (),
_ => return,
},
_ => return,
}
let next_frame_time =
std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
*control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);
t += 0.002;
if t > 0.5 {
t = -0.5;
}
let mut target = display.draw();
target.clear_color_and_depth((0.3, 0.5, 0.7, 1.0), 1.0);
let model = [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0f32],
];
let view = view_matrix(&[0.5, 0.2, -3.0], &[-0.5, -0.2, 3.0], &[0.0, 1.0, 0.0]);
let perspective = {
let (width, height) = target.get_dimensions();
let aspect_ratio = height as f32 / width as f32;
let fov: f32 = 3.141592 / 3.0;
let zfar = 1024.0;
let znear = 0.1;
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],
]
};
target
.draw(
&shape,
glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip),
&program,
&uniform! { model: model, view: view, perspective: perspective,
u_light: light, diffuse_tex: &diffuse_texture, normal_tex: &normal_map },
¶ms,
)
.unwrap();
target.finish().unwrap();
});
}
fn view_matrix(position: &[f32; 3], direction: &[f32; 3], up: &[f32; 3]) -> [[f32; 4]; 4] {
let f = {
let f = direction;
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 = [
up[1] * f[2] - up[2] * f[1],
up[2] * f[0] - up[0] * f[2],
up[0] * f[1] - 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 = [
-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
-position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
-position[0] * f[0] - position[1] * f[1] - 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],
]
}