added Model.rs
parent
5fa37d5f06
commit
19a8b30997
|
@ -8,8 +8,9 @@ edition = "2021"
|
|||
[dependencies]
|
||||
gl = "0.14.0"
|
||||
glm = "0.2.3"
|
||||
stb = { version = "0.3.2", default-features = false, features = ["stb_image"] }
|
||||
field-offset = "0.3.4"
|
||||
|
||||
image = "0.24.5"
|
||||
tobj = "3.2.4"
|
||||
cgmath = "0.18.0"
|
||||
[dependencies.glfw]
|
||||
version = "*"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
|
@ -0,0 +1,16 @@
|
|||
# Blender MTL File: 'None'
|
||||
# Material Count: 1
|
||||
|
||||
newmtl Scene_-_Root
|
||||
Ns 225.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.800000 0.800000 0.800000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.0 0.0 0.0
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd diffuse.jpg
|
||||
map_Bump normal.png
|
||||
map_Ks specular.jpg
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 5.8 MiB |
Binary file not shown.
After Width: | Height: | Size: 14 MiB |
Binary file not shown.
After Width: | Height: | Size: 4.2 MiB |
|
@ -0,0 +1,3 @@
|
|||
Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36
|
||||
|
||||
Modified material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup.
|
Binary file not shown.
After Width: | Height: | Size: 6.4 MiB |
|
@ -0,0 +1,12 @@
|
|||
|
||||
#version 330 core
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec2 TexCoords;
|
||||
|
||||
uniform sampler2D texture_diffuse1;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = texture(texture_diffuse1, TexCoords);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
#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,6 @@
|
|||
#version 330 core
|
||||
out vec4 Color;
|
||||
void main()
|
||||
{
|
||||
Color = vec4(0.9, 0.5, 0.2, 1.0);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec3 position;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(position, 1.0);
|
||||
// gl_Position = vec4(position.xyz, 1.0);
|
||||
// gl_Position = vec4(position.x, position.y, position.z, 1.0);
|
||||
}
|
19
src/main.rs
19
src/main.rs
|
@ -3,14 +3,15 @@ use std::convert::TryInto;
|
|||
use glfw;
|
||||
use glfw::{Action, Context, Key};
|
||||
use gl;
|
||||
use cgmath::{Matrix4, vec3, Point3, Deg, perspective};
|
||||
|
||||
const ScreenWidth: u32 = 480;
|
||||
const ScreenHeight: u32 = 320;
|
||||
const TITLE: &str = "GLFWtest";
|
||||
|
||||
mod shader;
|
||||
mod mesh;
|
||||
|
||||
mod model;
|
||||
use model::Model;
|
||||
fn main() {
|
||||
|
||||
// initialize GLFW
|
||||
|
@ -37,11 +38,13 @@ fn main() {
|
|||
unsafe {
|
||||
gl::Viewport(0, 0, screen_width, screen_height);
|
||||
gl::ClearColor(1.0, 1.0, 1.0, 1.0);
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
}
|
||||
|
||||
|
||||
// put biggie thingies here
|
||||
let test_Shader = shader::shader::new("basic");
|
||||
let model_Shader = shader::shader::new("model");
|
||||
let ourModel = Model::new("backpack/backpack.obj");
|
||||
|
||||
// NOTE window loop
|
||||
while !window.should_close() {
|
||||
|
@ -50,13 +53,17 @@ fn main() {
|
|||
glfw_handle_event(&mut window, event);
|
||||
}
|
||||
|
||||
clear_color(0.1, 0.1, 0.1, -0.0);
|
||||
model_Shader.Use();
|
||||
|
||||
|
||||
// view/projection transformations
|
||||
//let projection:;
|
||||
|
||||
|
||||
unsafe {
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
}
|
||||
};
|
||||
|
||||
test_Shader.Use();
|
||||
|
||||
window.swap_buffers();
|
||||
}
|
||||
|
|
98
src/mesh.rs
98
src/mesh.rs
|
@ -1,98 +0,0 @@
|
|||
|
||||
use field_offset::offset_of;
|
||||
|
||||
pub struct Vertex {
|
||||
Position: glm::Vec3,
|
||||
Normal: glm::Vec2,
|
||||
TexCoords: glm::Vec2,
|
||||
Tangent: glm::Vec3,
|
||||
Bitangent: glm::Vec3,
|
||||
m_BoneIDs: [i32; 4],
|
||||
m_Weights: [f32; 4],
|
||||
}
|
||||
|
||||
pub struct Texture {
|
||||
id: u32,
|
||||
Type: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
struct Mesh {
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Vec<u32>,
|
||||
pub textures: Vec<Texture>,
|
||||
pub VAO: Option<u32>,
|
||||
VBO: Option<u32>,
|
||||
EBO: Option<u32>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
impl Mesh{
|
||||
pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>)
|
||||
{
|
||||
let mut temp = Mesh {
|
||||
vertices,
|
||||
indices,
|
||||
textures,
|
||||
VAO: None,
|
||||
VBO: None,
|
||||
EBO: None,
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
fn setupMesh(mut temp: Mesh)
|
||||
{
|
||||
// create buffers/arrays
|
||||
|
||||
unsafe {
|
||||
|
||||
gl::GenVertexArrays(1, temp.VAO.as_mut().unwrap());
|
||||
gl::GenBuffers(1, temp.VBO.as_mut().unwrap());
|
||||
gl::GenBuffers(1, temp.EBO.as_mut().unwrap());
|
||||
|
||||
gl::BindVertexArray(temp.VAO.unwrap());
|
||||
|
||||
|
||||
// NOTE, i am not sure if this one will work
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, temp.VBO.unwrap());
|
||||
gl::BufferData(gl::ARRAY_BUFFER, std::mem::size_of_val(&temp.vertices) as isize, temp.vertices.as_ptr().cast(), gl::STATIC_DRAW);
|
||||
|
||||
// the vertex attribPointers
|
||||
// vert pox
|
||||
gl::EnableVertexAttribArray(0);
|
||||
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, 0 as *const _);
|
||||
// vertex normals
|
||||
gl::EnableVertexAttribArray(1);
|
||||
gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => Normal).get_byte_offset() as *const _);
|
||||
|
||||
// vertex texture coords
|
||||
|
||||
gl::EnableVertexAttribArray(2);
|
||||
gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => TexCoords).get_byte_offset() as *const _);
|
||||
|
||||
//vertex tangent
|
||||
|
||||
gl::EnableVertexAttribArray(3);
|
||||
gl::VertexAttribPointer(3, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => Tangent).get_byte_offset() as *const _);
|
||||
|
||||
// vertex Bitangent
|
||||
|
||||
gl::EnableVertexAttribArray(4);
|
||||
gl::VertexAttribPointer(4, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => Bitangent).get_byte_offset() as *const _);
|
||||
|
||||
// ids
|
||||
gl::EnableVertexAttribArray(5);
|
||||
gl::VertexAttribIPointer(5, 4, gl::INT, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => m_BoneIDs).get_byte_offset() as *const _);
|
||||
|
||||
// weights
|
||||
gl::EnableVertexAttribArray(6);
|
||||
gl::VertexAttribPointer(6, 4, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => m_Weights).get_byte_offset() as *const _);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
use image::GenericImage;
|
||||
use std::path::Path;
|
||||
use crate::shader::shader;
|
||||
mod mesh;
|
||||
use tobj;
|
||||
use cgmath::{vec2, vec3};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Model
|
||||
{
|
||||
pub textures_loaded: Vec<mesh::Texture>,
|
||||
pub meshes: Vec<mesh::Mesh>,
|
||||
directory: String,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
pub fn new(path: &str) -> Model {
|
||||
let mut model = Model::default();
|
||||
model.loadModel(path);
|
||||
model
|
||||
}
|
||||
|
||||
|
||||
pub fn Draw(&self, shader: shader) {
|
||||
for mesh in &self.meshes {
|
||||
unsafe { mesh.Draw(&shader); }
|
||||
}
|
||||
}
|
||||
|
||||
fn loadModel(&mut self, path: &str) {
|
||||
let path = Path::new(path);
|
||||
|
||||
|
||||
self.directory = path.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into();
|
||||
let obj = tobj::load_obj(path, &tobj::LoadOptions::default());
|
||||
|
||||
let (models, materials) = obj.unwrap();
|
||||
for model in models {
|
||||
let mesh = &model.mesh;
|
||||
let num_vertices = mesh.positions.len() / 3;
|
||||
|
||||
|
||||
let mut vertices: Vec<mesh::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(mesh::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]),
|
||||
..mesh::Vertex::default()
|
||||
})
|
||||
}
|
||||
|
||||
// process
|
||||
let mut textures = Vec::new();
|
||||
if let Some(material_id) = mesh.material_id {
|
||||
let material = &materials.as_ref().unwrap()[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
|
||||
//
|
||||
if !material.normal_texture.is_empty() {
|
||||
let texture = self.loadMaterialTexture(&material.normal_texture, "texture_normal");
|
||||
textures.push(texture);
|
||||
}
|
||||
}
|
||||
self.meshes.push(mesh::Mesh::new(vertices,indices, textures));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn loadMaterialTexture(&mut self, path: &str, typeName: &str) -> mesh::Texture {
|
||||
{
|
||||
let texture = self.textures_loaded.iter().find(|t| t.path == path);
|
||||
if let Some(texture) = texture {
|
||||
return texture.clone();
|
||||
}
|
||||
}
|
||||
let texture = mesh::Texture {
|
||||
id: TextureFromFile(path),
|
||||
type_: typeName.into(),
|
||||
path: path.into()
|
||||
};
|
||||
self.textures_loaded.push(texture.clone());
|
||||
texture
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fn TextureFromFile(path: &str) -> u32
|
||||
{
|
||||
let filename = format!("resources/models/{}", path);
|
||||
|
||||
let mut textureID = 0;
|
||||
|
||||
unsafe {
|
||||
// NOTE might become a problem later on
|
||||
gl::GenTextures(1, textureID as *mut u32);
|
||||
gl::BindTexture(gl::TEXTURE_2D, textureID);
|
||||
|
||||
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 as i32);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
|
||||
|
||||
let img = image::open(Path::new(&filename)).expect("Failed to load Texture");
|
||||
img.flipv();
|
||||
let format = match img {
|
||||
image::DynamicImage::ImageLuma8(_) => gl::RED,
|
||||
image::DynamicImage::ImageLumaA8(_) => gl::RG,
|
||||
image::DynamicImage::ImageRgb8(_) => gl::RGB,
|
||||
image::DynamicImage::ImageRgba8(_) => gl::RGBA,
|
||||
_ => panic!("What is this image u gave me big man?")
|
||||
};
|
||||
let data = img.as_bytes();
|
||||
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
format as i32,
|
||||
img.width() as i32,
|
||||
img.height() as i32,
|
||||
0,
|
||||
format,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&data[0] as *const u8 as *const std::os::raw::c_void);
|
||||
gl::GenerateMipmap(gl::TEXTURE_2D);
|
||||
}
|
||||
|
||||
textureID
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use field_offset::offset_of;
|
||||
|
||||
use cgmath::{Vector3, Vector2};
|
||||
use cgmath::prelude::*;
|
||||
|
||||
pub struct Vertex {
|
||||
pub Position: Vector3<f32>,
|
||||
pub Normal: Vector3<f32>,
|
||||
pub TexCoords: Vector2<f32>,
|
||||
pub Tangent: Vector3<f32>,
|
||||
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,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Mesh {
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Vec<u32>,
|
||||
pub textures: Vec<Texture>,
|
||||
pub VAO: u32,
|
||||
VBO: u32,
|
||||
EBO: u32,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
impl Mesh{
|
||||
pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Mesh
|
||||
{
|
||||
let mut temp = Mesh {
|
||||
vertices,
|
||||
indices,
|
||||
textures,
|
||||
VAO: 0,
|
||||
VBO: 0,
|
||||
EBO: 0,
|
||||
};
|
||||
temp.setupMesh();
|
||||
temp
|
||||
|
||||
}
|
||||
|
||||
fn setupMesh(&mut self)
|
||||
{
|
||||
// create buffers/arrays
|
||||
|
||||
unsafe {
|
||||
|
||||
gl::GenVertexArrays(1, &mut self.VAO);
|
||||
gl::GenBuffers(1, &mut self.VBO);
|
||||
gl::GenBuffers(1, &mut self.EBO);
|
||||
|
||||
gl::BindVertexArray(self.VAO);
|
||||
|
||||
let size = (self.vertices.len() * std::mem::size_of::<Vertex>()) as isize;
|
||||
|
||||
// NOTE, i am not sure if this one will work
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, self.VBO);
|
||||
gl::BufferData(gl::ARRAY_BUFFER, size, self.vertices.as_ptr().cast(), gl::STATIC_DRAW);
|
||||
|
||||
// the vertex attribPointers
|
||||
// vert pox
|
||||
gl::EnableVertexAttribArray(0);
|
||||
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, 0 as *const _);
|
||||
// vertex normals
|
||||
gl::EnableVertexAttribArray(1);
|
||||
gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => Normal).get_byte_offset() as *const std::os::raw::c_void);
|
||||
|
||||
// vertex texture coords
|
||||
|
||||
gl::EnableVertexAttribArray(2);
|
||||
gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => TexCoords).get_byte_offset() as *const std::os::raw::c_void);
|
||||
|
||||
//vertex tangent
|
||||
|
||||
gl::EnableVertexAttribArray(3);
|
||||
gl::VertexAttribPointer(3, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => Tangent).get_byte_offset() as *const std::os::raw::c_void);
|
||||
|
||||
// vertex Bitangent
|
||||
|
||||
gl::EnableVertexAttribArray(4);
|
||||
gl::VertexAttribPointer(4, 3, gl::FLOAT, gl::FALSE, std::mem::size_of::<Vertex>() as i32, offset_of!(Vertex => Bitangent).get_byte_offset() as *const std::os::raw::c_void);
|
||||
|
||||
gl::BindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
// TODO this
|
||||
pub fn Draw(&self, shader: &crate::shader::shader)
|
||||
{
|
||||
let mut diffuseNr = 0;
|
||||
let mut specularNr = 0;
|
||||
let mut normalNr = 0;
|
||||
let mut heightNr = 0;
|
||||
for (i, texture) in self.textures.iter().enumerate() {
|
||||
unsafe {gl::ActiveTexture(gl::TEXTURE0 + i as u32)};
|
||||
|
||||
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")
|
||||
};
|
||||
|
||||
// set the sampler to the correct texture unit
|
||||
let sampler = format!("{}{}", name, number);
|
||||
unsafe{
|
||||
shader.setInt( &(sampler as String), i as u32 );
|
||||
|
||||
gl::BindTexture(gl::TEXTURE_2D, texture.id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -93,7 +93,7 @@ use glm;
|
|||
unsafe {gl::UseProgram(self.ID);}
|
||||
}
|
||||
|
||||
// TODO write tests for these
|
||||
|
||||
// BOILERPLATE JUMPSCARE
|
||||
pub fn setBool(&self, name: &str, value: bool )
|
||||
{unsafe {gl::Uniform1i(gl::GetUniformLocation(self.ID, name.as_ptr() as *const gl::types::GLchar), value as i32);}}
|
||||
|
|
Loading…
Reference in New Issue