在使用基本教程搞砸了很多东西之后,我将尝试通过顶点或片段着色器实现OpenGL光照。问题是,根据摄像机视角,背景中有一个形状,而结果不依赖于我是否在顶点或片段中进行:
取决于视角,它看起来有点像前面和右边的空中飞人,只有在几乎看不见的情况下才能显示出亮起的表面(不知何故让我想起了一个平截头体)。
现在我对点光源的理解是,与聚光灯不同,它可以照亮任何方向的所有物体,也不应该依赖于相机。
我现在主要关注本教程:http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Diffuse_Reflection或http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights,而现在更像是第二个。
请不要怀疑我现在几乎把所有东西都传递给片段,只是为了试验它,如上所述,如果没有将任何东西传递给片段着色器,除了漫反射颜色并做所有事情之外,它会做同样的事情像第一篇教程中的顶点。另请注意,我还添加了一个纹理,这似乎可以很好地与coords。光位置目前处于世界空间,但也尝试在眼睛空间。我使用GLM在c ++中进行矩阵的大部分数学运算,只传递它。
FLOAT ViewMatrix[16] =
{
1.f, 0.f, 0.f, 0.f,
0.f, -1.f, 0.f, 0.f,
0.f, 0.f, -1.f, 0.f,
0.f, 0.f, 0.f, 1.f
};
viewMat = glm::make_mat4(ViewMatrix);
// Identity
modelMat = glm::mat4(1.0f);
//gl_NormalMatrix ?
modelviewMat=modelMat*viewMat;
m_3x3_inv_transp = glm::inverseTranspose(glm::mat3(modelviewMat));
//viewMat inverted
viewMatinv = glm::inverse(viewMat);
projMat = glm::frustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0f, 32768.0);
我当前的顶点着色器看起来像这样(暂时忽略任何环境或镜面反射):
uniform sampler2D Texture0;
layout (location = 0) in vec3 v_coord; // == gl_Vertex
layout (location = 1) in vec3 v_normal;
uniform mat3 m_3x3_inv_transp; // == gl_NormalMatrix inverse transpose of modelviewMat
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
uniform mat4 modelviewMat;
uniform mat4 modelviewprojMat; // == gl_ModelViewProjectionMatrix == projMat*viewMat*modelMat;
uniform mat4 viewMatinv; // == ViewMatrix inverse
out vec2 vTexCoords;
out vec3 vv_coord;
out vec3 vv_normal;
out vec3 vNormalDirection;
out mat3 vm_3x3_inv_transp;
out mat4 vprojMat;
out mat4 vviewMat;
out mat4 vmodelMat;
out mat4 vmodelviewMat;
out mat4 vmodelviewprojMat;
out mat4 vviewMatinv;
void main(void)
{
//pass matrices also to fragment shader
vprojMat = projMat;
vviewMat = viewMat;
vmodelMat = modelMat;
vmodelviewMat = modelviewMat;
vmodelviewprojMat = modelviewprojMat;
vm_3x3_inv_transp = m_3x3_inv_transp;
vviewMatinv = viewMatinv;
vv_coord = v_coord;
vv_normal = v_normal;
//Texture UV to fragment
vTexCoords=TexCoords;
//Texture UV Lightmap to fragment
vLightTexCoords = LightTexCoords;
vNormalDirection = m_3x3_inv_transp * v_normal;
gl_Position = modelviewprojMat * vec4(v_coord, 1.0);
}
虽然片段着色器目前看起来像这样:
uniform sampler2D Texture0;
in vec2 vTexCoords;
in vec2 vLightTexCoords;
in vec3 vv_coord;
in vec3 vv_normal;
in vec3 vNormalDirection;
in mat3 vm_3x3_inv_transp;
in mat4 vprojMat;
in mat4 vviewMat;
in mat4 vmodelMat;
in mat4 vmodelviewMat;
in mat4 vmodelviewprojMat;
in mat4 vviewMatinv;
struct LightInfo
{
vec4 LightLocation;
vec3 DiffuseLightColor;
vec3 AmbientLightColor;
vec3 SpecularLightColor;
vec3 spotDirection;
float AmbientLightIntensity;
float SpecularLightIntensity;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
float spotCutoff;
float spotExponent;
};
uniform LightInfo gLight;
struct material
{
vec4 diffuse;
};
material mymaterial = material(vec4(1.0, 0.8, 0.8, 1.0));
out vec4 FragColor;
void main (void)
{
vec4 color = texture2D(Texture0, vTexCoords);
vec3 normalDirection = normalize(vNormalDirection);
vec3 lightDirection;
float attenuation;
vec3 positionToLightSource;
if (gLight.LightLocation.w == 0.0) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(vec3(gLight.LightLocation));
}
else // point light or spotlight (or other kind of light)
{
positionToLightSource = vec3(gLight.LightLocation - vec4(vv_coord,1.0));
}
vec3 diffuseReflection = vec3(gLight.DiffuseLightColor) * max(0.0, dot(normalDirection, lightDirection));
FragColor = color*vec4(diffuseReflection,1.0);
}
我目前还省去了衰减以简化它,但是随着衰减,它也无法工作。将它设置为方向光,似乎很好,左边的墙完全被点亮,光的位置似乎也是正确的,因为在球体上是明显的。 然而,positionToLightSource似乎是罪魁祸首,但是由于LightLocation是修复的,它必须是vv_coord,我也尝试使用任何可用的矩阵进行任何可想象的转换版本,无论它是否有意义只是为了看它的行为,因为我在这里读了一些问题把矢量作为颜色可以帮助调试,但我无法弄清楚。如何看待一个vnormal的modelviewMat的逆转置?但无论如何它似乎并不关心视角...
我的猜测是,并非所有东西都在同一个空间(会很傻,但我会感到惊讶,因为它可以作为方向性光),或者由于某种原因f.e. normalDirection / vnormals是不对的 - 我不完全确定它,因为我从旧的游戏引擎中得到了这个应该可以工作的值,并且可以在某些教程和示例代码完美无缺地工作。
现在要做一个摘要,这不仅仅是关于当前的问题,因为它的来源可能超出了这些着色器的范围,因此可能没有解决方案,尽管我仍然希望即便如此有一个想法,但也如何正确调试这样的事情。我也尝试过glsldevil,但没有经验可能是对或错,在没有任何printf或其他东西的情况下进行调试时我仍然感到很无助。将矢量输出作为颜色也非常酷,但据说我不知道什么是“应该看起来正确” - 是否存在某种“有效调试输出”的存档?请仅针对OpenGL3或更新版本的建议:)
答案 0 :(得分:1)
似乎是我获得法线信息的引擎需要先对屏幕坐标进行一些转换,所以绝对不是着色器的问题。将vv_coords和LightLocation相乘然后用modMat将它放在正确的空间中,一切看起来都像预期的那样。不过,如果有一些档案或文档可以从glsl内部进行某种“颜色调试”,那么我仍然感兴趣。 不管怎样,谢谢;)
稍后编辑,对于任何寻找调试提示的人:http://antongerdelan.net/opengl/debugshaders.html