【发布时间】:2015-03-13 22:13:45
【问题描述】:
我正在学习 GLSL 并尝试实现一些光照和映射技巧。我正在使用 ShaderDesigner 工具。编码法线贴图后,我意识到我的模型照明看起来并不真实。这是我的代码和一些图片。如果可能的话,告诉我我的问题是什么。
顶点着色器
#define MAX_LIGHTS 1
struct LightProps
{
vec3 direction[MAX_LIGHTS];
};
attribute vec3 tangent;
attribute vec3 bitangent;
varying LightProps lights;
void main()
{
vec3 N = normalize(gl_NormalMatrix*gl_Normal);
vec3 T = normalize(gl_NormalMatrix*tangent);
vec3 B = normalize(gl_NormalMatrix*bitangent);
mat3 TBNMatrix = mat3(T,B,N);
vec4 vertex = gl_ModelViewMatrix*gl_Vertex;
for(int i = 0; i < MAX_LIGHTS; i++)
{
vec4 lightPos = gl_LightSource[i].position;
lights.direction[i] = vec3(lightPos.w > 0 ? lightPos-vertex : lightPos);
lights.direction[i] *= TBNMatrix;
}
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}
片段着色器
#define MAX_LIGHTS 1
struct LightProps
{
vec3 direction[MAX_LIGHTS];
};
uniform sampler2D textureUnit;
uniform sampler2D normalTextureUnit;
uniform vec4 TexColor;
varying LightProps lights;
void main()
{
vec3 N = normalize(texture2D(normalTextureUnit,gl_TexCoord[0].st).rgb*2.0-1.0);
vec4 color = vec4(0,0,0,0);
for(int i = 0; i < MAX_LIGHTS; i++)
{
vec3 L = lights.direction[i];
float dist = length(L);
L = normalize(L);
float NdotL = max(dot(N,L),0.0);
if(NdotL > 0)
{
float att = 1.0;
if(gl_LightSource[i].position.w > 0)
{
att = 1.0/ (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist);
}
vec4 ambient = gl_FrontLightProduct[i].ambient;
vec4 diffuse = clamp(att*NdotL*gl_FrontLightProduct[i].diffuse,0,1);
color += att*(ambient+diffuse);
}
}
vec4 textureColor = texture2D(textureUnit, vec2(gl_TexCoord[0]));
gl_FragColor = TexColor*textureColor + gl_FrontLightModelProduct.sceneColor + color;
}
我将 TexColor 设置为 (0.3,0.3,0.3,1.0) 并截图:
截图
当我向左旋转相机和灯光时,有一点点灯光, 但是当我向右旋转时,飞机完全被照亮了。我认为有问题,因为没有法线贴图,飞机从两侧看起来都是一样的。这是正常的纹理。提前致谢。
法线贴图:
【问题讨论】:
-
我认为每个片段的这些法线,我只需要将这些法线转换到世界空间以与光的方向相乘以获得漫反射强度
-
不,可以正常工作的法线存储在对象空间中,但事实并非如此。这些法线在切线空间中,您可以看出这一点,因为主要颜色是蓝色。您有两个选择:1. 将所有照明方向向量转换为切线空间或 2. 将法线贴图从切线空间反向转换回视图空间.两者都需要构建 TBN 矩阵。
-
好的,谢谢。我会试试的
-
我尝试了您建议的解决方案,结果如下i1300.photobucket.com/albums/ag94/haksist/…。是真的吗?
-
看起来差不多,如果不知道灯的确切位置很难说。颜色被洗掉了,但在您的原始屏幕截图中已经是这种情况了。
标签: opengl glsl fragment-shader vertex-shader