Skip to content

Commit

Permalink
Merge pull request #218 from ucsd-cse125-sp24/feat/normal-maps
Browse files Browse the repository at this point in the history
normal maps
  • Loading branch information
Tyler-Lentz authored Jun 7, 2024
2 parents caee1d5 + 2ac08bb commit 63d04ca
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 11 deletions.
3 changes: 3 additions & 0 deletions include/client/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct Vertex {
glm::vec2 textureCoords;
int m_boneIDs[MAX_BONE_INFLUENCE]; /* Bone indices which influence the vertex */
float m_weights[MAX_BONE_INFLUENCE]; /* Weights for each bone */
glm::vec3 tangent;
glm::vec3 bitangent;
};

class Texture {
Expand Down Expand Up @@ -115,6 +117,7 @@ class Mesh : public Renderable {

// render data opengl needs
GLuint VAO, VBO, EBO;
void setupNormalMaps();
};


Expand Down
6 changes: 3 additions & 3 deletions src/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,13 @@ bool Client::init() {
auto deferred_light_box_frag_path = shaders_dir / "deferred_light_box.frag";
this->deferred_light_box_shader = std::make_shared<Shader>(deferred_light_box_vert_path.string(), deferred_light_box_frag_path.string());

auto floor_model_path = env_models_dir / "floor.obj";
auto floor_model_path = env_models_dir / "floor-normal.obj";
this->floor_model = std::make_unique<Model>(floor_model_path.string(), true);

auto wall_model_path = env_models_dir / "wall.obj";
auto wall_model_path = env_models_dir / "wall-normals.obj";
this->wall_model = std::make_unique<Model>(wall_model_path.string(), true);

auto pillar_model_path = env_models_dir / "pillar.obj";
auto pillar_model_path = env_models_dir / "pillar-normals.obj";
this->pillar_model = std::make_unique<Model>(pillar_model_path.string(), true);

auto torchlight_model_path = env_models_dir / "exit.obj";
Expand Down
76 changes: 73 additions & 3 deletions src/client/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
#include <iostream>
#include <filesystem>

#include "assimp/postprocess.h"
#include "client/renderable.hpp"
#include "client/constants.hpp"
#include "client/util.hpp"
#include "glm/ext/quaternion_geometric.hpp"
#include "server/game/torchlight.hpp"
#include "shared/game/sharedobject.hpp"
#include "shared/utilities/constants.hpp"
Expand Down Expand Up @@ -44,11 +46,14 @@ Mesh::Mesh(
const Material& material) :
vertices(vertices), indices(indices), textures(textures), material(material) {

setupNormalMaps();

glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);

Expand All @@ -75,6 +80,14 @@ Mesh::Mesh(
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, m_weights)));

// tangents
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, tangent)));

// bitangents
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, bitangent)));

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

Expand All @@ -85,6 +98,44 @@ Mesh::Mesh(
// std::cout << "\t shininess" << this->material.shininess << std::endl;
}

void Mesh::setupNormalMaps() {
for (int i=0; i + 2 < indices.size(); i+=3){
// if (i + 1 > indices.size()) {
// }
// get 3 vertices for a triangle
Vertex& v0 = vertices.at(indices.at(i));
Vertex& v1 = vertices.at(indices.at(i+1));
Vertex& v2 = vertices.at(indices.at(i+2));

// Edges of the triangle : position delta
glm::vec3 deltaPos1 = v1.position - v0.position;
glm::vec3 deltaPos2 = v2.position - v0.position;

// UV delta
glm::vec2 deltaUV1 = v1.textureCoords - v0.textureCoords;
glm::vec2 deltaUV2 = v2.textureCoords - v0.textureCoords;

float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
glm::vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y)*r;
glm::vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x)*r;

v0.tangent += tangent;
v1.tangent += tangent;
v2.tangent += tangent;

v0.bitangent += bitangent;
v1.bitangent += bitangent;
v2.bitangent += bitangent;
}

for (int i = 0; i < vertices.size(); i++) {
// vertices.at(i).tangent = glm::normalize(vertices.at(i).tangent);
// // std::cout << "tangent " << glm::to_string(vertices.at(i).tangent) << "\n";
// // exit(1);
// vertices.at(i).bitangent = glm::normalize(vertices.at(i).bitangent);
}
}

void Mesh::draw(
Shader* shader,
glm::vec3 camPos,
Expand All @@ -93,10 +144,12 @@ void Mesh::draw(
auto model = this->getModelMat();

shader->setMat4("model", model);
shader->setVec3("viewPos", camPos);

if (textures.size() != 0) {
unsigned int diffuseNr = 1;
unsigned int specularNr = 1;
unsigned int normalNr = 1;
for(unsigned int i = 0; i < textures.size(); i++) {
glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
Expand All @@ -106,11 +159,20 @@ void Mesh::draw(
number = std::to_string(diffuseNr++);
else if(name == "texture_specular")
number = std::to_string(specularNr++);
else if(name == "texture_normal")
number = std::to_string(normalNr++);

std::string shaderTextureName = name + number;
shader->setInt(shaderTextureName, i);
glBindTexture(GL_TEXTURE_2D, textures[i].getID());
}

if (normalNr == 1) {
// never set any normal map texture uniform
shader->setBool("has_normal_map", false);
} else {
shader->setBool("has_normal_map", true);
}
} else {
// shader->setFloat("shininess", this->material.shininess);
}
Expand Down Expand Up @@ -142,13 +204,15 @@ Model::Model(const std::string& filepath, bool flip_uvs) {
aiProcess_FlipUVs |
aiProcess_SplitLargeMeshes |
aiProcess_OptimizeMeshes |
aiProcess_GenBoundingBoxes); // needed to query bounding box of the model later
aiProcess_GenBoundingBoxes | // needed to query bounding box of the model later
aiProcess_CalcTangentSpace);
} else {
scene = importer.ReadFile(filepath,
aiProcess_Triangulate | // flag to only creates geometry made of triangles
aiProcess_SplitLargeMeshes |
aiProcess_OptimizeMeshes |
aiProcess_GenBoundingBoxes); // needed to query bounding box of the model later
aiProcess_GenBoundingBoxes | // needed to query bounding box of the model later
aiProcess_CalcTangentSpace);
}

if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
Expand Down Expand Up @@ -355,6 +419,9 @@ Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) {
std::vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR);
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());

std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_HEIGHT);
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());

if(AI_SUCCESS != material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse_color)) {
std::cout << "couldn't get diffuse color" << std::endl;
}
Expand Down Expand Up @@ -442,7 +509,7 @@ void Model::extractBoneWeight(std::vector<Vertex>& vertices, aiMesh* mesh, const

std::vector<Texture> Model::loadMaterialTextures(aiMaterial* mat, const aiTextureType& type) {
std::vector<Texture> textures;
// std::cout << "material has " << mat->GetTextureCount(type) << " textures of type " << aiTextureTypeToString(type) << std::endl;
std::cout << "material has " << mat->GetTextureCount(type) << " textures of type " << aiTextureTypeToString(type) << std::endl;
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
aiString str;
mat->GetTexture(type, i, &str);
Expand All @@ -467,6 +534,9 @@ Texture::Texture(const std::string& filepath, const aiTextureType& type) {
case aiTextureType_SPECULAR:
this->type = "texture_specular";
break;
case aiTextureType_HEIGHT:
this->type = "texture_normal";
break;
default:
throw std::invalid_argument(std::string("Unimplemented texture type ") + aiTextureTypeToString(type));
}
Expand Down
33 changes: 31 additions & 2 deletions src/client/shaders/deferred_geometry.frag
Original file line number Diff line number Diff line change
@@ -1,23 +1,52 @@
#version 330 core

#define NR_POINT_LIGHTS 32

layout (location = 0) out vec3 gPosition;
layout (location = 1) out vec3 gNormal;
layout (location = 2) out vec4 gAlbedoSpec;
// layout (location = 3) out vec3 gTangentNormal;

in vec3 FragPos;
in vec3 FragNormal;
in vec2 TexCoords;
in mat3 TBN;

uniform sampler2D texture_diffuse1;
uniform sampler2D texture_specular1;
uniform sampler2D texture_normal1;
uniform bool has_normal_map;

void main()
{
// store the fragment position vector in the first gbuffer texture
gPosition = FragPos;
// also store the per-fragment normals into the gbuffer
gNormal = normalize(FragNormal);
if (has_normal_map) {
// obtain normal from normal map in range [0,1]
gNormal = texture(texture_normal1, TexCoords).rgb;
// transform normal vector to range [-1,1]
gNormal = gNormal * 2.0 - 1.0;
gNormal = normalize(TBN * gNormal);
gNormal = normalize(gNormal);
// if (gNormal == vec3(0.0, 0.0, 0.0)) {
// gAlbedoSpec.rgb = vec3(1.0, 0.0, 0.0);
// } else {
// gAlbedoSpec.rgb = vec3(0.0, 1.0, 0.0);
// }

// gNormal = normalize(TBN * (texture(texture_normal1, TexCoords).rgb * 2.0 - 1.0));
// gNormal = vec3(0.0, 1.0, 0.0);
// gAlbedoSpec.rgb = texture(texture_normal1, TexCoords).rgb;
} else {
gNormal = normalize(FragNormal);
// gAlbedoSpec.rgb = texture(texture_diffuse1, TexCoords).rgb;
}

// and the diffuse per-fragment color
gAlbedoSpec.rgb = texture(texture_diffuse1, TexCoords).rgb;
// store specular intensity in gAlbedoSpec's alpha component
gAlbedoSpec.a = texture(texture_specular1, TexCoords).r;
}

// gTangentNormal = texture(texture_normal, TexCoords).rgb;
}
29 changes: 26 additions & 3 deletions src/client/shaders/deferred_geometry.vert
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
#version 330 core

#define NR_POINT_LIGHTS 32

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in ivec4 boneIds;
layout (location = 4) in vec4 weights;
layout (location = 5) in vec3 aTangent;
layout (location = 6) in vec3 aBitangent;

const int MAX_BONES = 100;
const int MAX_BONE_INFLUENCE = 4;

out vec3 FragPos;
out vec2 TexCoords;
out vec3 FragNormal;
out vec2 TexCoords;
out mat3 TBN;

uniform mat4 model;
uniform mat4 viewProj;
Expand Down Expand Up @@ -49,9 +55,26 @@ void main()
vec4 worldPos = model * totalPosition;
FragPos = worldPos.xyz;
TexCoords = aTexCoords;


vec3 normal0 = (model * vec4(aNormal, 1.0)).xyz;
vec3 tangent0 = (model * vec4(aTangent, 1.0)).xyz;

vec3 Normal = normalize(normal0);
vec3 Tangent = normalize(tangent0);
Tangent = normalize(Tangent - dot(Tangent, Normal) * Normal);
vec3 Bitangent = cross(Normal, Tangent);
TBN = mat3(Tangent, Bitangent, Normal);

mat3 normalMatrix = transpose(inverse(mat3(model)));
FragNormal = normalMatrix * vec3(totalNormal);
// vec3 T = normalize(normalMatrix * aTangent);
// vec3 B = normalize(normalMatrix * aBitangent);
// vec3 N = normalize(normalMatrix * aNormal);
// // T = normalize(T - dot(T, N) * N);
// // vec3 B = cross(N, T);
//
// TBN = mat3(T, B, N);

FragNormal = normalMatrix * aNormal;

gl_Position = viewProj * worldPos;

Expand Down

0 comments on commit 63d04ca

Please sign in to comment.