我的 GLSL 着色器程序链接正常,但是当我尝试使用它时出错——我该如何调试它?
Posted
技术标签:
【中文标题】我的 GLSL 着色器程序链接正常,但是当我尝试使用它时出错——我该如何调试它?【英文标题】:My GLSL shader program links fine, but errors when I try to use it -- how do I debug this? 【发布时间】:2012-01-08 20:13:43 【问题描述】:如果我的 GLSL 中有语法错误,它会在链接时失败,不是吗?
无论如何,我尝试在 glslDevil 中运行我的程序(以前从未使用过此程序),它只是不断重复 wglGetCurrentContext()
。我不确定它是否应该这样做,或者因为它是一个 CLR 应用程序而感到困惑。
有没有更简单的方法来检查我的 GLSL 代码中的语法错误?
这似乎是导致问题的片段着色器......如果需要,这里是代码:
#version 330
const int MAX_POINT_LIGHTS = 2;
in vec2 TexCoord0;
in vec3 Normal0;
in vec3 WorldPos0;
out vec4 FragColor;
struct BaseLight
vec3 Color;
float AmbientIntensity;
float DiffuseIntensity;
;
struct DirectionalLight
struct BaseLight Base;
vec3 Direction;
;
struct Attenuation
float Constant;
float Linear;
float Exp;
;
struct PointLight
struct BaseLight Base;
vec3 Position;
Attenuation Atten;
;
uniform int gNumPointLights;
uniform DirectionalLight gDirectionalLight;
uniform PointLight gPointLights[MAX_POINT_LIGHTS];
uniform sampler2D gSampler;
uniform vec3 gEyeWorldPos;
uniform float gMatSpecularIntensity;
uniform float gSpecularPower;
vec4 CalcLightInternal(struct BaseLight Light, vec3 LightDirection, vec3 Normal)
vec4 AmbientColor = vec4(Light.Color, 1.0f) * Light.AmbientIntensity;
float DiffuseFactor = dot(Normal, -LightDirection);
vec4 DiffuseColor = vec4(0, 0, 0, 0);
vec4 SpecularColor = vec4(0, 0, 0, 0);
if (DiffuseFactor > 0)
DiffuseColor = vec4(Light.Color, 1.0f) * Light.DiffuseIntensity * DiffuseFactor;
vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0);
vec3 LightReflect = normalize(reflect(LightDirection, Normal));
float SpecularFactor = dot(VertexToEye, LightReflect);
SpecularFactor = pow(SpecularFactor, gSpecularPower);
if (SpecularFactor > 0)
SpecularColor = vec4(Light.Color, 1.0f) *
gMatSpecularIntensity * SpecularFactor;
return (AmbientColor + DiffuseColor + SpecularColor);
vec4 CalcDirectionalLight(vec3 Normal)
return CalcLightInternal(gDirectionalLight.Base, gDirectionalLight.Direction, Normal);
vec4 CalcPointLight(int Index, vec3 Normal)
vec3 LightDirection = WorldPos0 - gPointLights[Index].Position;
float Distance = length(LightDirection);
LightDirection = normalize(LightDirection);
vec4 Color = CalcLightInternal(gPointLights[Index].Base, LightDirection, Normal);
float Attenuation = gPointLights[Index].Atten.Constant +
gPointLights[Index].Atten.Linear * Distance +
gPointLights[Index].Atten.Exp * Distance * Distance;
return Color / Attenuation;
void main()
vec3 Normal = normalize(Normal0);
vec4 TotalLight = CalcDirectionalLight(Normal);
for (int i = 0 ; i < gNumPointLights ; i++)
TotalLight += CalcPointLight(i, Normal);
FragColor = texture2D(gSampler, TexCoord0.xy) * TotalLight;
编辑: 具体来说,当我调用glUseProgram
时,我会得到GL_INVALID_OPERATION
。文档说:
如果程序不是程序对象,则生成GL_INVALID_OPERATION。
如果程序无法成为其中的一部分,则会生成 GL_INVALID_OPERATION 当前状态。
GL_INVALID_OPERATION 如果 glUseProgram 在 glBegin 的执行和 glEnd 的相应执行。
但我不认为这是第一种或最后一种情况,因为在我调整着色器之前程序运行良好。 “不能成为当前状态的一部分”并没有给我太多继续。
【问题讨论】:
我注意到一些“1f”和“1.0f”(不允许)和“0”。一般来说,总是使用“1.0”和“0.0”格式是最安全的。至于验证你的着色器,我想我已经读过一些人推荐使用 RenderMonkey。如果你运行的是 Windows。编辑:请原谅我,显然“1f”在较新的着色器版本上有效,但为了更好的兼容性(尤其是 = ATI 卡),我认为我认为无论如何最好坚持使用“1.0”。 @harism:好吧,不是 f 杀死了它,而且我一辈子都不知道如何在 RenderMonkey 中打开着色器编辑器。 我认为可能是这些结构的定义。在 DirectionalLight 中,我有struct BaseLight
,但这不是声明,而是用法。我从教程中得到了这个,但我觉得这看起来很有趣.... 编辑: 哈!是的。
所以编译 (glGetShaderInfoLog()
) 和链接 (glGetProgramInfoLog()
) 日志中什么都没有?
【参考方案1】:
我认为一种可能的解释是代码中的 for 循环。
根据我的拙见,应该始终避免使用 for 语句。
考虑到 OpenGL ES 仅支持固定数量的迭代,并且在您的情况下,由于您是基于统一的,因此我会对其进行调查。
此外,考虑到许多驱动程序展开 for 语句以优化生成的代码。
换句话说,我会专注于更简单的着色器版本,如下所示:
if (gNumPointLights == 1)
TotalLight += CalcPointLight(1, Normal);
else if (gNumPointLights == 2)
TotalLight += CalcPointLight(1, Normal);
TotalLight += CalcPointLight(2, Normal);
else if (gNumPointLights == 3)
TotalLight += CalcPointLight(1, Normal);
TotalLight += CalcPointLight(2, Normal);
TotalLight += CalcPointLight(3, Normal);
显然,代码的样式和效率可以优化,但它是一个快速的起点。
无论如何,实际上,您不会同时拥有数千盏灯 :)
干杯
【讨论】:
实际上,我计划支持数百个......我的计算机可以处理的数量。是为了游戏,会有很多光源。我不确定为什么要手动展开该循环,除非它特别导致错误。特别是如果,如你所说,司机会为我做这件事。它会更难维护。 老实说,我想建议您避免在代码中使用大量灯光,因为根据代码的复杂性,它实际上会影响引擎的性能。考虑到固定线 OpenGL 默认支持 8 个灯,因为在普通 OpenGL 场景中它是非常多的灯。现在,您处于可编程管道中,但概念和所需的计算能力非常相似,我会避免这种方法。 那其他游戏是怎么做的呢?手电筒、灯光、车灯、手电筒、发光的方块或盔甲、施法的魔法……这一切都是伪造的还是什么?无论如何,我都会进行性能测试并找出哪些有效,哪些无效。感谢您的建议。 @Mark:他们使用了一种称为延迟着色的技术。您渲染几何图形以输出材质数据(闪亮、漫反射等)以及法线和世界位置到多个缓冲区,然后将每个灯光“渲染”为与该灯光的体积相对应的几何图形。然后,灯光着色器从先前的缓冲区中读取并渲染颜色输出,并使用加法混合。因此,照明计算仅针对实际可见和为此光源照明的像素进行。使用深度剪刀限制深度空间中受影响的像素,而不仅仅是屏幕空间。 @Macke:感谢您的解释。当我回到这个问题时,我将不得不进一步研究延迟着色。【参考方案2】:问题是这样的:
struct PointLight
struct BaseLight Base;
vec3 Position;
Attenuation Atten;
;
应该只是BaseLight Base
,不是struct
还有这个:
vec4 CalcLightInternal(struct BaseLight Light, vec3 LightDirection, vec3 Normal)
同样的问题。
觉得它看起来很有趣,所以我改变了它,它开始工作了。
【讨论】:
【参考方案3】:当程序对象链接成功后,调用glUseProgram可以使程序对象成为当前状态的一部分。所以在使用程序之前应该调用程序链接
【讨论】:
【参考方案4】:就我而言,我在一行的末尾有一个额外的刻度线。胖拇指打字。
gl_FragColor = vec4(0.6, 0.6, 0.6, 1.0);`
去掉勾号解决了这个问题。
奇怪的是,它一直通过编译,链接并在尝试使用程序时抛出错误。
【讨论】:
以上是关于我的 GLSL 着色器程序链接正常,但是当我尝试使用它时出错——我该如何调试它?的主要内容,如果未能解决你的问题,请参考以下文章