Basic Bump Mapping works

This commit is contained in:
karl 2021-04-11 19:19:50 +02:00
parent 5de6d88d37
commit 71aa55acb6
6 changed files with 300 additions and 1 deletions

140
BumpMapDemo.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "BumpMapDemo.h"
BumpMapDemo::BumpMapDemo()
: height_scale(0.2), render_shader(Shader("Shader/bump.vs", "Shader/bump.fs")),
camera(Camera(90, 1920, 1080, 0.1, 1000.0)),
albedo("Resources/Textures/PavingStones/PavingStones070_2K_Color.jpg", Texture::Settings()),
bump("Resources/Textures/PavingStones/PavingStones070_2K_Displacement.jpg",
Texture::Settings()),
normal("Resources/Textures/PavingStones/PavingStones070_2K_Normal.jpg", Texture::Settings()) {
// Move and rotate the camera so we see the quad well
camera.translate(glm::vec3(0.0, -1.0, 1.0));
camera.rotate(30, glm::vec3(1.0, 0.0, 0.0));
}
// renders a 1x1 quad in NDC with manually calculated tangent vectors
// ------------------------------------------------------------------
unsigned int quadVAO = 0;
unsigned int quadVBO;
void renderQuad() {
if (quadVAO == 0) {
// positions
glm::vec3 pos1(-1.0f, 1.0f, 0.0f);
glm::vec3 pos2(-1.0f, -1.0f, 0.0f);
glm::vec3 pos3(1.0f, -1.0f, 0.0f);
glm::vec3 pos4(1.0f, 1.0f, 0.0f);
// texture coordinates
glm::vec2 uv1(0.0f, 1.0f);
glm::vec2 uv2(0.0f, 0.0f);
glm::vec2 uv3(1.0f, 0.0f);
glm::vec2 uv4(1.0f, 1.0f);
// normal vector
glm::vec3 nm(0.0f, 0.0f, 1.0f);
// calculate tangent/bitangent vectors of both triangles
glm::vec3 tangent1, bitangent1;
glm::vec3 tangent2, bitangent2;
// triangle 1
// ----------
glm::vec3 edge1 = pos2 - pos1;
glm::vec3 edge2 = pos3 - pos1;
glm::vec2 deltaUV1 = uv2 - uv1;
glm::vec2 deltaUV2 = uv3 - uv1;
float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
tangent1 = glm::normalize(tangent1);
bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
bitangent1 = glm::normalize(bitangent1);
// triangle 2
// ----------
edge1 = pos3 - pos1;
edge2 = pos4 - pos1;
deltaUV1 = uv3 - uv1;
deltaUV2 = uv4 - uv1;
f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
tangent2 = glm::normalize(tangent2);
bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
bitangent2 = glm::normalize(bitangent2);
float quadVertices[] = {
// positions // normal // texcoords // tangent // bitangent
pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x,
uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x,
uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x,
uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x,
uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x,
uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x,
uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z};
// configure plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(6 * sizeof(float)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(8 * sizeof(float)));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(11 * sizeof(float)));
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
void BumpMapDemo::render(float delta) {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 projection = camera.get_projection();
glm::mat4 view = camera.get_view();
render_shader.use();
render_shader.setMat4("projection", projection);
render_shader.setMat4("view", view);
glm::mat4 quad_model = glm::mat4(1.0f);
quad_model = glm::rotate(
quad_model, glm::radians((float)glfwGetTime() * 20.0f),
glm::normalize(glm::vec3(
0.0, 0.0, 1.0))); // rotate the quad to show parallax mapping from multiple directions
render_shader.setMat4("model", quad_model);
render_shader.setVec3("viewPos", camera.get_translation());
render_shader.setVec3("lightPos", glm::vec3(0.0, 1.0, 5.0));
render_shader.setFloat("height_scale", height_scale);
albedo.bind_to(0);
normal.bind_to(1);
bump.bind_to(2);
renderQuad();
}

29
BumpMapDemo.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "Camera.h"
#include "Framebuffer3D.h"
#include "Shader.h"
#include "Texture.h"
#include "VertexBuffer.h"
class BumpMapDemo {
public:
BumpMapDemo();
void render(float delta);
private:
unsigned int step_count;
unsigned int refinement_step_count;
float height_scale;
Shader render_shader;
VertexBuffer vertex_rectangle;
Camera camera;
Texture albedo;
Texture bump;
Texture normal;
};

0
QuadMesh.h Normal file
View File

92
Shader/bump.fs Normal file
View File

@ -0,0 +1,92 @@
#version 430 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec2 TexCoords;
vec3 TangentLightPos;
vec3 TangentViewPos;
vec3 TangentFragPos;
} fs_in;
layout (binding = 0) uniform sampler2D diffuseMap;
layout (binding = 1) uniform sampler2D normalMap;
layout (binding = 2) uniform sampler2D depthMap;
uniform float height_scale;
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{
// number of depth layers
const float minLayers = 8;
const float maxLayers = 32;
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
// calculate the size of each layer
float layerDepth = 1.0 / numLayers;
// depth of current layer
float currentLayerDepth = 0.0;
// the amount to shift the texture coordinates per layer (from vector P)
vec2 P = viewDir.xy / viewDir.z * height_scale;
vec2 deltaTexCoords = P / numLayers;
// get initial values
vec2 currentTexCoords = texCoords;
float currentDepthMapValue = 1.0 - texture(depthMap, currentTexCoords).r;
while(currentLayerDepth < currentDepthMapValue)
{
// shift texture coordinates along direction of P
currentTexCoords -= deltaTexCoords;
// get depthmap value at current texture coordinates
currentDepthMapValue = 1.0 - texture(depthMap, currentTexCoords).r;
// get depth of next layer
currentLayerDepth += layerDepth;
}
// get texture coordinates before collision (reverse operations)
vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
// get depth after and before collision for linear interpolation
float afterDepth = currentDepthMapValue - currentLayerDepth;
float beforeDepth = 1.0 - texture(depthMap, prevTexCoords).r - currentLayerDepth + layerDepth;
// interpolation of texture coordinates
float weight = afterDepth / (afterDepth - beforeDepth);
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
return finalTexCoords;
}
void main()
{
// offset texture coordinates with Parallax Mapping
vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);
vec2 texCoords = fs_in.TexCoords;
texCoords = ParallaxMapping(fs_in.TexCoords, viewDir);
if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0)
discard;
// obtain normal from normal map
vec3 normal = texture(normalMap, texCoords).rgb;
normal = normalize(normal * 2.0 - 1.0);
// get diffuse color
vec3 color = texture(diffuseMap, texCoords).rgb;
// ambient
vec3 ambient = 0.1 * color;
// diffuse
vec3 lightDir = normalize(fs_in.TangentLightPos - fs_in.TangentFragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * color;
// specular
vec3 reflectDir = reflect(-lightDir, normal);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
vec3 specular = vec3(0.2) * spec;
FragColor = vec4(ambient + diffuse + specular, 1.0);
}

37
Shader/bump.vs Normal file
View File

@ -0,0 +1,37 @@
#version 430
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 VS_OUT {
vec3 FragPos;
vec2 TexCoords;
vec3 TangentLightPos;
vec3 TangentViewPos;
vec3 TangentFragPos;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform vec3 lightPos;
uniform vec3 viewPos;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
vs_out.TexCoords = aTexCoords;
vec3 T = normalize(mat3(model) * aTangent);
vec3 B = normalize(mat3(model) * aBitangent);
vec3 N = normalize(mat3(model) * aNormal);
mat3 TBN = transpose(mat3(T, B, N));
vs_out.TangentLightPos = TBN * lightPos;
vs_out.TangentViewPos = TBN * viewPos;
vs_out.TangentFragPos = TBN * vs_out.FragPos;
}

View File

@ -5,6 +5,7 @@
#include <GLFW/glfw3.h>
#include <iostream>
#include "BumpMapDemo.h"
#include "Framebuffer3D.h"
#include "Input.h"
#include "MCRenderer.h"
@ -59,7 +60,7 @@ int main() {
glEnable(GL_DEPTH_TEST);
// Setup the Marching Cubes renderer
MCRenderer renderer = MCRenderer(128, 128, 128);
BumpMapDemo renderer;
// render loop
double timeInLastFrame = glfwGetTime();