Advertisement Jump to content
Sign in to follow this  
Raptisoft

OpenGL Uniform fog across scene

This topic is 1879 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all,

 

I'm porting some DirectX code over to OpenGL in the hopes of discarding DirectX forever.

 

So far so good, except for fog.  When I render fog, I am getting uniform fog all across my display.  Now, I had some fog problems in DirectX that were a result of my projection matrix.  I was able to fix that by making the matrix "fog compatible" (basically dividing certain matrix elements by matrix[3][2]), but the same fix doesn't work in OpenGL. 

 

I'm doing a couple funny things here-- for instance, I'm combining the view and projection matrix into one so that I can use WORLDVIEW to position meshes.  I'm sure this is the problem, but I can't seem to get even to the point where I can begin to diagnose.

 

I know part of the problem is, in attempting to keep some compatibility, I'm combining what was, in DirectX, the View+Projection matrix in GL to make it the projection matrix, so that I can use ModelView exclusively to position meshes.  That works for drawing, but seems to be screwing up the fog.

 

To display fog, I'm doing this (note that GetZDepth returns the distance to my far clip plane):

    theStart=GetZDepth()*.5f;
    theEnd=GetZDepth();
   
    
    glEnable(GL_FOG);                   // Enables GL_FOG
    glFogi(GL_FOG_MODE,GL_LINEAR);        // Fog Mode
    glFogfv(GL_FOG_COLOR,aFogColor);      // Set Fog Color
    glFogf(GL_FOG_DENSITY, .33f);              // How Dense Will The Fog Be
    glHint(GL_FOG_HINT, GL_NICEST);          // Fog Hint Value
    glFogf(GL_FOG_START, theStart);             // Fog Start Depth
    glFogf(GL_FOG_END, theEnd);               // Fog End Depth

In setting up my matrixes, I am doing this:

    //
    // World matrix
    //
    float aWorldMatrix[4][4];
    float aViewMatrix[4][4];
    IDENTITYMATRIX(aWorldMatrix);
    
    SCALEMATRIX(aWorldMatrix,1,1,-1);
    
    theCameraZ = -theCameraZ;
    theLookatZ = -theLookatZ;
    theUpVectorZ = -theUpVectorZ;
    
    // We translate the world the opposite direction of the camera (relatively speakng, of course)
    TRANSLATEMATRIX(aWorldMatrix,-theCameraX, -theCameraY, -theCameraZ);
    
    //
    // Look-at matrix vectors
    //
    float aLookatVectorX = theLookatX-theCameraX;
    float aLookatVectorY = theLookatY-theCameraY;
    float aLookatVectorZ = theLookatZ-theCameraZ;
    
    // Side vector (UP cross LOOKAT)
    float aSideVectorX = theUpVectorY * aLookatVectorZ - theUpVectorZ * aLookatVectorY;
    float aSideVectorY = theUpVectorZ * aLookatVectorX - theUpVectorX * aLookatVectorZ;
    float aSideVectorZ = theUpVectorX * aLookatVectorY - theUpVectorY * aLookatVectorX;
    
    // Correct the UP vector (LOOKAT cross SIDE)
    theUpVectorX = aLookatVectorY * aSideVectorZ - aLookatVectorZ * aSideVectorY;
    theUpVectorY = aLookatVectorZ * aSideVectorX - aLookatVectorX * aSideVectorZ;
    theUpVectorZ = aLookatVectorX * aSideVectorY - aLookatVectorY * aSideVectorX;
    
    // Normalize the lookat vector
    float len = (float)sqrt(aLookatVectorX*aLookatVectorX + aLookatVectorY*aLookatVectorY + aLookatVectorZ*aLookatVectorZ);
    aLookatVectorX /= len;
    aLookatVectorY /= len;
    aLookatVectorZ /= len;
    
    // Normalize side vector
    len = (float)sqrt(aSideVectorX*aSideVectorX + aSideVectorY*aSideVectorY + aSideVectorZ*aSideVectorZ);
    aSideVectorX /= len;
    aSideVectorY /= len;
    aSideVectorZ /= len;
    
    // Normalize the up vector
    len = (float)sqrt(theUpVectorX*theUpVectorX + theUpVectorY*theUpVectorY + theUpVectorZ*theUpVectorZ);
    theUpVectorX /= len;
    theUpVectorY /= len;
    theUpVectorZ /= len;
    
    //
    // The view matrix (look-at)
    //
    
    aViewMatrix[0][0]=-aSideVectorX;
    aViewMatrix[1][0]=-aSideVectorY;
    aViewMatrix[2][0]=-aSideVectorZ;
    aViewMatrix[3][0]=0;
    
    aViewMatrix[0][1]=-theUpVectorX;
    aViewMatrix[1][1]=-theUpVectorY;
    aViewMatrix[2][1]=-theUpVectorZ;
    aViewMatrix[3][1]=0;
    
    aViewMatrix[0][2]=aLookatVectorX;
    aViewMatrix[1][2]=aLookatVectorY;
    aViewMatrix[2][2]=aLookatVectorZ;
    aViewMatrix[3][2]=0;
    
    aViewMatrix[0][3]=0;
    aViewMatrix[1][3]=0;
    aViewMatrix[2][3]=0;
    aViewMatrix[3][3]=1;
    
    // Combine the world and view (GL doesn't support View matrices)
    MULTIPLYMATRIX(aWorldMatrix,aViewMatrix);
    
    //
    // Perspective projection matrix (as per Blinn)
    //
    
    float aAspect = (float)gPageWidth/(float)gPageHeight;
    float aNear = gZNear;
    float aFar = GetZDepth();
    
    float aWidth = COS(theFOV / 2.0f);
    float aHeight = COS(theFOV / 2.0f);
    if (aAspect > 1.0)
    {
        aWidth /= aAspect;
    }
    else
    {
        aHeight *= aAspect;
    }
    float s  = SIN(theFOV / 2.0f);
    float d  = 1.0f - aNear/aFar;
    
    
    float aMatrix[4][4];
    aMatrix[0][0]=aWidth;
    aMatrix[1][0]=0;
    aMatrix[2][0]=0;
    aMatrix[3][0]=0;
    aMatrix[0][1]=0;
    aMatrix[1][1]=aHeight;
    aMatrix[2][1]=0;
    aMatrix[3][1]=0;
    aMatrix[0][2]=0;
    aMatrix[1][2]=0;
    aMatrix[2][2]=s/d;
    aMatrix[3][2]=-(s * aNear / d);
    aMatrix[0][3]=0;
    aMatrix[1][3]=0;
    aMatrix[2][3]=s;
    aMatrix[3][3]=0;
    
    //
    // The next two lines combine the matrix to make modelview usable
    //
    MULTIPLYMATRIX(aWorldMatrix,aMatrix);

//
// In DirectX, I used this to make my matrix "fog compatible."  However, in DirectX, I wasn't combining all these matrixes
// willy nill because DirectX has World/View/Projection and GL has ModelView/Projection ...
//
/*
    aMatrix[2][3]/=s;
    aMatrix[3][2]/=s;
    aMatrix[0][0]/=s;
    aMatrix[1][1]/=s;
    aMatrix[2][2]/=s;
*/

    SetProjectionMatrix(2,&aWorldMatrix);
 

I would greatly appreciate any assistance.  I am pretty sure the problem is not in the GL parameters, but in my matrix setup (as I said, I had similar problems in DirectX until I made the matrix "fog compatible"), but I'm not savvy enough to break down what I'm doing wrong here.

 

Thanks in advance!

Share this post


Link to post
Share on other sites
Advertisement

In my old-OpenGL code I set the fog up the same way as you and it works for me.

 

You can set the projection matrix separately with

gluPerspective( perspective_angle_vertical, aspect_ratio, NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE);

 

You dont have to combine that with the modelview.

 

Edit:

Thats just a stupid guess, but maybe OpenGL internally uses only the modelview matrix to calculate the fog(which you seem to leave at the identity, you just set up the Projection matrix.) So in the default shader it calculates the vertex coords in camera/eye space by P_cam = modelViewMatrix * P. Then uses the length( P_cam) to determine the fog level, and then translates the points to clip space by P_clip = projectionMatrix * P_cam.

 

It would be weird if it would try to figure out the fog level of a vertex from the projected coordinates.

Edited by Aliii

Share this post


Link to post
Share on other sites

Just confirming what Aliii said; OpenGL calculates the fog in eye space, so after the modelview matrix but before the projection matrix. You cannot combine the two into one matrix.

Share this post


Link to post
Share on other sites

Thanks for the responses, guys.  I was combining view into projection because on the directX end, I'd set my camera in the view matrix, then move meshes around using the world matrix.  I was trying to find a way to do it in OpenGL that wouldn't force me to basically set the camera every time I place a mesh.

 

So what's the right way to do this...?  Take my "world" matrix, multiply it by "view," and then set that as ModelView?  I'll probably keep my camera matrix seperate, and then just multiply the "actual" modelview matrix every time I move a model.  Does that sound like a viable solution?

Share this post


Link to post
Share on other sites

Thanks for the responses, guys.  I was combining view into projection because on the directX end, I'd set my camera in the view matrix, then move meshes around using the world matrix.  I was trying to find a way to do it in OpenGL that wouldn't force me to basically set the camera every time I place a mesh.

 

So what's the right way to do this...?  Take my "world" matrix, multiply it by "view," and then set that as ModelView?  I'll probably keep my camera matrix seperate, and then just multiply the "actual" modelview matrix every time I move a model.  Does that sound like a viable solution?

 

You can do this:

glLoadIdentity();

apply the view transformation: glRotate/glTranslate

For( every model){

    glPushMatrix();
    apply the model transformation: glTranslate/glRotate
    model.draw();
    glPopMatrix();
}

I dont think theres a need for a separate "world matrix". LoadIdentity gives you that, ....just not the left-handed DirectX matrix.

If you dont want to change the proj matrix every frame then just set it once. If you use multiple proj matrices in a frame the push-pop functions work for that too.(just switch to GL_PROJECTION with glMatrixMode())

If you want proper control of the matrices(or want to do something odd) use the modern openGL instead.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!