mirror of
https://github.com/IllusionMan1212/3dobs.git
synced 2026-10-24 10:12:35 +00:00
feat: basic texture support
- add texture support (ambient, diffuse, specular) - use opacity in fragment shader - calculate normal matrix on cpu for matricies with big determinants
This commit is contained in:
+45
-51
@@ -6,43 +6,15 @@ in vec2 texCoords;
|
|||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
struct Material {
|
struct Material {
|
||||||
sampler2D texture_diffuse1;
|
sampler2D texture_diffuse;
|
||||||
sampler2D texture_diffuse2;
|
sampler2D texture_specular;
|
||||||
sampler2D texture_diffuse3;
|
sampler2D texture_ambient;
|
||||||
sampler2D texture_diffuse4;
|
|
||||||
sampler2D texture_diffuse5;
|
|
||||||
sampler2D texture_diffuse6;
|
|
||||||
sampler2D texture_diffuse7;
|
|
||||||
sampler2D texture_diffuse8;
|
|
||||||
sampler2D texture_diffuse9;
|
|
||||||
sampler2D texture_diffuse10;
|
|
||||||
sampler2D texture_diffuse11;
|
|
||||||
sampler2D texture_diffuse12;
|
|
||||||
sampler2D texture_diffuse13;
|
|
||||||
sampler2D texture_diffuse14;
|
|
||||||
sampler2D texture_diffuse15;
|
|
||||||
sampler2D texture_diffuse16;
|
|
||||||
sampler2D texture_specular1;
|
|
||||||
sampler2D texture_specular2;
|
|
||||||
sampler2D texture_specular3;
|
|
||||||
sampler2D texture_specular4;
|
|
||||||
sampler2D texture_specular5;
|
|
||||||
sampler2D texture_specular6;
|
|
||||||
sampler2D texture_specular7;
|
|
||||||
sampler2D texture_specular8;
|
|
||||||
sampler2D texture_specular9;
|
|
||||||
sampler2D texture_specular10;
|
|
||||||
sampler2D texture_specular11;
|
|
||||||
sampler2D texture_specular12;
|
|
||||||
sampler2D texture_specular13;
|
|
||||||
sampler2D texture_specular14;
|
|
||||||
sampler2D texture_specular15;
|
|
||||||
sampler2D texture_specular16;
|
|
||||||
|
|
||||||
vec3 ambient;
|
vec3 ambient;
|
||||||
vec3 diffuse;
|
vec3 diffuse;
|
||||||
vec3 specular;
|
vec3 specular;
|
||||||
float shininess;
|
float shininess;
|
||||||
|
float opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DirLight {
|
struct DirLight {
|
||||||
@@ -88,6 +60,7 @@ uniform Material material;
|
|||||||
uniform DirLight dirLight;
|
uniform DirLight dirLight;
|
||||||
uniform PointLight pointLights[NR_POINT_LIGHTS];
|
uniform PointLight pointLights[NR_POINT_LIGHTS];
|
||||||
uniform SpotLight spotLight;
|
uniform SpotLight spotLight;
|
||||||
|
uniform bool useTextures;
|
||||||
|
|
||||||
vec3 CalculateDirLight(DirLight light, vec3 normal, vec3 viewDir) {
|
vec3 CalculateDirLight(DirLight light, vec3 normal, vec3 viewDir) {
|
||||||
vec3 lightDir = normalize(-light.direction);
|
vec3 lightDir = normalize(-light.direction);
|
||||||
@@ -103,12 +76,19 @@ vec3 CalculateDirLight(DirLight light, vec3 normal, vec3 viewDir) {
|
|||||||
spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
}
|
}
|
||||||
|
|
||||||
//vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, texCoords)) * material.ambient;
|
vec3 ambient = vec3(0.0, 0.0, 0.0);
|
||||||
//vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, texCoords)) * material.diffuse;
|
vec3 diffuse = vec3(0.0, 0.0, 0.0);
|
||||||
//vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, texCoords)) * material.specular;
|
vec3 specular = vec3(0.0, 0.0, 0.0);
|
||||||
vec3 ambient = light.ambient * material.ambient;
|
|
||||||
vec3 diffuse = light.diffuse * (diff * material.diffuse);
|
if (useTextures) {
|
||||||
vec3 specular = light.specular * (spec * material.specular);
|
ambient = light.ambient * vec3(texture(material.texture_ambient, texCoords)) * material.ambient;
|
||||||
|
diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse, texCoords)) * material.diffuse;
|
||||||
|
specular = light.specular * spec * vec3(texture(material.texture_specular, texCoords)) * material.specular;
|
||||||
|
} else {
|
||||||
|
ambient = light.ambient * material.ambient;
|
||||||
|
diffuse = light.diffuse * (diff * material.diffuse);
|
||||||
|
specular = light.specular * (spec * material.specular);
|
||||||
|
}
|
||||||
|
|
||||||
return (ambient + diffuse + specular);
|
return (ambient + diffuse + specular);
|
||||||
}
|
}
|
||||||
@@ -131,12 +111,19 @@ vec3 CalculatePointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewD
|
|||||||
float distance = length(light.position - fragPos);
|
float distance = length(light.position - fragPos);
|
||||||
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance + distance));
|
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance + distance));
|
||||||
|
|
||||||
//vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, texCoords)) * material.ambient;
|
vec3 ambient = vec3(0.0, 0.0, 0.0);
|
||||||
//vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, texCoords)) * material.diffuse;
|
vec3 diffuse = vec3(0.0, 0.0, 0.0);
|
||||||
//vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, texCoords)) * material.specular;
|
vec3 specular = vec3(0.0, 0.0, 0.0);
|
||||||
vec3 ambient = light.ambient * material.ambient;
|
|
||||||
vec3 diffuse = light.diffuse * (diff * material.diffuse);
|
if (useTextures) {
|
||||||
vec3 specular = light.specular * (spec * material.specular);
|
ambient = light.ambient * vec3(texture(material.texture_ambient, texCoords)) * material.ambient;
|
||||||
|
diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse, texCoords)) * material.diffuse;
|
||||||
|
specular = light.specular * spec * vec3(texture(material.texture_specular, texCoords)) * material.specular;
|
||||||
|
} else {
|
||||||
|
ambient = light.ambient * material.ambient;
|
||||||
|
diffuse = light.diffuse * (diff * material.diffuse);
|
||||||
|
specular = light.specular * (spec * material.specular);
|
||||||
|
}
|
||||||
|
|
||||||
ambient *= attenuation;
|
ambient *= attenuation;
|
||||||
diffuse *= attenuation;
|
diffuse *= attenuation;
|
||||||
@@ -168,12 +155,19 @@ vec3 CalculateSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir
|
|||||||
float epsilon = light.cutOff - light.outerCutOff;
|
float epsilon = light.cutOff - light.outerCutOff;
|
||||||
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
|
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
|
||||||
|
|
||||||
//vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, texCoords)) * material.ambient;
|
vec3 ambient = vec3(0.0, 0.0, 0.0);
|
||||||
//vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, texCoords)) * material.diffuse;
|
vec3 diffuse = vec3(0.0, 0.0, 0.0);
|
||||||
//vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, texCoords)) * material.specular;
|
vec3 specular = vec3(0.0, 0.0, 0.0);
|
||||||
vec3 ambient = light.ambient * material.ambient;
|
|
||||||
vec3 diffuse = light.diffuse * (diff * material.diffuse);
|
if (useTextures) {
|
||||||
vec3 specular = light.specular * (spec * material.specular);
|
ambient = light.ambient * vec3(texture(material.texture_ambient, texCoords)) * material.ambient;
|
||||||
|
diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse, texCoords)) * material.diffuse;
|
||||||
|
specular = light.specular * spec * vec3(texture(material.texture_specular, texCoords)) * material.specular;
|
||||||
|
} else {
|
||||||
|
ambient = light.ambient * material.ambient;
|
||||||
|
diffuse = light.diffuse * (diff * material.diffuse);
|
||||||
|
specular = light.specular * (spec * material.specular);
|
||||||
|
}
|
||||||
|
|
||||||
diffuse *= intensity;
|
diffuse *= intensity;
|
||||||
specular *= intensity;
|
specular *= intensity;
|
||||||
@@ -200,6 +194,6 @@ void main()
|
|||||||
|
|
||||||
result += CalculateSpotLight(spotLight, norm, fragPos, viewDir);
|
result += CalculateSpotLight(spotLight, norm, fragPos, viewDir);
|
||||||
|
|
||||||
FragColor = vec4(result, 1.0);
|
FragColor = vec4(result, material.opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -10,11 +10,15 @@ uniform mat4 model;
|
|||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
uniform mat3 normalMatrix;
|
uniform mat3 normalMatrix;
|
||||||
|
uniform bool useNormalMatrix;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = projection * view * model * vec4(aPos, 1.0f);
|
gl_Position = projection * view * model * vec4(aPos, 1.0f);
|
||||||
fragNormals = normalMatrix * aNormal;
|
if (useNormalMatrix)
|
||||||
|
fragNormals = normalMatrix * aNormal;
|
||||||
|
else
|
||||||
|
fragNormals = mat3(transpose(inverse(model))) * aNormal;
|
||||||
fragPos = vec3(model * vec4(aPos, 1.0));
|
fragPos = vec3(model * vec4(aPos, 1.0));
|
||||||
texCoords = aTexCoords;
|
texCoords = aTexCoords;
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-9
@@ -1,9 +1,9 @@
|
|||||||
mod obj;
|
mod obj;
|
||||||
mod stl;
|
mod stl;
|
||||||
|
|
||||||
use std::{path::PathBuf, collections::HashMap};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{mesh::Vertex, aabb::AABB, utils::SupportedFileExtensions};
|
use crate::{mesh::Vertex, aabb::AABB, utils::{SupportedFileExtensions, self}};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TextureType {
|
pub enum TextureType {
|
||||||
@@ -18,7 +18,23 @@ pub enum TextureType {
|
|||||||
Emissive
|
Emissive
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: take the textures out of the material and put it on the model/object
|
impl TextureType {
|
||||||
|
pub fn from_material_str(token: &str) -> Option<Self> {
|
||||||
|
match token {
|
||||||
|
"map_Ka" => Some(TextureType::Ambient),
|
||||||
|
"map_Kd" => Some(TextureType::Diffuse),
|
||||||
|
"map_Ks" => Some(TextureType::Specular),
|
||||||
|
"map_Ns" => Some(TextureType::SpecularHighlight),
|
||||||
|
"map_bump" => Some(TextureType::Bump),
|
||||||
|
"map_d" => Some(TextureType::Displacement),
|
||||||
|
"decal" => Some(TextureType::Decal),
|
||||||
|
"refl" => Some(TextureType::Reflection),
|
||||||
|
"map_Ke" => Some(TextureType::Emissive),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Material {
|
pub struct Material {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -27,11 +43,11 @@ pub struct Material {
|
|||||||
pub specular_color: glm::Vec3,
|
pub specular_color: glm::Vec3,
|
||||||
pub specular_exponent: f32,
|
pub specular_exponent: f32,
|
||||||
pub opacity: f32,
|
pub opacity: f32,
|
||||||
pub textures: HashMap<String, TextureType>,
|
pub textures: Vec<Texture>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material {
|
impl Material {
|
||||||
fn new(name: String, ambient: glm::Vec3, diffuse: glm::Vec3, specular: glm::Vec3, shininess: f32, opacity: f32, textures: HashMap<String, TextureType>) -> Self {
|
fn new(name: String, ambient: glm::Vec3, diffuse: glm::Vec3, specular: glm::Vec3, shininess: f32, opacity: f32, textures: Vec<Texture>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
ambient_color: ambient,
|
ambient_color: ambient,
|
||||||
@@ -53,7 +69,7 @@ impl Default for Material {
|
|||||||
specular_color: glm::vec3(0.1, 0.1, 0.1),
|
specular_color: glm::vec3(0.1, 0.1, 0.1),
|
||||||
specular_exponent: 32.0,
|
specular_exponent: 32.0,
|
||||||
opacity: 1.0,
|
opacity: 1.0,
|
||||||
textures: HashMap::new()
|
textures: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,16 +78,35 @@ impl std::fmt::Display for Material {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Ambient: {:?}\nDiffuse: {:?}\nSpecular: {:?}\nShininess: {}\nOpacity: {}",
|
"Ambient: {:?}\nDiffuse: {:?}\nSpecular: {:?}\nShininess: {}\nOpacity: {}\nTextures: {:?}",
|
||||||
self.ambient_color,
|
self.ambient_color,
|
||||||
self.diffuse_color,
|
self.diffuse_color,
|
||||||
self.specular_color,
|
self.specular_color,
|
||||||
self.specular_exponent,
|
self.specular_exponent,
|
||||||
self.opacity
|
self.opacity,
|
||||||
|
self.textures
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Texture {
|
||||||
|
pub id: u32,
|
||||||
|
pub typ: TextureType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Texture {
|
||||||
|
pub fn new(path: std::path::PathBuf, typ: TextureType) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
|
let id = utils::load_texture(path)?;
|
||||||
|
|
||||||
|
Ok(Texture {
|
||||||
|
id,
|
||||||
|
typ,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ObjMesh {
|
pub struct ObjMesh {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -84,7 +119,7 @@ pub struct ObjMesh {
|
|||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub meshes: Vec<ObjMesh>,
|
pub meshes: Vec<ObjMesh>,
|
||||||
pub aabb: AABB
|
pub aabb: AABB,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_file(path: &PathBuf) -> Result<Object, Box<dyn std::error::Error>> {
|
pub fn load_from_file(path: &PathBuf) -> Result<Object, Box<dyn std::error::Error>> {
|
||||||
|
|||||||
+34
-8
@@ -2,7 +2,7 @@ use std::{io::{BufReader, BufRead}, collections::HashMap, path::PathBuf};
|
|||||||
|
|
||||||
use log::{error, warn, trace};
|
use log::{error, warn, trace};
|
||||||
|
|
||||||
use crate::{mesh::Vertex, aabb::AABB, importer::ObjMesh, importer::Object, importer::Material};
|
use crate::{mesh::Vertex, aabb::AABB, importer::{ObjMesh, Object, Material, Texture, TextureType}};
|
||||||
|
|
||||||
const BUF_CAP: usize = 1024 * 128; // 128 Kilobytes
|
const BUF_CAP: usize = 1024 * 128; // 128 Kilobytes
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ impl MtlToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_mtl(path: &PathBuf) -> Result<HashMap<String, Material>, Box<dyn std::error::Error>> {
|
fn parse_mtl(path: &PathBuf, obj_textures: &mut HashMap<String, Texture>) -> Result<HashMap<String, Material>, Box<dyn std::error::Error>> {
|
||||||
let file = std::fs::File::open(path)?;
|
let file = std::fs::File::open(path)?;
|
||||||
let reader = BufReader::with_capacity(BUF_CAP, file);
|
let reader = BufReader::with_capacity(BUF_CAP, file);
|
||||||
let mut material_name = String::new();
|
let mut material_name = String::new();
|
||||||
@@ -95,6 +95,7 @@ fn parse_mtl(path: &PathBuf) -> Result<HashMap<String, Material>, Box<dyn std::e
|
|||||||
let mut specular = glm::vec3(0.0, 0.0, 0.0);
|
let mut specular = glm::vec3(0.0, 0.0, 0.0);
|
||||||
let mut shininess = 32.0;
|
let mut shininess = 32.0;
|
||||||
let mut opacity = 1.0;
|
let mut opacity = 1.0;
|
||||||
|
let mut mat_textures: Vec<Texture> = Vec::new();
|
||||||
|
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
let line = line?;
|
let line = line?;
|
||||||
@@ -109,8 +110,10 @@ fn parse_mtl(path: &PathBuf) -> Result<HashMap<String, Material>, Box<dyn std::e
|
|||||||
match MtlToken::from_str(token) {
|
match MtlToken::from_str(token) {
|
||||||
Some(MtlToken::NewMaterial) => {
|
Some(MtlToken::NewMaterial) => {
|
||||||
if !material_name.is_empty() {
|
if !material_name.is_empty() {
|
||||||
material = Material::new(material_name.clone(), ambient, diffuse, specular, shininess, opacity, HashMap::new());
|
material = Material::new(material_name.clone(), ambient, diffuse, specular, shininess, opacity, mat_textures.clone());
|
||||||
materials.insert(material_name, material);
|
materials.insert(material_name, material);
|
||||||
|
|
||||||
|
mat_textures.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
material_name = iter.next().unwrap().to_string();
|
material_name = iter.next().unwrap().to_string();
|
||||||
@@ -139,15 +142,36 @@ fn parse_mtl(path: &PathBuf) -> Result<HashMap<String, Material>, Box<dyn std::e
|
|||||||
Some(MtlToken::Opacity) => {
|
Some(MtlToken::Opacity) => {
|
||||||
opacity = iter.next().unwrap().parse::<f32>().unwrap();
|
opacity = iter.next().unwrap().parse::<f32>().unwrap();
|
||||||
}
|
}
|
||||||
Some(MtlToken::DiffuseTexture) => {
|
Some(MtlToken::DiffuseTexture)
|
||||||
// TODO: textures
|
| Some(MtlToken::AmbientTexture)
|
||||||
|
| Some(MtlToken::SpecularTexture) => {
|
||||||
|
let tex_type = TextureType::from_material_str(token).unwrap();
|
||||||
|
|
||||||
|
let name = iter.next().unwrap().to_string();
|
||||||
|
let mat = if obj_textures.contains_key(&name) {
|
||||||
|
obj_textures.get(&name).unwrap().clone()
|
||||||
|
} else {
|
||||||
|
let path = path.parent().unwrap().join(&name);
|
||||||
|
let tex = match Texture::new(path, tex_type) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to load texture: {}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
obj_textures.insert(name, tex.clone());
|
||||||
|
tex
|
||||||
|
};
|
||||||
|
|
||||||
|
mat_textures.push(mat);
|
||||||
}
|
}
|
||||||
_ => { warn!("Unhandled material token: {}", token) },
|
_ => { warn!("Unhandled material token: {}", token) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
material = Material::new(material_name.clone(), ambient, diffuse, specular, shininess, opacity, HashMap::new());
|
material = Material::new(material_name.clone(), ambient, diffuse, specular, shininess, opacity, mat_textures);
|
||||||
|
|
||||||
materials.insert(material_name, material);
|
materials.insert(material_name, material);
|
||||||
|
|
||||||
@@ -170,6 +194,7 @@ pub fn load_obj(obj_path: &PathBuf, file: std::fs::File) -> Result<Object, Box<d
|
|||||||
let mut current_material: Option<Material> = None;
|
let mut current_material: Option<Material> = None;
|
||||||
let mut min_aabb = glm::vec3(f32::MAX, f32::MAX, f32::MAX);
|
let mut min_aabb = glm::vec3(f32::MAX, f32::MAX, f32::MAX);
|
||||||
let mut max_aabb = glm::vec3(f32::MIN, f32::MIN, f32::MIN);
|
let mut max_aabb = glm::vec3(f32::MIN, f32::MIN, f32::MIN);
|
||||||
|
let mut textures = HashMap::new();
|
||||||
|
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
let line = line?;
|
let line = line?;
|
||||||
@@ -264,7 +289,8 @@ pub fn load_obj(obj_path: &PathBuf, file: std::fs::File) -> Result<Object, Box<d
|
|||||||
.map(|i| i.parse::<f32>().unwrap());
|
.map(|i| i.parse::<f32>().unwrap());
|
||||||
let u = iter.next().unwrap();
|
let u = iter.next().unwrap();
|
||||||
let v = iter.next().unwrap();
|
let v = iter.next().unwrap();
|
||||||
tex_coords.push(glm::vec2(u, v));
|
// vertically flip the texcoords because flipping the texture is expensive
|
||||||
|
tex_coords.push(glm::vec2(u, 1.0 - v));
|
||||||
}
|
}
|
||||||
Some(ObjToken::Face) => {
|
Some(ObjToken::Face) => {
|
||||||
let face = iter.collect::<Vec<_>>();
|
let face = iter.collect::<Vec<_>>();
|
||||||
@@ -372,7 +398,7 @@ pub fn load_obj(obj_path: &PathBuf, file: std::fs::File) -> Result<Object, Box<d
|
|||||||
Some(ObjToken::MaterialLib) => {
|
Some(ObjToken::MaterialLib) => {
|
||||||
for matlib in iter {
|
for matlib in iter {
|
||||||
let material_path = obj_path.parent().unwrap().join(matlib);
|
let material_path = obj_path.parent().unwrap().join(matlib);
|
||||||
let new_materials = parse_mtl(&material_path);
|
let new_materials = parse_mtl(&material_path, &mut textures);
|
||||||
match new_materials {
|
match new_materials {
|
||||||
Ok(m) => {
|
Ok(m) => {
|
||||||
materials.extend(m);
|
materials.extend(m);
|
||||||
|
|||||||
+1
-1
@@ -264,7 +264,7 @@ fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
|||||||
} else {
|
} else {
|
||||||
gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
|
gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
|
||||||
}
|
}
|
||||||
if Some(obj.id) == state.active_model {obj.draw(&mesh_shader, state.draw_aabb);}
|
if Some(obj.id) == state.active_model {obj.draw(&mesh_shader, state.draw_aabb, state.show_textures);}
|
||||||
}
|
}
|
||||||
gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
|
gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
|
||||||
|
|
||||||
|
|||||||
+46
-56
@@ -1,6 +1,7 @@
|
|||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
use crate::{shader::Shader, utils, importer::Material};
|
use crate::{shader::Shader, utils, importer::{Material, TextureType}};
|
||||||
|
|
||||||
fn create_rotation_matrix(pitch: f32, yaw: f32, roll: f32, pivot: glm::Vec3) -> glm::Mat4 {
|
fn create_rotation_matrix(pitch: f32, yaw: f32, roll: f32, pivot: glm::Vec3) -> glm::Mat4 {
|
||||||
let pitch = pitch.to_radians();
|
let pitch = pitch.to_radians();
|
||||||
@@ -36,7 +37,6 @@ pub struct Mesh {
|
|||||||
|
|
||||||
pub vertices: Vec<Vertex>,
|
pub vertices: Vec<Vertex>,
|
||||||
pub indices: Vec<u32>,
|
pub indices: Vec<u32>,
|
||||||
// pub textures: Vec<Texture>,
|
|
||||||
pub material: Material,
|
pub material: Material,
|
||||||
|
|
||||||
vao: u32,
|
vao: u32,
|
||||||
@@ -82,7 +82,6 @@ impl Mesh {
|
|||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
vertices,
|
vertices,
|
||||||
indices,
|
indices,
|
||||||
// textures,
|
|
||||||
material: material.unwrap_or_default(),
|
material: material.unwrap_or_default(),
|
||||||
vbo,
|
vbo,
|
||||||
vao,
|
vao,
|
||||||
@@ -94,23 +93,26 @@ impl Mesh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, shader: &Shader, scale: f32, pivot: glm::Vec3) {
|
pub fn draw(&self, shader: &Shader, scale: f32, pivot: glm::Vec3, show_textures: bool) {
|
||||||
// let mut diffuse = 1;
|
|
||||||
// let mut specular = 1;
|
|
||||||
|
|
||||||
shader.use_shader();
|
shader.use_shader();
|
||||||
|
|
||||||
let model_mat = glm::ext::scale(&utils::mat_ident(), glm::vec3(scale, scale, scale));
|
let model_mat = glm::ext::scale(&utils::mat_ident(), glm::vec3(scale, scale, scale));
|
||||||
let model_mat = apply_rotation(&model_mat, self.rotation, pivot);
|
let model_mat = apply_rotation(&model_mat, self.rotation, pivot);
|
||||||
let model_mat = glm::ext::translate(&model_mat, glm::vec3(self.position.x, self.position.y, self.position.z));
|
let model_mat = glm::ext::translate(&model_mat, glm::vec3(self.position.x, self.position.y, self.position.z));
|
||||||
shader.set_mat4fv("model", &model_mat);
|
shader.set_mat4fv("model", &model_mat);
|
||||||
let normal_mat = glm::transpose(&glm::inverse(&model_mat));
|
|
||||||
let normal_mat = glm::mat3(
|
if glm::ext::is_invertible(&model_mat) {
|
||||||
normal_mat[0][0], normal_mat[0][1], normal_mat[0][2],
|
let normal_mat = glm::transpose(&glm::inverse(&model_mat));
|
||||||
normal_mat[1][0], normal_mat[1][1], normal_mat[1][2],
|
let normal_mat = glm::mat3(
|
||||||
normal_mat[2][0], normal_mat[2][1], normal_mat[2][2],
|
normal_mat[0][0], normal_mat[0][1], normal_mat[0][2],
|
||||||
);
|
normal_mat[1][0], normal_mat[1][1], normal_mat[1][2],
|
||||||
shader.set_mat3fv("normalMatrix", &normal_mat);
|
normal_mat[2][0], normal_mat[2][1], normal_mat[2][2],
|
||||||
|
);
|
||||||
|
shader.set_mat3fv("normalMatrix", &normal_mat);
|
||||||
|
shader.set_bool("useNormalMatrix", true);
|
||||||
|
} else {
|
||||||
|
shader.set_bool("useNormalMatrix", false);
|
||||||
|
}
|
||||||
|
|
||||||
let mut polygon_mode = 0;
|
let mut polygon_mode = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -119,34 +121,44 @@ impl Mesh {
|
|||||||
let is_wireframe = polygon_mode as u32 == gl::LINE;
|
let is_wireframe = polygon_mode as u32 == gl::LINE;
|
||||||
|
|
||||||
if !is_wireframe {
|
if !is_wireframe {
|
||||||
|
// TODO: these can be missing in the (.obj) material, maybe we should set them
|
||||||
|
// to 1.0 as fallback. shininess too
|
||||||
shader.set_3fv("material.ambient", self.material.ambient_color);
|
shader.set_3fv("material.ambient", self.material.ambient_color);
|
||||||
shader.set_3fv("material.diffuse", self.material.diffuse_color);
|
shader.set_3fv("material.diffuse", self.material.diffuse_color);
|
||||||
shader.set_3fv("material.specular", self.material.specular_color);
|
shader.set_3fv("material.specular", self.material.specular_color);
|
||||||
shader.set_float("material.shininess", self.material.specular_exponent);
|
shader.set_float("material.shininess", 32.0);
|
||||||
|
shader.set_float("material.opacity", self.material.opacity);
|
||||||
} else {
|
} else {
|
||||||
shader.set_3fv("material.ambient", glm::vec3(0.0, 0.0, 0.0));
|
shader.set_3fv("material.ambient", glm::vec3(0.0, 0.0, 0.0));
|
||||||
shader.set_3fv("material.diffuse", glm::vec3(0.0, 0.0, 0.0));
|
shader.set_3fv("material.diffuse", glm::vec3(0.0, 0.0, 0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for i in 0..self.textures.len() {
|
if show_textures {
|
||||||
// unsafe {
|
shader.set_bool("useTextures", self.material.textures.len() > 0);
|
||||||
// gl::ActiveTexture(gl::TEXTURE0 + i as u32);
|
for (i, tex) in self.material.textures.iter().enumerate() {
|
||||||
// match self.textures[i].typ {
|
unsafe {
|
||||||
// russimp::material::TextureType::Diffuse => {
|
gl::ActiveTexture(gl::TEXTURE0 + i as u32);
|
||||||
// diffuse += 1;
|
match tex.typ {
|
||||||
// shader.set_int(format!("material.texture_diffuse{}", diffuse).as_str(), i as i32);
|
TextureType::Ambient => {
|
||||||
// },
|
shader.set_int("material.texture_ambient", i as i32);
|
||||||
// russimp::material::TextureType::Specular => {
|
},
|
||||||
// specular += 1;
|
TextureType::Diffuse => {
|
||||||
// shader.set_int(format!("material.texture_specular{}", specular).as_str(), i as i32);
|
shader.set_int("material.texture_diffuse", i as i32);
|
||||||
// },
|
},
|
||||||
// _ => {}, // don't do anything because unsupported texture types are logged
|
TextureType::Specular => {
|
||||||
// // when the model is loaded
|
shader.set_int("material.texture_specular{}", i as i32);
|
||||||
// }
|
},
|
||||||
|
_ => {
|
||||||
|
warn!("Unsupported texture type: {:?}", tex.typ);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// gl::BindTexture(gl::TEXTURE_2D, self.textures[i].id);
|
gl::BindTexture(gl::TEXTURE_2D, tex.id);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
} else {
|
||||||
|
shader.set_bool("useTextures", false);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// draw Mesh
|
// draw Mesh
|
||||||
@@ -170,6 +182,7 @@ impl Mesh {
|
|||||||
|
|
||||||
impl Drop for Mesh {
|
impl Drop for Mesh {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// TODO: should we impl a Drop on material to delete the textures from gpu??
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
gl::DeleteBuffers(1, &self.vbo);
|
gl::DeleteBuffers(1, &self.vbo);
|
||||||
@@ -197,26 +210,3 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Clone, Debug)]
|
|
||||||
// pub struct Texture {
|
|
||||||
// pub id: u32,
|
|
||||||
// pub typ: russimp::material::TextureType,
|
|
||||||
// pub path: std::path::PathBuf,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Texture {
|
|
||||||
// pub fn new(path: std::path::PathBuf, typ: russimp::material::TextureType) -> Result<Self, Box<dyn std::error::Error>> {
|
|
||||||
// let path_str = match path.to_str() {
|
|
||||||
// Some(path) => path,
|
|
||||||
// None => return Err("Failed to convert texture path to string".into()),
|
|
||||||
// };
|
|
||||||
// let id = utils::load_texture(path_str)?;
|
|
||||||
|
|
||||||
// Ok(Texture {
|
|
||||||
// id,
|
|
||||||
// typ,
|
|
||||||
// path,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|||||||
+2
-51
@@ -12,55 +12,6 @@ pub struct Model {
|
|||||||
pub mem_usage: usize,
|
pub mem_usage: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: texture support, kept for reference
|
|
||||||
// fn load_material_textures(
|
|
||||||
// mat: &russimp::material::Material,
|
|
||||||
// dir: &std::path::PathBuf,
|
|
||||||
// loaded_textures: &mut Vec<Texture>
|
|
||||||
// ) -> (Vec<Texture>, Vec<Box<dyn std::error::Error>>) {
|
|
||||||
|
|
||||||
// let mut textures = vec![];
|
|
||||||
// let mut errors = vec![];
|
|
||||||
|
|
||||||
// for (typ, tex) in mat.textures.iter() {
|
|
||||||
// if SUPPORTED_TEXTURE_TYPES.contains(typ) {
|
|
||||||
// let texture = tex.borrow();
|
|
||||||
// let mut skip = false;
|
|
||||||
// let tex_filename = &texture.filename;
|
|
||||||
// // HACK: fix this
|
|
||||||
// if tex_filename.is_empty() {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// // println!("texture filename: {}", tex_filename);
|
|
||||||
// let path = dir.join(tex_filename);
|
|
||||||
|
|
||||||
// for loaded_tex in &mut *loaded_textures {
|
|
||||||
// if loaded_tex.path == path {
|
|
||||||
// textures.push(loaded_tex.clone());
|
|
||||||
// skip = true;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if !skip {
|
|
||||||
// match Texture::new(path, *typ) {
|
|
||||||
// Ok(texture) => {
|
|
||||||
// loaded_textures.push(texture.clone());
|
|
||||||
// textures.push(texture);
|
|
||||||
// },
|
|
||||||
// Err(e) => {
|
|
||||||
// let err = anyhow!("Error loading texture: {}", e);
|
|
||||||
// println!("{}", err);
|
|
||||||
// errors.push(err.into());
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return (textures, errors);
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
pub fn new(obj: importer::Object, state: &mut ui::State) -> Model {
|
pub fn new(obj: importer::Object, state: &mut ui::State) -> Model {
|
||||||
let mut meshes = Vec::new();
|
let mut meshes = Vec::new();
|
||||||
@@ -90,7 +41,7 @@ impl Model {
|
|||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, shader: &Shader, draw_aabb: bool) {
|
pub fn draw(&self, shader: &Shader, draw_aabb: bool, show_textures: bool) {
|
||||||
let center_x = ((self.aabb.max.x / 2.0) + (self.aabb.min.x / 2.0)) * self.scaling_factor;
|
let center_x = ((self.aabb.max.x / 2.0) + (self.aabb.min.x / 2.0)) * self.scaling_factor;
|
||||||
let center_y = ((self.aabb.max.y / 2.0) + (self.aabb.min.y / 2.0)) * self.scaling_factor;
|
let center_y = ((self.aabb.max.y / 2.0) + (self.aabb.min.y / 2.0)) * self.scaling_factor;
|
||||||
let center_z = ((self.aabb.max.z / 2.0) + (self.aabb.min.z / 2.0)) * self.scaling_factor;
|
let center_z = ((self.aabb.max.z / 2.0) + (self.aabb.min.z / 2.0)) * self.scaling_factor;
|
||||||
@@ -102,7 +53,7 @@ impl Model {
|
|||||||
|
|
||||||
|
|
||||||
for mesh in &self.meshes {
|
for mesh in &self.meshes {
|
||||||
mesh.draw(shader, self.scaling_factor, pivot);
|
mesh.draw(shader, self.scaling_factor, pivot, show_textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
if draw_aabb {
|
if draw_aabb {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pub struct State {
|
|||||||
pub logger: logger::WritableLog,
|
pub logger: logger::WritableLog,
|
||||||
pub settings: Settings,
|
pub settings: Settings,
|
||||||
pub fps: f32,
|
pub fps: f32,
|
||||||
|
pub show_textures: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
@@ -55,6 +56,7 @@ impl Default for State {
|
|||||||
logger: logger::WritableLog::default(),
|
logger: logger::WritableLog::default(),
|
||||||
settings: Settings::default(),
|
settings: Settings::default(),
|
||||||
fps: 0.0,
|
fps: 0.0,
|
||||||
|
show_textures: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -487,6 +489,8 @@ fn draw_viewport(ui: &imgui::Ui, state: &mut State, texture: u32) {
|
|||||||
ui.same_line();
|
ui.same_line();
|
||||||
ui.checkbox("FOV zoom", &mut state.fov_zoom);
|
ui.checkbox("FOV zoom", &mut state.fov_zoom);
|
||||||
ui.same_line();
|
ui.same_line();
|
||||||
|
ui.checkbox("Show Textures", &mut state.show_textures);
|
||||||
|
ui.same_line();
|
||||||
ui.set_next_item_width(150.0);
|
ui.set_next_item_width(150.0);
|
||||||
imgui::Drag::new("Camera Speed")
|
imgui::Drag::new("Camera Speed")
|
||||||
.range(1.0, 10000.0)
|
.range(1.0, 10000.0)
|
||||||
|
|||||||
+9
-4
@@ -22,11 +22,11 @@ impl SupportedFileExtensions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_texture(path: &str) -> Result<u32> {
|
pub fn load_texture(path: PathBuf) -> Result<u32> {
|
||||||
let tex = image::io::Reader::open(path)
|
let tex = image::io::Reader::open(path.clone())
|
||||||
.with_context(|| format!("Failed to open texture file: {}", path))?
|
.with_context(|| format!("Failed to open texture file: {:?}", path))?
|
||||||
.decode()
|
.decode()
|
||||||
.with_context(|| format!("Failed to decode texture: {}", path))?;
|
.with_context(|| format!("Failed to decode texture: {:?}", path))?;
|
||||||
|
|
||||||
let mut texture_id: u32 = 0;
|
let mut texture_id: u32 = 0;
|
||||||
let format = match tex.color().channel_count() {
|
let format = match tex.color().channel_count() {
|
||||||
@@ -38,6 +38,9 @@ pub fn load_texture(path: &str) -> Result<u32> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// set alignment to 1 since we use u8 for the pixel data type
|
||||||
|
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
gl::GenTextures(1, &mut texture_id);
|
gl::GenTextures(1, &mut texture_id);
|
||||||
gl::BindTexture(gl::TEXTURE_2D, texture_id);
|
gl::BindTexture(gl::TEXTURE_2D, texture_id);
|
||||||
|
|
||||||
@@ -49,6 +52,8 @@ pub fn load_texture(path: &str) -> Result<u32> {
|
|||||||
|
|
||||||
gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, tex.width() as i32, tex.height() as i32, 0, format, gl::UNSIGNED_BYTE, tex.as_bytes().as_ptr() as *const std::ffi::c_void);
|
gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, tex.width() as i32, tex.height() as i32, 0, format, gl::UNSIGNED_BYTE, tex.as_bytes().as_ptr() as *const std::ffi::c_void);
|
||||||
gl::GenerateMipmap(gl::TEXTURE_2D);
|
gl::GenerateMipmap(gl::TEXTURE_2D);
|
||||||
|
|
||||||
|
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(texture_id)
|
Ok(texture_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user