Here is the shader from an example program I’m working with:
static const char* pFS = " \n\
#version 330 \n\
\n\
const int MAX_POINT_LIGHTS = 2; \n\
const int MAX_SPOT_LIGHTS = 2; \n\
\n\
in vec4 LightSpacePos; \n\
in vec2 TexCoord0; \n\
in vec3 Normal0; \n\
in vec3 WorldPos0; \n\
in vec3 Tangent0; \n\
\n\
out vec4 FragColor; \n\
\n\
struct BaseLight \n\
{ \n\
vec3 Color; \n\
float AmbientIntensity; \n\
float DiffuseIntensity; \n\
}; \n\
\n\
struct DirectionalLight \n\
{ \n\
struct BaseLight Base; \n\
vec3 Direction; \n\
}; \n\
\n\
struct Attenuation \n\
{ \n\
float Constant; \n\
float Linear; \n\
float Exp; \n\
}; \n\
\n\
struct PointLight \n\
{ \n\
struct BaseLight Base; \n\
vec3 Position; \n\
Attenuation Atten; \n\
}; \n\
\n\
struct SpotLight \n\
{ \n\
struct PointLight Base; \n\
vec3 Direction; \n\
float Cutoff; \n\
}; \n\
\n\
uniform int gNumPointLights; \n\
uniform int gNumSpotLights; \n\
uniform DirectionalLight gDirectionalLight; \n\
uniform PointLight gPointLights[MAX_POINT_LIGHTS]; \n\
uniform SpotLight gSpotLights[MAX_SPOT_LIGHTS]; \n\
uniform sampler2D gColorMap; \n\
uniform sampler2D gShadowMap; \n\
uniform sampler2D gNormalMap; \n\
uniform vec3 gEyeWorldPos; \n\
uniform float gMatSpecularIntensity; \n\
uniform float gSpecularPower; \n\
\n\
float CalcShadowFactor(vec4 LightSpacePos) \n\
{ \n\
vec3 ProjCoords = LightSpacePos.xyz / LightSpacePos.w; \n\
vec2 UVCoords; \n\
UVCoords.x = 0.5 * ProjCoords.x + 0.5; \n\
UVCoords.y = 0.5 * ProjCoords.y + 0.5; \n\
float Depth = texture(gShadowMap, UVCoords).x; \n\
if (Depth <= (ProjCoords.z + 0.005)) \n\
return 0.5; \n\
else \n\
return 1.0; \n\
} \n\
\n\
vec4 CalcLightInternal(struct BaseLight Light, vec3 LightDirection, vec3 Normal, \n\
float ShadowFactor) \n\
{ \n\
vec4 AmbientColor = vec4(Light.Color, 1.0f) * Light.AmbientIntensity; \n\
float DiffuseFactor = dot(Normal, -LightDirection); \n\
\n\
vec4 DiffuseColor = vec4(0, 0, 0, 0); \n\
vec4 SpecularColor = vec4(0, 0, 0, 0); \n\
\n\
if (DiffuseFactor > 0) { \n\
DiffuseColor = vec4(Light.Color, 1.0f) * Light.DiffuseIntensity * DiffuseFactor; \n\
\n\
vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0); \n\
vec3 LightReflect = normalize(reflect(LightDirection, Normal)); \n\
float SpecularFactor = dot(VertexToEye, LightReflect); \n\
SpecularFactor = pow(SpecularFactor, gSpecularPower); \n\
if (SpecularFactor > 0) { \n\
SpecularColor = vec4(Light.Color, 1.0f) * \n\
gMatSpecularIntensity * SpecularFactor; \n\
} \n\
} \n\
\n\
return (AmbientColor + ShadowFactor * (DiffuseColor + SpecularColor)); \n\
} \n\
\n\
vec4 CalcDirectionalLight(vec3 Normal) \n\
{ \n\
return CalcLightInternal(gDirectionalLight.Base, gDirectionalLight.Direction, Normal, 1.0); \n\
} \n\
\n\
vec4 CalcPointLight(struct PointLight l, vec3 Normal, vec4 LightSpacePos) \n\
{ \n\
vec3 LightDirection = WorldPos0 - l.Position; \n\
float Distance = length(LightDirection); \n\
LightDirection = normalize(LightDirection); \n\
float ShadowFactor = CalcShadowFactor(LightSpacePos); \n\
\n\
vec4 Color = CalcLightInternal(l.Base, LightDirection, Normal, ShadowFactor); \n\
float Attenuation = l.Atten.Constant + \n\
l.Atten.Linear * Distance + \n\
l.Atten.Exp * Distance * Distance; \n\
\n\
return Color / Attenuation; \n\
} \n\
\n\
vec4 CalcSpotLight(struct SpotLight l, vec3 Normal, vec4 LightSpacePos) \n\
{ \n\
vec3 LightToPixel = normalize(WorldPos0 - l.Base.Position); \n\
float SpotFactor = dot(LightToPixel, l.Direction); \n\
\n\
if (SpotFactor > l.Cutoff) { \n\
vec4 Color = CalcPointLight(l.Base, Normal, LightSpacePos); \n\
return Color * (1.0 - (1.0 - SpotFactor) * 1.0/(1.0 - l.Cutoff)); \n\
} \n\
else { \n\
return vec4(0,0,0,0); \n\
} \n\
} \n\
\n\
vec3 CalcBumpedNormal() \n\
{ \n\
vec3 Normal = normalize(Normal0); \n\
vec3 Tangent = normalize(Tangent0); \n\
Tangent = normalize(Tangent - dot(Tangent, Normal) * Normal); \n\
vec3 Bitangent = cross(Tangent, Normal); \n\
vec3 BumpMapNormal = texture(gNormalMap, TexCoord0).xyz; \n\
BumpMapNormal = 2.0 * BumpMapNormal - vec3(1.0, 1.0, 1.0); \n\
vec3 NewNormal; \n\
mat3 TBN = mat3(Tangent, Bitangent, Normal); \n\
NewNormal = TBN * BumpMapNormal; \n\
NewNormal = normalize(NewNormal); \n\
return NewNormal; \n\
} \n\
\n\
void main() \n\
{ \n\
vec3 Normal = CalcBumpedNormal(); \n\
vec4 TotalLight = CalcDirectionalLight(Normal); \n\
\n\
for (int i = 0 ; i < gNumPointLights ; i++) { \n\
TotalLight += CalcPointLight(gPointLights[i], Normal, LightSpacePos); \n\
} \n\
\n\
for (int i = 0 ; i < gNumSpotLights ; i++) { \n\
TotalLight += CalcSpotLight(gSpotLights[i], Normal, LightSpacePos); \n\
} \n\
\n\
vec4 SampledColor = texture2D(gColorMap, TexCoord0.xy); \n\
FragColor = SampledColor * TotalLight; \n\
}";
GLSL complains that:
Error compiling FS: ‘Fragment shader failed to compile with the following errors:
ERROR: 0:24: error(#132) Syntax error: ‘Base’ parse error
ERROR: error(#273) 1 compilation errors. No code generated’
However, the GLSL standard clearly states:
…it also
creates a variable of that type called variableName. As in C/C++, the
variable name can be omitted. Structs cannot contain variables of
sampler types. They can contain variables of other struct types.
Structs define a named type. But there are limits on the type
qualifiers that can be used with struct types. Uniforms can use struct
types, as well as regular globals, locals, and constant variables.
Structs cannot be used with any other storage qualifiers.
Why doesn’t this compile?
GLSL is not C. You don’t use the
structkeyword like that.BaseLightis a typename, so you just sayBaseLight Base. You do it correctly when you createPointLight, so I don’t know why you got it wrong so consistently with your uses ofBaseLight.