PDA

View Full Version : Strange Shader Behaviour



TimTimTim
01-13-2011, 10:58 AM
I am having a strange problem in which the behavior of my shader in rendermonkey is different than in OpenGL.

I am trying to create a simple terrain shader. In Rendermonkey this is displayed as a full terrain, where as in OpenGL it is just the first loaded image textured on the flat plane I am using. It looks like fixed function drawing.

Code to call and draw shader


virtual void Draw(SceneData* Scene)
{
Shader->Update(Scene);
glUseProgramObjectARB(Shader->m_Program);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, Mesh.VBO); // for vertex coordinates
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, Mesh.IBO);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);

glTexCoordPointer(2, GL_FLOAT, sizeof(VBOVertex),(char *)NULL + sizeof(point) * 2);
glNormalPointer(GL_FLOAT, sizeof(VBOVertex),(char *)NULL + sizeof(point));
glVertexPointer(3, GL_FLOAT, sizeof(VBOVertex), (char *)NULL + 0);

glDrawElements(GL_TRIANGLES, Mesh.VertexCount, GL_UNSIGNED_INT,(char *)NULL + 0);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);


glUseProgramObjectARB(0);
}



Shader->Update


void Update(SceneData* Scene)
{
glActiveTextureARB(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_DiffuseMapID);
glEnable(GL_TEXTURE_2D);
glUniform1iARB(m_DiffuseMapLoc, 1);

glActiveTextureARB(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_HeightMapID);
glEnable(GL_TEXTURE_2D);
glUniform1iARB(m_HeightMapLoc, 0);

glActiveTextureARB(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m_LightMapID);
glEnable(GL_TEXTURE_2D);
glUniform1iARB(m_LightMapLoc, 2);

glActiveTextureARB(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, m_NormalMapID);
glEnable(GL_TEXTURE_2D);
glUniform1iARB(m_NormalMapLoc, 3);

glActiveTextureARB(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, m_SpecularMapID);
glEnable(GL_TEXTURE_2D);
glUniform1iARB(m_SpecularMapLoc, 4);

glUniform1fARB(m_HeightScaleLoc, m_HeightScale);
glUniform3fARB(m_AmbientLoc, Scene->AmbientVector[0].x, Scene->AmbientVector[0].y, Scene->AmbientVector[0].z);
glUniform4fARB(m_EyePositionLoc, Scene->CameraVector[0].Position.x, Scene->CameraVector[0].Position.y, Scene->CameraVector[0].Position.z, 0);
glUniform3fARB(m_LightVectorLoc, -Scene->LightVector[0].Position.x, -Scene->LightVector[0].Position.y, -Scene->LightVector[0].Position.z);

}


Fragment Shader


uniform sampler2D LightMap;
uniform sampler2D NormalMap;
uniform sampler2D DiffuseMap;
uniform sampler2D SpecularMap;

uniform vec3 LightVector;
uniform vec3 Ambient;

varying vec2 vTexCoord;
varying vec3 ViewDirection;

float saturate( float inValue)
{
return clamp(inValue, 0.0, 1.0);
}

void main(void)
{
vec3 Normal = texture2D(NormalMap, vTexCoord).xyz;
normalize(Normal);
normalize(LightVector);
vec3 fvLightDirection = normalize( LightVector );

vec4 temp = texture2D(SpecularMap, vTexCoord);
float transparent = (temp.x + temp.y + temp.z)/3;
float SpecularIntensity = 0.4 * transparent;
float fvTotalSpecular = pow(saturate(dot(reflect(normalize(ViewDirection), Normal), fvLightDirection)), 45.0 );//temp * ( pow( fRDotV, fSpecularPower ) );
vec3 Specular = SpecularIntensity * vec3(fvTotalSpecular, fvTotalSpecular,fvTotalSpecular);


vec4 temp1 = texture2D(LightMap, vTexCoord);
float Intensity = (temp1.x + temp1.y + temp1.z)/3;

vec4 rgb = texture2D(DiffuseMap, vTexCoord);
vec3 Colour = rgb.xyz * Intensity;
Colour += rgb.xyz * dot(Normal,-fvLightDirection);
Specular = (rgb.xyz * Specular) * dot(Normal,-fvLightDirection);



gl_FragColor = vec4((Ambient + Colour + Specular),1);
}


Vertex Shader


uniform sampler2D HeightMap;
uniform float HeightScale;
uniform vec4 EyePosition;
uniform sampler2D NormalMap;

varying vec2 vTexCoord;
varying vec3 ViewDirection;
void main(void)
{
vTexCoord = vec2(gl_MultiTexCoord0);
gl_Position = ftransform();
vec4 PositionChange = vec4(texture2D(HeightMap, vTexCoord).xyz, 0);
PositionChange.y *= HeightScale;


ViewDirection = EyePosition.xyz - (gl_ModelViewMatrix * (gl_Vertex + PositionChange)).xyz;
vec3 Normal = texture2D(NormalMap, vTexCoord).xyz;



gl_Position += (gl_ModelViewProjectionMatrix * vec4((gl_Normal * PositionChange.xyz),1));

}


Images
Rendermonkey
http://i.imgur.com/GoHvc.png (http://imgur.com/GoHvc)
OpenGL
http://i.imgur.com/aMpAG.png (http://imgur.com/aMpAG)

I find this strange as I have other simper shaders working fine with textures.

I am using a ATi 4870HD and have checked the caps to make sure I am not over the texture limit.

Since this is my first time implementing shaders, I think I may have made a mistake when using the uniforms, which may have caused it to fall back on fixed function, but for all my looking I cannot see what would cause this not to work and my other shaders to work.

Any help or advice would be greatly appreciated.

Dark Photon
01-13-2011, 04:14 PM
Well, it's probably obvious to you what's likely going on here. For some reason, your app is rendering the height map (texture unit 0) as an intensity texture rather than using it to displace the vertices.

One possibility is that your shader is not really active though you think it is. Check for GL errors, or use gDEBugger or similar.

Another possibility: let's see the code that determines m_HeightMapLoc, m_HeightMapID, and friends. Maybe you're binding the wrong textures to the wrong uniforms.

Also, these directives:

glEnable(GL_TEXTURE_2D);

are no-ops when you're using shaders (specifically a fragment shader). Change these to glDisable's. If you see any difference in the output, you're not rendering with your shader -- you're rendering with the fixed function pipeline. In any case, you should remove these. Legacy stuff for controlling the fixed function pipe.

Also, change your frag shader to always output red (1,0,0,1), or change your vertex shader to output a wildly different position -- basic kick-the-tires test to see if your shader program is properly active and being executed.

kRogue
01-14-2011, 12:29 AM
One thing that is definitely not good:



Shader->Update(Scene);
glUseProgramObjectARB(Shader->m_Program);


and within Update, uniforms are set. Since the program is not active, those functions will not affect the uniforms of Shader->m_program.

There are 2 different ways to fix it:

change the above block to:



glUseProgramObjectARB(Shader->m_Program);
Shader->Update(Scene);


or

Use glProgramUniform in Update() to directly set the values of the uniforms (these functions take as argument the name of the program as well).

Alfonse Reinheart
01-14-2011, 12:37 AM
Also, I would strongly suggest not using the ARB_shader_objects functions. Just use the core OpenGL 2.0 functions. The reason is that there were some non-trivial changes between ARB_shader_objects and core OpenGL 2.0.

TimTimTim
01-14-2011, 06:12 AM
Thank you all for the help, I am currently at work but I will try and apply these changes once I get back.

I am slightly confused to why ARB_Shader_objects are still provided (and much easier to find out about through google) if OpenGL 2.0 already had the functions built in?

Alfonse Reinheart
01-14-2011, 09:55 AM
I am slightly confused to why ARB_Shader_objects are still provided (and much easier to find out about through google) if OpenGL 2.0 already had the functions built in?

I don't know what Google searches you're using to find ARB_shader_objects, but there were at least some applications released between the time ARB_shader_objects came out and OpenGL 2.0. OpenGL implementations therefore must expose ARB_shader_objects in order to support that software.

TimTimTim
01-14-2011, 10:32 AM
The code to update textures and variables is:

virtual void Update()
{
CTerrainShader* Ter = (CTerrainShader*)Shader;

Ter->m_HeightMapID = m_Height;
Ter->m_DiffuseMapID=m_Diffuse;
Ter->m_LightMapID = m_Light;
Ter->m_NormalMapID = m_Normal;
Ter->m_SpecularMapID = m_Specular;
Ter->m_HeightScale = m_HeightScale;
}


Switching these two around:

andShader->Update(Scene);
glUseProgramObjectARB(Shader->m_Program);

and switching to 'glDisable(GL_TEXTURE_2D)' has caused it to become the same as rendermonkey except all white. So I think the vertex shader must be working ok.

I am looking into seeing if it is just my lighting that may be causing that.

Update:
It is a problem with lighting washing it out. I think the main problem has been sorted, just need to tidy the code and switch it around a bit and sort out my lighting. Thank you all

Really didnt pay attention to my lighting...