PDA

View Full Version : glFog() axis problem



Henners
07-31-2010, 07:44 PM
I'm trying to use glfog() to hide clipping points in my terrain editor.

However, because I am playing around with matrix multiplications, the glFog() seems to be working on the wrong axis.

Here is my renderFrame() method:



void RenderFrame()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);

glViewport(0, 0, g_windowWidth, g_windowHeight);
glClearColor(0.3f, 0.5f, 0.9f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(&g_camera.getProjectionMatrix()[0][0]);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(&g_camera.getViewMatrix()[0][0]);

RenderTerrain();

RenderText();
}

Here are a few screenshots to illustrate the problem:
image 1 (http://henryprescott.com/images/fog1.png)
image 2 (http://henryprescott.com/images/fog2.png)
image 3 (http://henryprescott.com/images/fog3.png)
As the camera turns to look down the Y axis, the fog takes affect. How can I fix this?

Any help would be much appreciated thank you!

ZbuffeR
08-01-2010, 12:06 AM
The camera rotation should not affect GL_PROJECTION matrix, and currently it looks that it is the case.

Henners
08-01-2010, 03:19 AM
So I should change my camera class to use gluLookAt() instead of returning a matrix?

ZbuffeR
08-01-2010, 05:45 AM
No need to, but make sure g_camera.getProjectionMatrix() returns a real projection matrix, ie. no rotation/translation.

Can you show how you currently generate g_camera.getProjectionMatrix() ?

Henners
08-01-2010, 06:50 AM
Here is the method I am using to generate the projection matrix.



void Camera::perspective(float fovx, float aspect, float znear, float zfar)
{
// Construct a projection matrix based on the horizontal field of view
// 'fovx' rather than the more traditional vertical field of view 'fovy'.

float e = 1.0f / tanf(Math::degreesToRadians(fovx) / 2.0f);
float aspectInv = 1.0f / aspect;
float fovy = 2.0f * atanf(aspectInv / e);
float xScale = 1.0f / tanf(0.5f * fovy);
float yScale = xScale / aspectInv;

m_projMatrix[0][0] = xScale;
m_projMatrix[0][1] = 0.0f;
m_projMatrix[0][2] = 0.0f;
m_projMatrix[0][3] = 0.0f;

m_projMatrix[1][0] = 0.0f;
m_projMatrix[1][1] = yScale;
m_projMatrix[1][2] = 0.0f;
m_projMatrix[1][3] = 0.0f;

m_projMatrix[2][0] = 0.0f;
m_projMatrix[2][1] = 0.0f;
m_projMatrix[2][2] = (zfar + znear) / (znear - zfar);
m_projMatrix[2][3] = -1.0f;

m_projMatrix[3][0] = 0.0f;
m_projMatrix[3][1] = 0.0f;
m_projMatrix[3][2] = (2.0f * zfar * znear) / (znear - zfar);
m_projMatrix[3][3] = 0.0f;

m_viewProjMatrix = m_viewMatrix * m_projMatrix;

m_fovx = fovx;
m_aspectRatio = aspect;
m_znear = znear;
m_zfar = zfar;
}


This is how I'm adjusting the modelview matrix.



void Camera::rotateFirstPerson(float headingDegrees, float pitchDegrees)
{
// Implements the rotation logic for the first person style and
// spectator style camera behaviors. Roll is ignored.

m_accumPitchDegrees += pitchDegrees;

if (m_accumPitchDegrees > 90.0f)
{
pitchDegrees = 90.0f - (m_accumPitchDegrees - pitchDegrees);
m_accumPitchDegrees = 90.0f;
}

if (m_accumPitchDegrees < -90.0f)
{
pitchDegrees = -90.0f - (m_accumPitchDegrees - pitchDegrees);
m_accumPitchDegrees = -90.0f;
}

Quaternion rot;

// Rotate camera about the world y axis.
// Note the order the quaternions are multiplied. That is important!
if (headingDegrees != 0.0f)
{
rot.fromAxisAngle(WORLD_YAXIS, headingDegrees);
m_orientation = rot * m_orientation;
}

// Rotate camera about its local x axis.
// Note the order the quaternions are multiplied. That is important!
if (pitchDegrees != 0.0f)
{
rot.fromAxisAngle(WORLD_XAXIS, pitchDegrees);
m_orientation = m_orientation * rot;
}
}




void Camera::updateViewMatrix()
{
// Reconstruct the view matrix.

m_viewMatrix = m_orientation.toMatrix4();

m_xAxis.set(m_viewMatrix[0][0], m_viewMatrix[1][0], m_viewMatrix[2][0]);
m_yAxis.set(m_viewMatrix[0][1], m_viewMatrix[1][1], m_viewMatrix[2][1]);
m_zAxis.set(m_viewMatrix[0][2], m_viewMatrix[1][2], m_viewMatrix[2][2]);
m_viewDir = -m_zAxis;

if (m_behavior == CAMERA_BEHAVIOR_ORBIT)
{
// Calculate the new camera position based on the current
// orientation. The camera must always maintain the same
// distance from the target. Use the current offset vector
// to determine the correct distance from the target.

m_eye = m_target + m_zAxis * m_orbitOffsetDistance;
}

m_viewMatrix[3][0] = -Vector3::dot(m_xAxis, m_eye);
m_viewMatrix[3][1] = -Vector3::dot(m_yAxis, m_eye);
m_viewMatrix[3][2] = -Vector3::dot(m_zAxis, m_eye);
}


All of this code is coming from this demo (http://www.dhpoware.com/demos/glCamera3.html).

Dark Photon
08-01-2010, 08:16 AM
float xScale = 1.0f / tanf(0.5f * fovy);
float yScale = xScale / aspectInv;

m_projMatrix[0][0] = xScale;
...
m_projMatrix[1][1] = yScale;

Haven't sifted it all, but this looks wrong. proj0,0 in the general perspective projection matrix is 2n/(r-l) (see this page (http://glprogramming.com/red/appendixf.html) at the end, Perspective Projection).

Your projection matrix computation code above obviously presumes a symmetric frustum, so r = -l. So 2n/(r-l) is the same as 2n/2r = n/r = 1/tan(0.5 * fovx). However, as you'll notice your code above uses fovy instead of fovx here. That's appears to be wrong.

Henners
08-01-2010, 09:23 AM
It also seems to use (zfar + znear) / (znear - zfar) and (2.0f * zfar * znear) / (znear - zfar) instead of using -(zfar + znear) / (znear - zfar) and (-2.0f * zfar * znear) / (znear - zfar)

Why have they chosen to do this, and what effect does it have on the model view matrix?

If I change them to the correct values it seems to stretch the scene out at the edges.

Dark Photon
08-01-2010, 09:50 AM
It also seems to use (zfar + znear) / (znear - zfar) and (2.0f * zfar * znear) / (znear - zfar) instead of using -(zfar + znear) / (znear - zfar) and (-2.0f * zfar * znear) / (znear - zfar)

No, you swapped a couple terms transcribing from the correct matrix in the book. It's -(zfar + znear) / (zfar - znear) and (-2.0f * zfar * znear) / (zfar - znear).

If you negate the numerator and denominator of these corrected expressions, I believe you get what is in his code.

Henners
08-01-2010, 10:38 AM
The problem was with my light settings, so what I thought was the black fog wasn't.

here are the fog settings I am using



glFogi(GL_FOG_MODE, GL_LINEAR);
glFogfv(GL_FOG_COLOR, fogColor);
glFogf(GL_FOG_DENSITY, 0.9f);
glHint(GL_FOG_HINT, GL_DONT_CARE);
glFogf(GL_FOG_START, 20.0f);
glFogf(GL_FOG_END, HEIGHTMAP_SIZE * HEIGHTMAP_GRID_SPACING);
glEnable(GL_FOG);


Could it be that the shaders I am using to texture the terrain is preventing the fog from working?

as shown above the following method is called from my renderFrame() method.



void RenderTerrain()
{
glUseProgram(g_terrainShader);
UpdateTerrainShaderParameters();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, g_lightDir);
......
glDisable(GL_LIGHT0);
glDisable(GL_LIGHTING);
glUseProgram(0);
}


This is also the only point where lighting is enabled.

Henners
08-01-2010, 01:15 PM
Ok so glFog doesn't work when using a shader, so I have adjusted my shader:


[vert]
uniform float tilingFactor;

varying vec4 normal;

varying float gl_FogFragCoord;

void main()
{
gl_FogFragCoord = gl_Position.z;

normal.xyz = normalize(gl_NormalMatrix * gl_Normal);
normal.w = gl_Vertex.y;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0 * tilingFactor;
}

[frag]
struct TerrainRegion
{
float min;
float max;
};

uniform TerrainRegion region1;
uniform TerrainRegion region2;
uniform TerrainRegion region3;
uniform TerrainRegion region4;
uniform TerrainRegion region5;

uniform sampler2D region1ColorMap;
uniform sampler2D region2ColorMap;
uniform sampler2D region3ColorMap;
uniform sampler2D region4ColorMap;
uniform sampler2D region5ColorMap;

varying vec4 normal;
varying float gl_FogFragCoord;

vec4 GenerateTerrainColor()
{
vec4 terrainColor = vec4(0.0, 0.0, 0.0, 1.0);
float height = normal.w;
float regionMin = 0.0;
float regionMax = 0.0;
float regionRange = 0.0;
float regionWeight = 0.0;

// Terrain region 1.
regionMin = region1.min;
regionMax = region1.max;
regionRange = regionMax - regionMin;
regionWeight = (regionRange - abs(height - regionMax)) / regionRange;
regionWeight = max(0.0, 0.5 * regionWeight);
terrainColor += regionWeight * texture2D(region1ColorMap, gl_TexCoord[0].st);

// Terrain region 2.
regionMin = region2.min;
regionMax = region2.max;
regionRange = regionMax - regionMin;
regionWeight = (regionRange - abs(height - regionMax)) / (regionRange * 2) ;
regionWeight = max(0.0,regionWeight);
terrainColor += regionWeight * texture2D(region2ColorMap, gl_TexCoord[0].st);

// Terrain region 3.
regionMin = region3.min;
regionMax = region3.max;
regionRange = regionMax - regionMin;
regionWeight = (regionRange - abs(height - regionMax)) / regionRange;
regionWeight = max(0.0, regionWeight);
terrainColor += regionWeight * texture2D(region3ColorMap, gl_TexCoord[0].st);

// Terrain region 4.
regionMin = region4.min;
regionMax = region4.max;
regionRange = regionMax - regionMin;
regionWeight = (regionRange - abs(height - regionMax)) / regionRange;
regionWeight = max(0.0, regionWeight);
terrainColor += regionWeight * texture2D(region4ColorMap, gl_TexCoord[0].st);

// Terrain region 5.
regionMin = region5.min;
regionMax = region5.max;
regionRange = regionMax - regionMin;
regionWeight = (regionRange - abs(height - regionMax)) / regionRange;
regionWeight = max(0.0, regionWeight);
terrainColor += regionWeight * texture2D(region5ColorMap, gl_TexCoord[0].st);

return terrainColor;
}

void main()
{
float fog;
vec3 n = normalize(normal.xyz);

float nDotL = max(0.0, dot(n, gl_LightSource[0].position.xyz));

vec4 ambient = gl_FrontLightProduct[0].ambient;
vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL;
vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse;

fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;

gl_FragColor = mix(gl_Fog.color, (color * GenerateTerrainColor()), fog);
}



The texture splatting is still working, but random patches are appearing each frame, can anyone point out what I am doing wrong please?