This commit is contained in:
Piotr Siuszko 2020-08-20 20:34:57 +02:00
parent 7ce2f9830a
commit b8b0a46361
14 changed files with 860 additions and 83 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
/target /target
**png
**jpg
**jpeg

57
Cargo.lock generated
View File

@ -200,6 +200,9 @@ dependencies = [
"glfw", "glfw",
"human-panic", "human-panic",
"image", "image",
"num",
"rand 0.7.3",
"tobj",
] ]
[[package]] [[package]]
@ -320,7 +323,7 @@ dependencies = [
"gif", "gif",
"jpeg-decoder", "jpeg-decoder",
"num-iter", "num-iter",
"num-rational", "num-rational 0.2.4",
"num-traits", "num-traits",
"png", "png",
"scoped_threadpool", "scoped_threadpool",
@ -418,6 +421,40 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "num"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3e176191bc4faad357e3122c4747aa098ac880e88b168f106386128736cf4a"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational 0.3.0",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
dependencies = [
"autocfg 1.0.0",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "num-derive" name = "num-derive"
version = "0.2.5" version = "0.2.5"
@ -461,6 +498,18 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-rational"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
dependencies = [
"autocfg 1.0.0",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.12" version = "0.2.12"
@ -868,6 +917,12 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "tobj"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6172100cd5b17cdd085c94f261e31101ca31886c86a2337a6687dac6d2fb3cf1"
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.6" version = "0.5.6"

View File

@ -17,7 +17,7 @@ gl = "0.14.0"
glfw = "0.39.1" glfw = "0.39.1"
image = "0.22.5" image = "0.22.5"
# only needed from chapter 3 on # only needed from chapter 3 on
# tobj = "0.1.6" tobj = "2.0.2"
# num = "0.2.0" num = "0.3.0"
# rand = "0.5.5" rand = "0.7.3"
human-panic = "1.0.3" human-panic = "1.0.3"

View File

@ -0,0 +1,7 @@
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0); // set alle 4 vector values to 1.0
}

11
resources/shaders/lamp.vs Normal file
View File

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
}

View File

@ -0,0 +1,11 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D texture_diffuse1;
void main()
{
FragColor = texture(texture_diffuse1, TexCoords);
}

View File

@ -0,0 +1,16 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}

View File

@ -0,0 +1,147 @@
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct DirLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct PointLight {
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct SpotLight {
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
#define NR_POINT_LIGHTS 4
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform DirLight dirLight;
uniform PointLight pointLights[NR_POINT_LIGHTS];
uniform SpotLight spotLight;
uniform Material material;
// function prototypes
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
void main()
{
// properties
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
// == =====================================================
// Our lighting is set up in 3 phases: directional, point lights and an optional flashlight
// For each phase, a calculate function is defined that calculates the corresponding color
// per lamp. In the main() function we take all the calculated colors and sum them up for
// this fragment's final color.
// == =====================================================
// phase 1: directional lighting
vec3 result = CalcDirLight(dirLight, norm, viewDir);
// phase 2: point lights
for(int i = 0; i < NR_POINT_LIGHTS; i++)
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
// phase 3: spot light
result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
FragColor = vec4(result, 1.0);
}
// calculates the color when using a directional light.
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
return (ambient + diffuse + specular);
}
// calculates the color when using a point light.
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
// calculates the color when using a spot light.
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// spotlight intensity
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
return (ambient + diffuse + specular);
}

View File

@ -0,0 +1,21 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoords = aTexCoords;
gl_Position = projection * view * vec4(FragPos, 1.0);
}

View File

@ -35,3 +35,27 @@ void main()
FragColor = texture(texture1, TexCoord); FragColor = texture(texture1, TexCoord);
} }
"#; "#;
pub const SH_FRAG_LAMP: &str = r#"
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0); // set alle 4 vector values to 1.0
}
"#;
pub const SH_VERT_LAMP: &str = r#"
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
"#;

View File

@ -0,0 +1,60 @@
use std::os::raw::c_void;
use std::path::Path;
use std::sync::mpsc::Receiver;
use gl;
extern crate glfw;
use self::glfw::{Action, Key};
use image;
use image::DynamicImage::*;
use image::GenericImage;
use image::*;
pub unsafe fn loadTexture(path: &str) -> u32 {
let mut textureID = 0;
gl::GenTextures(1, &mut textureID);
let img = image::open(&Path::new(path)).expect("Texture failed to load");
let format = match img {
ImageLuma8(_) => gl::RED,
ImageLumaA8(_) => gl::RG,
ImageRgb8(_) => gl::RGB,
ImageRgba8(_) => gl::RGBA,
_ => gl::RGB,
};
let data = img.raw_pixels();
let dim = img.dimensions();
gl::BindTexture(gl::TEXTURE_2D, textureID);
gl::TexImage2D(
gl::TEXTURE_2D,
0,
format as i32,
dim.0 as i32,
dim.1 as i32,
0,
format,
gl::UNSIGNED_BYTE,
&data[0] as *const u8 as *const c_void,
);
gl::GenerateMipmap(gl::TEXTURE_2D);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_MIN_FILTER,
gl::LINEAR_MIPMAP_LINEAR as i32,
);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
textureID
}
pub unsafe fn loadTextureFromDir(filename: &str, directory: &str) -> u32 {
let fullpath = format!("{}/{}", directory, filename);
loadTexture(&fullpath)
}

View File

@ -16,8 +16,11 @@ use std::ptr;
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
mod camera; mod camera;
mod consts; mod consts;
mod engine;
mod macros; mod macros;
mod shader; mod shader;
mod model;
mod mesh;
const CUBES_POS: [Vector3<f32>; 10] = [ const CUBES_POS: [Vector3<f32>; 10] = [
vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0),
@ -68,42 +71,91 @@ pub fn main() {
.expect("Failed to create GLFW window"); .expect("Failed to create GLFW window");
window.make_current(); window.make_current();
window.set_key_polling(true);
window.set_framebuffer_size_polling(true); window.set_framebuffer_size_polling(true);
window.set_cursor_pos_polling(true);
window.set_scroll_polling(true);
// tell GLFW to capture our mouse
window.set_cursor_mode(glfw::CursorMode::Disabled);
// gl: load all OpenGL function pointers // gl: load all OpenGL function pointers
// --------------------------------------- // ---------------------------------------
gl::load_with(|symbol| window.get_proc_address(symbol) as *const _); gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
let (shader_object, vbo, vao, texture) = unsafe { let (
lightingShader,
lampShader,
VBO,
cubeVAO,
lightVAO,
diffuseMap,
specularMap,
cubePositions,
pointLightPositions
) = unsafe {
// configure global opengl state
// -----------------------------
gl::Enable(gl::DEPTH_TEST); gl::Enable(gl::DEPTH_TEST);
let v_shader = CString::new(consts::VERTEX_SHADER_SRC.as_bytes()).unwrap();
let f_shader = CString::new(consts::FRAGMENT_SHADER_SRC.as_bytes()).unwrap(); // build and compile our shader program
let shader = crate::shader::Shader::new(v_shader, f_shader); // ------------------------------------
let lightingShader = shader::Shader::from_file(
"resources/shaders/multiple_lights.vs",
"resources/shaders/multiple_lights.fs",
);
let lampShader =
shader::Shader::from_file("resources/shaders/lamp.vs", "resources/shaders/lamp.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes // set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// HINT: type annotation is crucial since default for float literals is f64 let vertices: [f32; 288] = [
let vertices: [f32; 180] = [ // positions // normals // texture coords
-0.5, -0.5, -0.5, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, -0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 0.0, 0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 0.0,
0.5, -0.5, 1.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0, -0.5, -0.5, 0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0, 0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0,
0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, -0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 0.0,
1.0, -0.5, 0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 0.0, 0.5,
-0.5, 0.5, -0.5, 1.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, -0.5, 0.5,
-0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, -0.5, 0.5, 0.5,
-0.5, 1.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, 0.5, -1.0, 0.0, 0.0, 1.0, 0.0, -0.5, 0.5, -0.5, -1.0, 0.0, 0.0, 1.0, 1.0, -0.5, -0.5, -0.5,
0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, -0.5, -0.5, -0.5, -1.0, 0.0, 0.0, 0.0, 1.0, -0.5, -0.5, 0.5,
1.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -0.5, 0.5, 0.5, -1.0, 0.0, 0.0, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0,
-0.5, -0.5, -0.5, 0.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.0, 0.0, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 0.5, -0.5, -0.5, 1.0, 0.0,
0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, 0.5, -0.5, 0.0, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 1.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, -0.5, -0.5, -0.5, 0.0, -1.0, 0.0,
0.0, 1.0, 0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 1.0, 1.0, 0.5, -0.5, 0.5, 0.0, -1.0, 0.0,
1.0, 0.0, 0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, -1.0, 0.0,
0.0, 0.0, -0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 0.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, 0.0,
0.0, 1.0, 0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0,
0.0, 0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0,
-0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0,
]; ];
let (mut vbo, mut vao) = (0, 0); // positions all containers
gl::GenVertexArrays(1, &mut vao); let cubePositions: [Vector3<f32>; 10] = [
gl::GenBuffers(1, &mut vbo); vec3(0.0, 0.0, 0.0),
vec3(2.0, 5.0, -15.0),
vec3(-1.5, -2.2, -2.5),
vec3(-3.8, -2.0, -12.3),
vec3(2.4, -0.4, -3.5),
vec3(-1.7, 3.0, -7.5),
vec3(1.3, -2.0, -2.5),
vec3(1.5, 2.0, -2.5),
vec3(1.5, 0.2, -1.5),
vec3(-1.3, 1.0, -1.5),
];
// positions of the point lights
let pointLightPositions: [Vector3<f32>; 4] = [
vec3(0.7, 0.2, 2.0),
vec3(2.3, -3.3, -4.0),
vec3(-4.0, 2.0, -12.0),
vec3(0.0, 0.0, -3.0),
];
// first, configure the cube's VAO (and VBO)
let (mut VBO, mut cubeVAO) = (0, 0);
gl::GenVertexArrays(1, &mut cubeVAO);
gl::GenBuffers(1, &mut VBO);
gl::BindVertexArray(vao); gl::BindBuffer(gl::ARRAY_BUFFER, VBO);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData( gl::BufferData(
gl::ARRAY_BUFFER, gl::ARRAY_BUFFER,
(vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
@ -111,62 +163,67 @@ pub fn main() {
gl::STATIC_DRAW, gl::STATIC_DRAW,
); );
let stride = 5 * mem::size_of::<GLfloat>() as GLsizei; gl::BindVertexArray(cubeVAO);
// position attribute let stride = 8 * mem::size_of::<GLfloat>() as GLsizei;
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null()); gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null());
gl::EnableVertexAttribArray(0); gl::EnableVertexAttribArray(0);
// texture coord attribute
gl::VertexAttribPointer( gl::VertexAttribPointer(
1, 1,
2, 3,
gl::FLOAT, gl::FLOAT,
gl::FALSE, gl::FALSE,
stride, stride,
(3 * mem::size_of::<GLfloat>()) as *const c_void, (3 * mem::size_of::<GLfloat>()) as *const c_void,
); );
gl::EnableVertexAttribArray(1); gl::EnableVertexAttribArray(1);
gl::VertexAttribPointer(
// uncomment this call to draw in wireframe polygons. 2,
// gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); 2,
gl::FLOAT,
// ------------------------- gl::FALSE,
let mut texture = 0; stride,
gl::GenTextures(1, &mut texture); (6 * mem::size_of::<GLfloat>()) as *const c_void,
gl::BindTexture(gl::TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// set the texture wrapping parameters
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32); // set texture wrapping to gl::REPEAT (default wrapping method)
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
// set texture filtering parameters
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
// load image, create texture and generate mipmaps
let img = image::open("resources/garlic_dog_space.jpg")
.unwrap()
.flipv();
let data = img.raw_pixels();
// let data = flipped
let dimensions = (img.width(), img.height());
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGB as i32,
dimensions.0 as i32,
dimensions.1 as i32,
0,
gl::RGB,
gl::UNSIGNED_BYTE,
&data[0] as *const u8 as *const c_void,
); );
gl::GenerateMipmap(gl::TEXTURE_2D); gl::EnableVertexAttribArray(2);
(shader, vbo, vao, texture)
// second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube)
let mut lightVAO = 0;
gl::GenVertexArrays(1, &mut lightVAO);
gl::BindVertexArray(lightVAO);
gl::BindBuffer(gl::ARRAY_BUFFER, VBO);
// note that we update the lamp's position attribute's stride to reflect the updated buffer data
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null());
gl::EnableVertexAttribArray(0);
// load textures (we now use a utility function to keep the code more organized)
// -----------------------------------------------------------------------------
let diffuseMap = engine::loadTexture("resources/pattern.png");
let specularMap = engine::loadTexture("resources/textures/container2_specular.png");
// shader configuration
// --------------------
lightingShader.useProgram();
lightingShader.setInt(c_str!("material.diffuse"), 0);
lightingShader.setInt(c_str!("material.specular"), 1);
(
lightingShader,
lampShader,
VBO,
cubeVAO,
lightVAO,
diffuseMap,
specularMap,
cubePositions,
pointLightPositions
)
}; };
// render loop // render loop
// ----------- // -----------
let color_r = 0.188; let (r, g, b) = (0.188, 0.22, 0.235);
let color_g = 0.22;
let color_b = 0.235;
while !window.should_close() { while !window.should_close() {
// per-frame time logic // per-frame time logic
// -------------------- // --------------------
@ -188,39 +245,124 @@ pub fn main() {
// ----- // -----
process_input(&mut window, delta_time, &mut camera); process_input(&mut window, delta_time, &mut camera);
// render
// ------
// render // render
// ------ // ------
unsafe { unsafe {
gl::ClearColor(color_r, color_g, color_b, 1.0); gl::ClearColor(r, g, b, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
gl::BindTexture(gl::TEXTURE_2D, texture); // be sure to activate shader when setting uniforms/drawing objects
shader_object.useProgram(); lightingShader.useProgram();
lightingShader.setVector3(c_str!("viewPos"), &camera.Position.to_vec());
lightingShader.setFloat(c_str!("material.shininess"), 32.0);
/*
Here we set all the uniforms for the 5/6 types of lights we have. We have to set them manually and index
the proper PointLight struct in the array to set each uniform variable. This can be done more code-friendly
by defining light types as classes and set their values in there, or by using a more efficient uniform approach
by using 'Uniform buffer objects', but that is something we'll discuss in the 'Advanced GLSL' tutorial.
*/
// directional light
lightingShader.setVec3(c_str!("dirLight.direction"), -0.2, -1.0, -0.3);
lightingShader.setVec3(c_str!("dirLight.ambient"), 0.05, 0.05, 0.05);
lightingShader.setVec3(c_str!("dirLight.diffuse"), 0.4, 0.4, 0.4);
lightingShader.setVec3(c_str!("dirLight.specular"), 0.5, 0.5, 0.5);
// point light 1
lightingShader.setVector3(c_str!("pointLights[0].position"), &pointLightPositions[0]);
lightingShader.setVec3(c_str!("pointLights[0].ambient"), 0.05, 0.05, 0.05);
lightingShader.setVec3(c_str!("pointLights[0].diffuse"), 0.8, 0.8, 0.8);
lightingShader.setVec3(c_str!("pointLights[0].specular"), 1.0, 1.0, 1.0);
lightingShader.setFloat(c_str!("pointLights[0].constant"), 1.0);
lightingShader.setFloat(c_str!("pointLights[0].linear"), 0.09);
lightingShader.setFloat(c_str!("pointLights[0].quadratic"), 0.032);
// point light 2
lightingShader.setVector3(c_str!("pointLights[1].position"), &pointLightPositions[1]);
lightingShader.setVec3(c_str!("pointLights[1].ambient"), 0.05, 0.05, 0.05);
lightingShader.setVec3(c_str!("pointLights[1].diffuse"), 0.8, 0.8, 0.8);
lightingShader.setVec3(c_str!("pointLights[1].specular"), 1.0, 1.0, 1.0);
lightingShader.setFloat(c_str!("pointLights[1].constant"), 1.0);
lightingShader.setFloat(c_str!("pointLights[1].linear"), 0.09);
lightingShader.setFloat(c_str!("pointLights[1].quadratic"), 0.032);
// point light 3
lightingShader.setVector3(c_str!("pointLights[2].position"), &pointLightPositions[2]);
lightingShader.setVec3(c_str!("pointLights[2].ambient"), 0.05, 0.05, 0.05);
lightingShader.setVec3(c_str!("pointLights[2].diffuse"), 0.8, 0.8, 0.8);
lightingShader.setVec3(c_str!("pointLights[2].specular"), 1.0, 1.0, 1.0);
lightingShader.setFloat(c_str!("pointLights[2].constant"), 1.0);
lightingShader.setFloat(c_str!("pointLights[2].linear"), 0.09);
lightingShader.setFloat(c_str!("pointLights[2].quadratic"), 0.032);
// point light 4
lightingShader.setVector3(c_str!("pointLights[3].position"), &pointLightPositions[3]);
lightingShader.setVec3(c_str!("pointLights[3].ambient"), 0.05, 0.05, 0.05);
lightingShader.setVec3(c_str!("pointLights[3].diffuse"), 0.8, 0.8, 0.8);
lightingShader.setVec3(c_str!("pointLights[3].specular"), 1.0, 1.0, 1.0);
lightingShader.setFloat(c_str!("pointLights[3].constant"), 1.0);
lightingShader.setFloat(c_str!("pointLights[3].linear"), 0.09);
lightingShader.setFloat(c_str!("pointLights[3].quadratic"), 0.032);
// spotLight
lightingShader.setVector3(c_str!("spotLight.position"), &camera.Position.to_vec());
lightingShader.setVector3(c_str!("spotLight.direction"), &camera.Front);
lightingShader.setVec3(c_str!("spotLight.ambient"), 0.0, 0.0, 0.0);
lightingShader.setVec3(c_str!("spotLight.diffuse"), 1.0, 1.0, 1.0);
lightingShader.setVec3(c_str!("spotLight.specular"), 1.0, 1.0, 1.0);
lightingShader.setFloat(c_str!("spotLight.constant"), 1.0);
lightingShader.setFloat(c_str!("spotLight.linear"), 0.09);
lightingShader.setFloat(c_str!("spotLight.quadratic"), 0.032);
lightingShader.setFloat(c_str!("spotLight.cutOff"), 12.5f32.to_radians().cos());
lightingShader.setFloat(c_str!("spotLight.outerCutOff"), 15.0f32.to_radians().cos());
// pass projection matrix to shader (note that in this case it could change every frame) // view/projection transformations
let projection: Matrix4<f32> = perspective( let projection: Matrix4<f32> = perspective(
Deg(camera.Zoom), Deg(camera.Zoom),
consts::SCR_WIDTH as f32 / consts::SCR_HEIGHT as f32, consts::SCR_WIDTH as f32 / consts::SCR_HEIGHT as f32,
0.1, 0.1,
100.0, 100.0,
); );
shader_object.setMat4(c_str!("projection"), &projection);
// camera/view transformation
let view = camera.get_view_matrix(); let view = camera.get_view_matrix();
shader_object.setMat4(c_str!("view"), &view); lightingShader.setMat4(c_str!("projection"), &projection);
lightingShader.setMat4(c_str!("view"), &view);
gl::BindVertexArray(vao); // world transformation
for (i, position) in CUBES_POS.iter().enumerate() { let mut model = Matrix4::<f32>::identity();
lightingShader.setMat4(c_str!("model"), &model);
// bind diffuse map
gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, diffuseMap);
// bind specular map
gl::ActiveTexture(gl::TEXTURE1);
gl::BindTexture(gl::TEXTURE_2D, specularMap);
// render containers
gl::BindVertexArray(cubeVAO);
for (i, position) in cubePositions.iter().enumerate() {
// calculate the model matrix for each object and pass it to shader before drawing // calculate the model matrix for each object and pass it to shader before drawing
let mut model: Matrix4<f32> = Matrix4::from_translation(*position); let mut model: Matrix4<f32> = Matrix4::from_translation(*position);
let angle = 20.0 * i as f32; let angle = 20.0 * i as f32;
// don't forget to normalize the axis!
model = model =
model * Matrix4::from_axis_angle(vec3(1.0, 0.3, 0.5).normalize(), Deg(angle)); model * Matrix4::from_axis_angle(vec3(1.0, 0.3, 0.5).normalize(), Deg(angle));
shader_object.setMat4(c_str!("model"), &model); lightingShader.setMat4(c_str!("model"), &model);
gl::DrawArrays(gl::TRIANGLES, 0, 36); gl::DrawArrays(gl::TRIANGLES, 0, 36);
} }
// also draw the lamp object(s)
lampShader.useProgram();
lampShader.setMat4(c_str!("projection"), &projection);
lampShader.setMat4(c_str!("view"), &view);
// we now draw as many light bulbs as we have point lights.
gl::BindVertexArray(lightVAO);
for position in &pointLightPositions {
model = Matrix4::from_translation(*position);
model = model * Matrix4::from_scale(0.2); // Make it a smaller cube
lampShader.setMat4(c_str!("model"), &model);
gl::DrawArrays(gl::TRIANGLES, 0, 36);
}
} }
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
@ -230,8 +372,9 @@ pub fn main() {
} }
unsafe { unsafe {
gl::DeleteVertexArrays(1, &vao); gl::DeleteVertexArrays(1, &cubeVAO);
gl::DeleteBuffers(1, &vbo); gl::DeleteVertexArrays(1, &lightVAO);
gl::DeleteBuffers(1, &VBO);
} }
} }

162
src/mesh.rs Normal file
View File

@ -0,0 +1,162 @@
#![allow(non_snake_case)]
#![allow(dead_code)]
use std::ffi::CString;
use std::mem::size_of;
use std::os::raw::c_void;
use std::ptr;
use cgmath::{ Vector3, Vector2 };
use cgmath::prelude::*;
use gl;
use crate::shader::Shader;
// NOTE: without repr(C) the compiler may reorder the fields or use different padding/alignment than C.
// Depending on how you pass the data to OpenGL, this may be bad. In this case it's not strictly
// necessary though because of the `offset!` macro used below in setupMesh()
#[repr(C)]
pub struct Vertex {
// position
pub Position: Vector3<f32>,
// normal
pub Normal: Vector3<f32>,
// texCoords
pub TexCoords: Vector2<f32>,
// tangent
pub Tangent: Vector3<f32>,
// bitangent
pub Bitangent: Vector3<f32>,
}
impl Default for Vertex {
fn default() -> Self {
Vertex {
Position: Vector3::zero(),
Normal: Vector3::zero(),
TexCoords: Vector2::zero(),
Tangent: Vector3::zero(),
Bitangent: Vector3::zero(),
}
}
}
#[derive(Clone)]
pub struct Texture {
pub id: u32,
pub type_: String,
pub path: String,
}
pub struct Mesh {
/* Mesh Data */
pub vertices: Vec<Vertex>,
pub indices: Vec<u32>,
pub textures: Vec<Texture>,
pub VAO: u32,
/* Render data */
VBO: u32,
EBO: u32,
}
impl Mesh {
pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Mesh {
let mut mesh = Mesh {
vertices, indices, textures,
VAO: 0, VBO: 0, EBO: 0
};
// now that we have all the required data, set the vertex buffers and its attribute pointers.
unsafe { mesh.setupMesh() }
mesh
}
/// render the mesh
pub unsafe fn Draw(&self, shader: &Shader) {
// bind appropriate textures
let mut diffuseNr = 0;
let mut specularNr = 0;
let mut normalNr = 0;
let mut heightNr = 0;
for (i, texture) in self.textures.iter().enumerate() {
gl::ActiveTexture(gl::TEXTURE0 + i as u32); // active proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
let name = &texture.type_;
let number = match name.as_str() {
"texture_diffuse" => {
diffuseNr += 1;
diffuseNr
},
"texture_specular" => {
specularNr += 1;
specularNr
}
"texture_normal" => {
normalNr += 1;
normalNr
}
"texture_height" => {
heightNr += 1;
heightNr
}
_ => panic!("unknown texture type")
};
// now set the sampler to the correct texture unit
let sampler = CString::new(format!("{}{}", name, number)).unwrap();
gl::Uniform1i(gl::GetUniformLocation(shader.ID, sampler.as_ptr()), i as i32);
// and finally bind the texture
gl::BindTexture(gl::TEXTURE_2D, texture.id);
}
// draw mesh
gl::BindVertexArray(self.VAO);
gl::DrawElements(gl::TRIANGLES, self.indices.len() as i32, gl::UNSIGNED_INT, ptr::null());
gl::BindVertexArray(0);
// always good practice to set everything back to defaults once configured.
gl::ActiveTexture(gl::TEXTURE0);
}
unsafe fn setupMesh(&mut self) {
// create buffers/arrays
gl::GenVertexArrays(1, &mut self.VAO);
gl::GenBuffers(1, &mut self.VBO);
gl::GenBuffers(1, &mut self.EBO);
gl::BindVertexArray(self.VAO);
// load data into vertex buffers
gl::BindBuffer(gl::ARRAY_BUFFER, self.VBO);
// A great thing about structs with repr(C) is that their memory layout is sequential for all its items.
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which
// again translates to 3/2 floats which translates to a byte array.
let size = (self.vertices.len() * size_of::<Vertex>()) as isize;
let data = &self.vertices[0] as *const Vertex as *const c_void;
gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.EBO);
let size = (self.indices.len() * size_of::<u32>()) as isize;
let data = &self.indices[0] as *const u32 as *const c_void;
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size, data, gl::STATIC_DRAW);
// set the vertex attribute pointers
let size = size_of::<Vertex>() as i32;
// vertex Positions
gl::EnableVertexAttribArray(0);
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Position) as *const c_void);
// vertex normals
gl::EnableVertexAttribArray(1);
gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Normal) as *const c_void);
// vertex texture coords
gl::EnableVertexAttribArray(2);
gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, TexCoords) as *const c_void);
// vertex tangent
gl::EnableVertexAttribArray(3);
gl::VertexAttribPointer(3, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Tangent) as *const c_void);
// vertex bitangent
gl::EnableVertexAttribArray(4);
gl::VertexAttribPointer(4, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Bitangent) as *const c_void);
gl::BindVertexArray(0);
}
}

117
src/model.rs Normal file
View File

@ -0,0 +1,117 @@
#![allow(non_snake_case)]
#![allow(dead_code)]
use std::os::raw::c_void;
use std::path::Path;
use cgmath::{vec2, vec3};
use gl;
use image;
use image::DynamicImage::*;
use image::GenericImage;
use tobj;
use crate::mesh::{ Mesh, Texture, Vertex };
use crate::shader::Shader;
use crate::engine::*;
// #[derive(Default)]
pub struct Model {
/* Model Data */
pub meshes: Vec<Mesh>,
pub textures_loaded: Vec<Texture>, // stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once.
directory: String,
}
impl Model {
/// constructor, expects a filepath to a 3D model.
pub fn new(path: &str) -> Model {
let pathObj = Path::new(path);
let mut model = Model{
meshes: Vec::<Mesh>::new(),
textures_loaded: Vec::<Texture>::new(),
directory: pathObj.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into()
};
model.loadModel(path);
model
}
pub fn Draw(&self, shader: &Shader) {
for mesh in &self.meshes {
unsafe { mesh.Draw(shader); }
}
}
// loads a model from file and stores the resulting meshes in the meshes vector.
fn loadModel(&mut self, path: &str) {
let path = Path::new(path);
// retrieve the directory path of the filepath
self.directory = path.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into();
let obj = tobj::load_obj(path, true);
let (models, materials) = obj.unwrap();
for model in models {
let mesh = &model.mesh;
let num_vertices = mesh.positions.len() / 3;
// data to fill
let mut vertices: Vec<Vertex> = Vec::with_capacity(num_vertices);
let indices: Vec<u32> = mesh.indices.clone();
let (p, n, t) = (&mesh.positions, &mesh.normals, &mesh.texcoords);
for i in 0..num_vertices {
vertices.push(Vertex {
Position: vec3(p[i*3], p[i*3+1], p[i*3+2]),
Normal: vec3(n[i*3], n[i*3+1], n[i*3+2]),
TexCoords: vec2(t[i*2], t[i*2+1]),
..Vertex::default()
})
}
// process material
let mut textures = Vec::new();
if let Some(material_id) = mesh.material_id {
let material = &materials[material_id];
// 1. diffuse map
if !material.diffuse_texture.is_empty() {
let texture = self.loadMaterialTexture(&material.diffuse_texture, "texture_diffuse");
textures.push(texture);
}
// 2. specular map
if !material.specular_texture.is_empty() {
let texture = self.loadMaterialTexture(&material.specular_texture, "texture_specular");
textures.push(texture);
}
// 3. normal map
if !material.normal_texture.is_empty() {
let texture = self.loadMaterialTexture(&material.normal_texture, "texture_normal");
textures.push(texture);
}
// NOTE: no height maps
}
self.meshes.push(Mesh::new(vertices, indices, textures));
}
}
fn loadMaterialTexture(&mut self, path: &str, typeName: &str) -> Texture {
{
let texture = self.textures_loaded.iter().find(|t| t.path == path);
if let Some(texture) = texture {
return texture.clone();
}
}
let texture = Texture {
id: unsafe { loadTextureFromDir(path, &self.directory) },
type_: typeName.into(),
path: path.into()
};
self.textures_loaded.push(texture.clone());
texture
}
}