由于内置制服(如gl_LightSource )现在在OpenGL规范的最新版本中被标记为不受欢迎,我目前正在实现一个基本的照明系统(点灯现在),该系统通过自定义的统一变量接收所有光线和材料信息。
我已经实现了一个点光的光衰减和镜面高光,它似乎工作良好,除了一个位置故障:我正在手动移动灯,改变它沿X轴的位置。然而,光源(从它投射到它下面的正方形平面上的光线判断)似乎不是沿着X轴移动,而是在X轴和Z轴上对角移动(可能也是Y,虽然它并不完全是定位错误)。
这是变形情况的屏幕截图(光线在-35,5,0,苏珊娜在0,2,0:

当光线在0,5,0时,它看起来没问题:

根据OpenGL规范,所有默认的光计算都是在眼睛坐标中进行的,这就是我在这里试图模拟的(因此光位置与vMatrix相乘)。我只使用视图矩阵,因为应用对光线渲染的顶点批处理的模型转换是没有意义的。
如果有关系的话,所有飞机的法线都指向- 0,1,0。
(注:我现在解决了这个问题,多亏了msell和myAces!下面的片段是修正后的版本。也有一个选项,添加聚光灯参数,现在(d3d风格的)
下面是我在顶点着色器中使用的代码
#version 330
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat4 vMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
uniform vec3 spotDirection;
uniform bool useTexture;
uniform bool fogEnabled;
uniform float minFogDistance;
uniform float maxFogDistance;
in vec4 vVertex;
in vec3 vNormal;
in vec2 vTexCoord;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
smooth out vec2 vVaryingTexCoords;
smooth out float fogFactor;
smooth out vec4 vertPos_ec;
smooth out vec4 lightPos_ec;
smooth out vec3 spotDirection_ec;
void main() {
// Surface normal in eye coords
vVaryingNormal = normalMatrix * vNormal;
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
vec4 tLightPos4 = vMatrix * vec4(vLightPosition, 1.0);
vec3 tLightPos = tLightPos4.xyz / tLightPos4.w;
// Diffuse light
// Vector to light source (do NOT normalize this!)
vVaryingLightDir = tLightPos - vPosition3;
if(useTexture) {
vVaryingTexCoords = vTexCoord;
}
lightPos_ec = vec4(tLightPos, 1.0f);
vertPos_ec = vec4(vPosition3, 1.0f);
// Transform the light direction (for spotlights)
vec4 spotDirection_ec4 = vec4(spotDirection, 1.0f);
spotDirection_ec = spotDirection_ec4.xyz / spotDirection_ec4.w;
spotDirection_ec = normalMatrix * spotDirection;
// Projected vertex
gl_Position = mvpMatrix * vVertex;
// Fog factor
if(fogEnabled) {
float len = length(gl_Position);
fogFactor = (len - minFogDistance) / (maxFogDistance - minFogDistance);
fogFactor = clamp(fogFactor, 0, 1);
}
}这是我在片段着色器中使用的代码
#version 330
uniform vec4 globalAmbient;
// ADS shading model
uniform vec4 lightDiffuse;
uniform vec4 lightSpecular;
uniform float lightTheta;
uniform float lightPhi;
uniform float lightExponent;
uniform int shininess;
uniform vec4 matAmbient;
uniform vec4 matDiffuse;
uniform vec4 matSpecular;
// Cubic attenuation parameters
uniform float constantAt;
uniform float linearAt;
uniform float quadraticAt;
uniform float cubicAt;
// Texture stuff
uniform bool useTexture;
uniform sampler2D colorMap;
// Fog
uniform bool fogEnabled;
uniform vec4 fogColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
smooth in vec2 vVaryingTexCoords;
smooth in float fogFactor;
smooth in vec4 vertPos_ec;
smooth in vec4 lightPos_ec;
smooth in vec3 spotDirection_ec;
out vec4 vFragColor;
// Cubic attenuation function
float att(float d) {
float den = constantAt + d * linearAt + d * d * quadraticAt + d * d * d * cubicAt;
if(den == 0.0f) {
return 1.0f;
}
return min(1.0f, 1.0f / den);
}
float computeIntensity(in vec3 nNormal, in vec3 nLightDir) {
float intensity = max(0.0f, dot(nNormal, nLightDir));
float cos_outer_cone = lightTheta;
float cos_inner_cone = lightPhi;
float cos_inner_minus_outer = cos_inner_cone - cos_outer_cone;
// If we are a point light
if(lightTheta > 0.0f) {
float cos_cur = dot(normalize(spotDirection_ec), -nLightDir);
// d3d style smooth edge
float spotEffect = clamp((cos_cur - cos_outer_cone) /
cos_inner_minus_outer, 0.0, 1.0);
spotEffect = pow(spotEffect, lightExponent);
intensity *= spotEffect;
}
float attenuation = att( length(lightPos_ec - vertPos_ec) );
intensity *= attenuation;
return intensity;
}
/**
* Phong per-pixel lighting shading model.
* Implements basic texture mapping and fog.
*/
void main() {
vec3 ct, cf;
vec4 texel;
float at, af;
if(useTexture) {
texel = texture2D(colorMap, vVaryingTexCoords);
} else {
texel = vec4(1.0f);
}
ct = texel.rgb;
at = texel.a;
vec3 nNormal = normalize(vVaryingNormal);
vec3 nLightDir = normalize(vVaryingLightDir);
float intensity = computeIntensity(nNormal, nLightDir);
cf = matAmbient.rgb * globalAmbient.rgb + intensity * lightDiffuse.rgb * matDiffuse.rgb;
af = matAmbient.a * globalAmbient.a + lightDiffuse.a * matDiffuse.a;
if(intensity > 0.0f) {
// Specular light
// - added *after* the texture color is multiplied so that
// we get a truly shiny result
vec3 vReflection = normalize(reflect(-nLightDir, nNormal));
float spec = max(0.0, dot(nNormal, vReflection));
float fSpec = pow(spec, shininess) * lightSpecular.a;
cf += intensity * vec3(fSpec) * lightSpecular.rgb * matSpecular.rgb;
}
// Color modulation
vFragColor = vec4(ct * cf, at * af);
// Add the fog to the mix
if(fogEnabled) {
vFragColor = mix(vFragColor, fogColor, fogFactor);
}
}是什么数学错误导致了这种扭曲?
编辑1:
我更新了着色代码。衰减现在是计算在碎片阴影,因为它应该一直。但目前它已被禁用-- bug与衰减没有任何关系。当只渲染光的衰减因子时(见碎片着色器的最后几行),衰减计算是正确的。这意味着光线的位置被正确地转换成眼睛坐标,所以它不可能是错误的来源。
片段着色器的最后几行可以用于一些调试(稍微有点麻烦,但还是很有洞察力)--似乎每个片段的光强度都没有得到正确的计算,尽管我不知道为什么。
有趣的是,这个bug只在(非常)大的四边形上才能被注意到,比如图像中的地板。这在小型模特身上是不明显的。
编辑2:
我已经更新了着色代码到一个工作版本。现在一切都很好,我希望它能帮助任何未来的用户阅读这篇文章,因为到今天为止,我还没有看到任何glsl教程实现完全没有固定功能和秘密隐式转换(例如gl_LightSource[i].*和眼空间隐式转换)的glsl教程。
我的代码是根据BSD 2条款许可和可以在GitHub上找到许可的!
发布于 2013-01-03 11:52:40
最近,我遇到了一个类似的问题,在使用大多边形时,照明工作有点错误。问题是在顶点着色器中将眼睛矢量归一化,因为插值归一化值会导致不正确的结果。
变化
vVaryingLightDir = normalize( tLightPos - vPosition3 );至
vVaryingLightDir = tLightPos - vPosition3;在你的顶点着色器。您可以将规范化保存在片段着色器中。
发布于 2013-01-03 12:14:00
就因为我注意到:
vec3 tLightPos = (vMatrix * vec4(vLightPosition, 1.0)).xyz;你只是在这里消除了同质坐标,而不是首先对它进行分割。这会引起一些问题。
https://stackoverflow.com/questions/14114437
复制相似问题