HLSL missing declarations?

I have made a - basic - shader in HLSL which runs fine in DX but throws compilation errors in OpenGL:

ERROR: 0:47: 'ps_v4' : undeclared identifier 
ERROR: 0:47: 'xyz' :  field selection requires structure, vector, or matrix on left hand side 
ERROR: 0:48: 'ps_v3' : undeclared identifier 
ERROR: 0:48: 'xyz' :  field selection requires structure, vector, or matrix on left hand side 
ERROR: 0:70: 'ps_v5' : undeclared identifier 
ERROR: 0:70: 'xxxx' :  field selection requires structure, vector, or matrix on left hand side 

I don’t know much about GLSL, but I did look into the generated .xnb files and indeed, the declarations are missing:

...
...
uniform sampler2D ps_s0;
uniform sampler2D ps_s1;
varying vec4 vTexCoord0;
#define ps_v0 vTexCoord0
#define ps_oC0 gl_FragColor
varying vec4 vTexCoord1;
#define ps_v1 vTexCoord1
varying vec4 vFrontColor;
#define ps_v2 vFrontColor

void main()
...
...
ps_r1 = (ps_r1.xyzx * ps_c12.wwwz) + ps_c12.zzzw;
ps_r0 = clamp(ps_r0 * ps_r1, vec4(0.0), vec4(1.0));
ps_oC0 = mix(ps_c12.zzzw, ps_r0, ps_v5.xxxx);
...

but they are used in the same file.

Can someone help me find out, what exactly could be the problem, so MGCP is building that file wrong?
There is no error in MGCP, just warnings about implicit vector truncations.

The whole shadercode may be a bit wrong, but it’s not so unusal, but is using Tangent/Binormal for bumpmapping:

struct VSI
{
	float4 Position : POSITION0;
	float4 Normal : NORMAL0;
	float2 UV : TEXCOORD0;
	float4 Color : COLOR0;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

Any ideas?

I’m not aware of the differences between DX and OpenGL compilation, but if the shader is basic, can you show us the full HLSL source? Maybe something will stand out.

sure - I even tried the same shader without the bumpmapping (an older version) and it has the same error …

#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

matrix World;
matrix View;
matrix Projection;
matrix WorldIT;

float4 MixColor = float4(1.0, 1.0, 1.0, 1.0);

float4 AmbientColor = float4(1.0, 1.0, 1.0, 1.0);
float AmbientIntensity = 0.3;

float3 DiffuseLightDirection = float3(1.0, 0, 0);
float4 DiffuseColor = float4(1.0, 1.0, 1.0, 1.0);
float DiffuseIntensity = 1.0;

float Shininess = 200.0;
float4 SpecularColor = float4(1, 1, 1, 1);
float SpecularIntensity = 0.1;
float3 ViewVector = float3(1, 0.0, 0.0);

texture Texture;
sampler2D textureSampler = sampler_state {
	Texture = (Texture);
	MinFilter = Linear;
	MagFilter = Linear;
	AddressU = Clamp;
	AddressV = Clamp;
};

texture NormalMap;
sampler2D bumpSampler = sampler_state {
	Texture = (NormalMap);
	MinFilter = Linear;
	MagFilter = Linear;
	AddressU = Clamp;
	AddressV = Clamp;
};

struct VSI
{
	float4 Position : POSITION0;
	float4 Normal : NORMAL0;
	float2 UV : TEXCOORD0;
	float4 Color : COLOR0;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

struct VSO
{
	float4 Position : POSITION0;
	float3 Normal : TEXCOORD0;
	float2 UV : TEXCOORD1;
	float4 Color : COLOR0;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
    float Fog : FOG;
};

VSO VS(in VSI input)
{
	VSO output;

	float4 worldPosition = mul(input.Position, World);
	float4 viewPosition = mul(worldPosition, View);
	output.Position = mul(viewPosition, Projection);

	output.Color = input.Color;

	output.Normal = mul(input.Normal, WorldIT).xyz;
	output.Tangent = mul(input.Tangent, WorldIT);
	output.Binormal = mul(input.Binormal, WorldIT);

	output.UV = input.UV;

    output.Fog = 1.0;

	return output;
}

float4 PS(VSO input) : COLOR
{
	float3 bump = 3.5f * (tex2D(bumpSampler, input.UV) - float3(0.5,0.5,0.5));
	float3 bumpNormal = input.Normal + (bump.x * input.Tangent + bump.y * input.Binormal);
	bumpNormal = normalize(bumpNormal);

	float3 light = normalize(DiffuseLightDirection);

	float diffuseIntensity = dot(light, bumpNormal);
	if (diffuseIntensity < 0)
	{
		diffuseIntensity = 0;
	}

	float3 r = normalize(2.0 * dot(light, bumpNormal) * bumpNormal - light);
	float3 v = normalize(mul(normalize(ViewVector), World));
	float dotProduct = saturate(dot(r, v));

	float4 specular = SpecularIntensity * SpecularColor * max(pow(dotProduct, Shininess), 0.0) * diffuseIntensity;

	float4 textureColor = tex2D(textureSampler, input.UV);
	textureColor.a = 1;

	float4 col = saturate(textureColor * (input.Color * diffuseIntensity * MixColor + AmbientColor * AmbientIntensity + specular));

	return col;
}

technique BasicColorDrawing
{
	pass P0
	{
		VertexShader = compile VS_SHADERMODEL VS();
		PixelShader = compile PS_SHADERMODEL PS();
	}
};

another version without bump mapping - really just a basic texture/specular shader, produces this:

as you can see at the end of the main function, there is some ps_v3 which is not declared at the top. I also don’t know why there is a “mix” in there, because there is no “lerp” in HLSL code (which is the equivalent of mix afaik)

...
uniform sampler2D ps_s0;
varying vec4 vTexCoord0;
#define ps_v0 vTexCoord0
#define ps_oC0 gl_FragColor
varying vec4 vTexCoord1;
#define ps_v1 vTexCoord1
varying vec4 vFrontColor;
#define ps_v2 vFrontColor

void main()
{
	ps_r0.xyz = normalize(ps_c11.xyz);
	ps_r1.w = dot(ps_r0.xyz, ps_c3.xyz);
	ps_r1.x = dot(ps_r0.xyz, ps_c0.xyz);
	ps_r1.y = dot(ps_r0.xyz, ps_c1.xyz);
	ps_r1.z = dot(ps_r0.xyz, ps_c2.xyz);
	ps_r0.x = dot(ps_r1, ps_r1);
	ps_r0.x = inversesqrt(ps_r0.x);
	ps_r0.xyz = ps_r0.xxx * ps_r1.xyz;
	ps_r1.xyz = normalize(ps_c7.xyz);
	ps_r2.xyz = normalize(ps_v0.xyz);
	ps_r0.w = dot(ps_r1.xyz, ps_r2.xyz);
	ps_r0.w = ps_r0.w + ps_r0.w;
	ps_r1.xyz = (ps_r0.www * ps_r2.xyz) + -ps_r1.xyz;
	ps_r2.xyz = normalize(ps_r1.xyz);
	ps_r0.x = clamp(dot(ps_r2.xyz, ps_r0.xyz), 0.0, 1.0);
	ps_r1.x = pow(abs(ps_r0.x), ps_c8.x);
	ps_r0.x = ps_c10.x;
	ps_r0 = ps_r0.xxxx * ps_c9;
	ps_r0 = ps_r1.xxxx * ps_r0;
	ps_r1.x = dot(ps_v2, ps_v2);
	ps_r1.x = inversesqrt(ps_r1.x);
	ps_r1.x = 1.0 / ps_r1.x;
	ps_r2 = ps_c5;
	ps_r2 = ps_r2 * ps_c6.xxxx;
	ps_r2 = (ps_v2 * ps_c4) + ps_r2;
	ps_r0 = (ps_r0 * ps_r1.xxxx) + ps_r2;
	ps_r1 = texture2D(ps_s0, ps_v1.xy);
	ps_r1 = (ps_r1.xyzx * ps_c12.xxxy) + ps_c12.yyyx;
	ps_r0 = clamp(ps_r0 * ps_r1, vec4(0.0), vec4(1.0));
	ps_oC0 = mix(ps_c12.yyyx, ps_r0, ps_v3.xxxx);
}
...

`

OH WAIT! Could it be the FOG in VSO? Which is in register FOG … not sure if this exists in GLSL…`

edit: Tried with packing the fog value into the Color.a and get rid of the FOG. The error persists.

After lots of fiddeling around, I somehow solved the error - I still don’t know why, but here is what I’ve done:

In the VertexShaderOutput (struct VSO), I replaced TANGENT0 and BINORMAL0 with TEXCOORD2 and TEXCOORD3 - that finally resolved the issue and the shader does now compile and the output seems to be correct.

While it seems to be OK to habe TANGENT/BINORMAL register in VS_Input, somehow it is not working in VS_Output.

Yes, I usually look at the D3D semantics docs for reference. I mainly just use COLOR and TEXCOORD in the PS (and thus the VS output). The same seems to apply to OpenGL in my experience. I’m not sure if it was expected to really work before in DX anyway.

just looked it up. Never realised that TANGENT/BINORMAL are not for output - a dev learns something new everyday :slight_smile:

There were some other hickups involved, which may or may not help anyone who struggles with the GLSL compilation:

  • if you define default values in HLSL, those will not be taken over to GLSL - always assign every (global) parameter over the effect class (took me a while to find out why some lighting is weird)

  • a wierd thing was, that I had to normalize to normals after multiplying with WorldInverseTranspose in GLSL but not in HLSL. took me several hours to find out why tthere were issues with lighting