Normal/Height maps now working from models, and are only applied to models that have them.
This commit is contained in:
parent
4efe72b8d8
commit
8b41591360
8 changed files with 170 additions and 12 deletions
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"scene": {
|
||||
"shader": {
|
||||
"vertex_path": "shaders/33-framebuffers.vert.glsl",
|
||||
"frag_path": "shaders/33-framebuffers.frag.glsl",
|
||||
"vertex_path": "shaders/43-framebuffers.vert.glsl",
|
||||
"frag_path": "shaders/43-framebuffers.frag.glsl",
|
||||
"geometry_path": ""
|
||||
},
|
||||
"reflect_shader": {
|
||||
|
|
@ -66,6 +66,10 @@
|
|||
"human": {
|
||||
"directory": "../assets",
|
||||
"model_path": "human.glb"
|
||||
},
|
||||
"brick_cube": {
|
||||
"directory": "../assets",
|
||||
"model_path": "brick_cube_normal.obj"
|
||||
}
|
||||
},
|
||||
"things": [
|
||||
|
|
@ -73,10 +77,10 @@
|
|||
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
|
||||
"scale": 1.0,
|
||||
"material": "shiny"},
|
||||
{"model": "marble_cube", "position": [1.5, 0.0, -1.0],
|
||||
{"model": "brick_cube", "position": [-2, 0.21, -1.0],
|
||||
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
|
||||
"scale": 1.0,
|
||||
"material": "shiny"},
|
||||
"scale": 0.5,
|
||||
"material": "default"},
|
||||
{"model": "human", "position": [1.28, 0.0, 1.33],
|
||||
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
|
||||
"scale": 1.0,
|
||||
|
|
|
|||
82
43-normal-maps/shaders/43-framebuffers.frag.glsl
Normal file
82
43-normal-maps/shaders/43-framebuffers.frag.glsl
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#version 330 core
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec3 Normal;
|
||||
in vec2 TexCoords;
|
||||
in vec4 FragPosLightSpace;
|
||||
in mat3 TBN;
|
||||
|
||||
uniform vec3 lightPos;
|
||||
uniform vec3 viewPos;
|
||||
uniform sampler2D shadowMap;
|
||||
uniform sampler2D texture_diffuse1;
|
||||
uniform sampler2D texture_specular1;
|
||||
uniform sampler2D texture_height1; // bump/normal map
|
||||
uniform bool hasHeight;
|
||||
|
||||
float ShadowCalculation(vec4 fragPosLightSpace, float bias)
|
||||
{
|
||||
// perform perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
|
||||
// transform to [0,1] range
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
// avoid the frustrum
|
||||
if(projCoords.z > 1.0) return 0.0;
|
||||
|
||||
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
|
||||
float closestDepth = texture(shadowMap, projCoords.xy).r;
|
||||
|
||||
// get depth of current fragment from light's perspective
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
// check whether current frag pos is in shadow
|
||||
// PCF
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
|
||||
for(int x = -1; x <= 1; ++x) {
|
||||
for(int y = -1; y <= 1; ++y) {
|
||||
float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
return shadow / 9.0;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 color = texture(texture_diffuse1, TexCoords).rgb;
|
||||
vec3 normal = normalize(Normal);
|
||||
|
||||
if(hasHeight) {
|
||||
normal = texture(texture_height1, TexCoords).rgb;
|
||||
normal = normal * 2.0 - 1.0;
|
||||
normal = normalize(TBN * normal);
|
||||
}
|
||||
|
||||
vec3 lightColor = vec3(0.7);
|
||||
// ambient
|
||||
vec3 ambient = 0.3 * lightColor;
|
||||
// diffuse
|
||||
vec3 lightDir = normalize(lightPos - FragPos);
|
||||
float diff = max(dot(lightDir, normal), 0.0);
|
||||
vec3 diffuse = diff * lightColor;
|
||||
// specular
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
vec3 reflectDir = reflect(-lightDir, normal);
|
||||
float spec = 0.0;
|
||||
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
|
||||
vec3 specular = spec * lightColor;
|
||||
// calculate shadow
|
||||
|
||||
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||
float shadow = ShadowCalculation(FragPosLightSpace, bias);
|
||||
|
||||
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;
|
||||
|
||||
FragColor = vec4(lighting, 1.0);
|
||||
}
|
||||
31
43-normal-maps/shaders/43-framebuffers.vert.glsl
Normal file
31
43-normal-maps/shaders/43-framebuffers.vert.glsl
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 2) in vec2 aTexCoords;
|
||||
layout (location = 3) in vec3 aTangent;
|
||||
layout (location = 4) in vec3 aBitangent;
|
||||
|
||||
out vec3 FragPos;
|
||||
out vec3 Normal;
|
||||
out vec2 TexCoords;
|
||||
out vec4 FragPosLightSpace;
|
||||
out mat3 TBN;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 model;
|
||||
uniform mat4 lightSpaceMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||
Normal = transpose(inverse(mat3(model))) * aNormal;
|
||||
TexCoords = aTexCoords;
|
||||
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||
|
||||
vec3 T = normalize(vec3(model * vec4(aTangent, 0.0)));
|
||||
vec3 B = normalize(vec3(model * vec4(aBitangent, 0.0)));
|
||||
vec3 N = normalize(vec3(model * vec4(aNormal, 0.0)));
|
||||
TBN = mat3(T, B, N);
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ void process_input(GLFWwindow *window, std::shared_ptr<Scene> scene) {
|
|||
std::shared_ptr<Scene> setup() {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
|
|
|||
|
|
@ -14,17 +14,25 @@ void Mesh::draw(Shader &shader, bool with_textures) {
|
|||
|
||||
void Mesh::apply_textures(const Shader& shader) {
|
||||
int texture_i = 1;
|
||||
bool has_height = false;
|
||||
|
||||
for(auto& texture : textures) {
|
||||
texture.uniform_id = glGetUniformLocation(shader.ID, texture.target.c_str());
|
||||
if(texture.uniform_id == -1) continue;
|
||||
|
||||
if(texture.target.starts_with("texture_height")) {
|
||||
has_height = true;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + texture_i);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.id);
|
||||
glUniform1i(texture.uniform_id, texture_i);
|
||||
|
||||
texture_i++;
|
||||
}
|
||||
|
||||
// quick hack to avoid applying height/normal to things without one
|
||||
shader.setBool("hasHeight", has_height);
|
||||
}
|
||||
|
||||
void Mesh::setup_mesh() {
|
||||
|
|
@ -48,4 +56,10 @@ void Mesh::setup_mesh() {
|
|||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, tex_coords));
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, tangent));
|
||||
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, bitangent));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ struct Vertex {
|
|||
glm::vec3 position;
|
||||
glm::vec3 normal;
|
||||
glm::vec2 tex_coords;
|
||||
glm::vec3 tangent;
|
||||
glm::vec3 bitangent;
|
||||
};
|
||||
|
||||
struct TextureCounts {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ void Model::draw(Shader &shader, bool with_textures) {
|
|||
void Model::load_model() {
|
||||
std::string path = directory + "/" + model_path;
|
||||
|
||||
fmt::println("Loading model {}", path);
|
||||
|
||||
Assimp::Importer importer;
|
||||
|
||||
const aiScene* scene = importer.ReadFile(path,
|
||||
|
|
@ -131,6 +133,8 @@ Mesh Model::process_mesh(const aiScene *scene, aiMesh *mesh) {
|
|||
|
||||
glm::vec3 normal{};
|
||||
glm::vec2 tex_coords{0.0f, 0.0f};
|
||||
glm::vec3 tangent;
|
||||
glm::vec3 bitangent;
|
||||
|
||||
if(mesh->HasNormals()) {
|
||||
normal = glm::vec3(
|
||||
|
|
@ -146,7 +150,22 @@ Mesh Model::process_mesh(const aiScene *scene, aiMesh *mesh) {
|
|||
);
|
||||
}
|
||||
|
||||
vertices.emplace_back(position, normal, tex_coords);
|
||||
// if has height/normal map
|
||||
if(mesh->HasTangentsAndBitangents()) {
|
||||
tangent = glm::vec3(
|
||||
mesh->mTangents[i].x,
|
||||
mesh->mTangents[i].y,
|
||||
mesh->mTangents[i].z
|
||||
);
|
||||
|
||||
bitangent = glm::vec3(
|
||||
mesh->mBitangents[i].x,
|
||||
mesh->mBitangents[i].y,
|
||||
mesh->mBitangents[i].z
|
||||
);
|
||||
}
|
||||
|
||||
vertices.emplace_back(position, normal, tex_coords, tangent, bitangent);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
||||
|
|
@ -172,17 +191,19 @@ Mesh Model::process_mesh(const aiScene *scene, aiMesh *mesh) {
|
|||
// 2. specular maps
|
||||
load_material_textures(scene, textures, material, aiTextureType_SPECULAR, "texture_specular");
|
||||
|
||||
// 3. normal maps
|
||||
load_material_textures(scene, textures, material, aiTextureType_HEIGHT, "texture_normal");
|
||||
// 3. normal maps, possibly wrong?
|
||||
load_material_textures(scene, textures, material, aiTextureType_NORMALS, "texture_normal");
|
||||
|
||||
// 4. height maps
|
||||
load_material_textures(scene, textures, material, aiTextureType_AMBIENT, "texture_height");
|
||||
load_material_textures(scene, textures, material, aiTextureType_HEIGHT, "texture_height");
|
||||
|
||||
return Mesh(vertices, indices, textures);
|
||||
}
|
||||
|
||||
void Model::load_material_textures(const aiScene *scene, std::vector<Texture>& textures, aiMaterial *mat, aiTextureType type, std::string type_name)
|
||||
{
|
||||
fmt::println(">>> loading texture type {}", type_name);
|
||||
|
||||
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
|
||||
aiString str;
|
||||
|
||||
|
|
@ -190,6 +211,8 @@ void Model::load_material_textures(const aiScene *scene, std::vector<Texture>& t
|
|||
std::string tx_path{str.C_Str()};
|
||||
dbc::check(!tx_path.empty(), "Texture has empty path, should be impossible?");
|
||||
|
||||
fmt::println("texture {}", tx_path);
|
||||
|
||||
if(textures_loaded.contains(tx_path)) {
|
||||
textures.push_back(textures_loaded.at(tx_path));
|
||||
} else {
|
||||
|
|
@ -210,4 +233,6 @@ void Model::load_material_textures(const aiScene *scene, std::vector<Texture>& t
|
|||
textures_loaded.try_emplace(tx_path, result);
|
||||
}
|
||||
}
|
||||
|
||||
fmt::println("<<< loading texture type {}", type_name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@
|
|||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct Model {
|
||||
std::string directory;
|
||||
std::string model_path;
|
||||
std::map<std::string, Texture> textures_loaded;
|
||||
std::unordered_map<std::string, Texture> textures_loaded;
|
||||
std::vector<Mesh> meshes;
|
||||
TextureCounts texture_counts;
|
||||
bool gammaCorrection;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue