我正在尝试对我的着色器实现法线映射,但我不断得到奇怪的结果。
我已经实现了漫反射和镜面光(它们正在工作)。我首先从法线贴图计算归一化向量:Ni = 2 * normalColor - 1
然后通过法线和切线的交叉向量计算副法线向量。
最后,我通过转置(正切、副法线、法线)创建了 TBN 矩阵
这是我的代码和一些屏幕截图。
顶点着色器
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
in vec4 vertexTangent;
// Input uniform values
uniform mat4 mvp;
// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragPosition;
out vec4 fragTangent;
out vec3 fragNormal;
// out vec3 fragBiTangent;
// NOTE: Add here your custom variables
void main()
{
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
//added
fragNormal = vertexNormal;
fragPosition = vertexPosition;
fragTangent = vertexTangent;
// Calculate final vertex position
gl_Position = mvp*vec4(vertexPosition, 1.0);
}
片段着色器
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragNormal;
in vec3 fragPosition;
in vec4 fragTangent;
// Input uniform values
uniform sampler2D texture0; // diffuse texture
uniform vec4 colDiffuse;
uniform vec3 lightPos; // light position
uniform mat4 matModel; // pos, rotation and scaling of object
uniform vec3 viewPos; // eyes position
uniform sampler2D normalMap; // normal texture
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
vec3 unHomogenous(vec4 v)
{
return v.xyz/v.w;
}
void main()
{
//=====================LOAD TEXTURES=============================
// Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord);
// obtain normal from normal map in range [0,1]
vec3 normalColor = texture(normalMap, fragTexCoord).xyz;
//=======================PARAMETERS==============================
// calculate normal in world coordinates
mat3 matNormal = transpose(inverse(mat3(matModel))); //CPU heavy
vec3 worldNormal = normalize(matNormal * fragNormal);
// Calculate the location of this fragment (pixel) in world coordinates
vec3 worldPosition = unHomogenous(matModel * vec4(fragPosition, 1.0));
//=======================NORMAL MAPPING========================
// transform normal vector to range [-1,1]
vec3 normal = normalize(normalColor * 2.0 - 1.0);
normal = normalize(matNormal * normal);
vec3 tangent = normalize(matNormal * fragTangent.xyz);
vec3 binormal = normalize(cross(normal, tangent));
mat3 TBN = mat3(tangent, binormal, worldNormal);
TBN = transpose(TBN);
//=======================DIFFUSING LIGHT===========================
// Shading is calculated by diffuse = (LightVect dot NormalVect) * Diffused color
vec3 ambiant = 0.01 * texelColor.xyz ;
// find light source : L = Lightposition - surfacePosition
vec3 lightDir = normalize(lightPos - worldPosition);
lightDir *= TBN; // NOT WORKING
// diffuse the light with the dot matrix :
float shading = clamp(dot(worldNormal, lightDir), 0.1, 1.0);
vec3 diffuse = shading * texelColor.xyz;
//=======================SPECULAR LIGHTNING====================
//intensity between 0 and 1
float specularStrength = 1;
// //calculate the view direction vector and corresponding reflect vector along the normal axis
vec3 viewDir = normalize(viewPos - worldPosition);
viewDir *= TBN; // NOT WORKING
vec3 reflectDir = reflect(-lightDir, worldNormal);
//Note that we negate the lightDir vector.
//The reflect function expects the first vector to point from the light source towards the fragment's position,
//but the lightDir vector is currently pointing the other way
// calclulate the specula component 32 is the shininess value of the highlight
int shininess = 32;
float spec = pow(clamp(dot(viewDir, reflectDir), 0.1, 1.0), shininess);
vec3 lightColor = vec3(1.0,1.0,1.0);
vec3 specular = specularStrength * spec * texelColor.xyz;
//=======================RENDER================================
finalColor = vec4(ambiant + diffuse + specular, 1.0);
}
主文件
#include "raylib.h"
#include "rlgl.h"
#include <math.h>
#include <raymath.h>
int main(void)
{
// Initialization
//[...]
//=====================WALL=======================//
Vector3 position = { -2.5f, 3.0f, 0.0f };
Model model = LoadModel("assets/models/wall.obj");
Texture2D texture = LoadTexture("assets/textures/cgaxis_pbr_17_stone_wall_5_diffuse.png");
// Set normal mapping
Texture2D normal_texture = LoadTexture("assets/textures/cgaxis_pbr_17_stone_wall_5_normal.png");
model.materials[0].maps[MATERIAL_MAP_NORMAL].texture = normal_texture;
//==========Generate mesh and diffuse texture=========//
GenMeshTangents(model.meshes);
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture
//===================SELECT SHADERS====================//
// Shader shader = LoadShader("assets/shaders/base.vs", "assets/shaders/base.fs"); // diffuse light
// Shader shader = LoadShader("assets/shaders/specular.vs", "assets/shaders/specular.fs"); // diff + specular
Shader shader = LoadShader("assets/shaders/normal_mapping.vs", "assets/shaders/normal_mapping.fs"); // diff + spec + normal mapping
// Set shader effect to 3d model
model.materials[0].shader = shader;
//==================Light======================//
Vector3 sunPos = {0.0f, 2.0f, 0.0f };
float rotation = 90.0f;
float radius = 5.0f;
// Diffuse light
int lightPosLoc = GetShaderLocation(shader, "lightPos");
float lightPos[] = {sunPos.x, sunPos.y, sunPos.z};
SetShaderValue(shader, lightPosLoc, lightPos, SHADER_UNIFORM_VEC3);
//specular light
int specularPosLoc = GetShaderLocation(shader, "viewPos");
float specularPos[] = {camera.position.x, camera.position.y, camera.position.z};
SetShaderValue(shader, specularPosLoc, specularPos, SHADER_UNIFORM_VEC3);
//RUN & draw
//[...]
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}