Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

normal maps #218

Merged
merged 4 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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