mirror of https://github.com/Leinnan/doppler.git
Lighting
This commit is contained in:
parent
7ce2f9830a
commit
b8b0a46361
|
|
@ -1 +1,4 @@
|
||||||
/target
|
/target
|
||||||
|
**png
|
||||||
|
**jpg
|
||||||
|
**jpeg
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = vec4(1.0); // set alle 4 vector values to 1.0
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
in vec2 TexCoords;
|
||||||
|
|
||||||
|
uniform sampler2D texture_diffuse1;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = texture(texture_diffuse1, TexCoords);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
301
src/main.rs
301
src/main.rs
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue