2

I am building a simple city with OpenGL and GLUT, I created a textured skydome and now I would like to connect that with a flat plane to give an appearance of the horizon. To give relative size, the skydome is 3.0 in radius with depth mask turned off, and it only has the camera rotation applied and sits over the camera. A building is about 30.0 in size, and I am looking at it from y=500.0 down.

I have a ground plane that is 1000x1000, I am texturing with a 1024x1024 resolution texture that looks good up close when I am against the ground. My texture is loaded with GL_REPEAT with texture coordinate of 1000 to repeat it 1000 times.

Connecting the skydome with the flat ground plane is where I am having some issues. I will list a number of things I have tried.

Issues:

1) When I rotate my heading, because of the square nature of the plane, I see edge like the attached picture instead of a flat horizon.

Horizon not flat

2) I have tried a circular ground plane instead, but I get a curve horizon, that becomes more curvy when I fly up.

Horizon curved

3) To avoid the black gap between the infinite skydome, and my limited size flat plane, I set a limit on how far up I can fly, and shift the skydome slightly down as I go up, so I don't see the black gap between the infinite skydome and my flat plane when I am up high. Are there other methods to fade the plane into the skydome and take care of the gap when the gap varies in size at different location (ie. Circle circumscribing a square)? I tried to apply a fog color of the horizon, but I get a purple haze over white ground.

4) If I attached the ground as the bottom lid of the skydome hemisphere, then it looks weird when I zoom in and out, it looks like the textured ground is sliding and disconnected with my building.

5) I have tried to draw the infinitely large plane using the vanishing point concept by setting w=0. Rendering infinitely large plane The horizon does look flat, but texturing properly seems difficult, so I am stuck with a single color.

6) I am disable lighting for the skydome, if I want to enable lighting for my ground plane, then at certain pitch angle, my plane would look black, but my sky is still completely lit, and it looks unnatural.

7) If I make my plane larger, like 10000x10000, then the horizon will look seemingly flat, but, if I press the arrow key to adjust my heading, the horizon will shake for a couple of seconds before stabilizing, what is causing it, and how could I prevent it. A related question to this, it seems like tiling and texturing 1000x1000 ground plane and 10000x10000 does not affect my frame rate, why is that? Wouldn't more tiling mean more work?

8) I read some math-based approach with figuring out the clipping rectangle to draw the horizon, but I wonder if there are simpler approaches http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/a-super-simple-method-for-creating-infinite-sce-r2769

Most threads I read regarding horizon would say, use a skybox, use a skydome, but I haven't come across a specific tutorial that talks about merging skydome with a large ground plane nicely. A pointer to such a tutorial would be great. Feel free to answer any parts of the question by indicating the number, I didn't want to break them up because they are all related. Thanks.

Here is some relevant code on my setup:

void Display()
    {        

        // Clear frame buffer and depth buffer
        glClearColor (0.0,0.0,0.0,1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);     

        glLoadIdentity();
        camera.Update();

        GLfloat accumulated_camera_rotation_matrix[16];
        GetAccumulatedRotationMatrix(accumulated_camera_rotation_matrix);

        SkyDome_Draw(accumulated_camera_rotation_matrix);

        FlatGroundPlane_Draw();     

        // draw buildings

        // swap buffers when GLUT_DOUBLE double buffering is enabled
        glutSwapBuffers();

    }

    void SkyDome_Draw(GLfloat (&accumulated_camera_rotation_matrix)[16])
    {
        glPushMatrix();
        glLoadIdentity();
        glDepthMask(GL_FALSE);
        glDisable(GL_LIGHTING);     

        glMultMatrixf(accumulated_camera_rotation_matrix);

        // 3.0f is the radius of the skydome        
        // If we offset by 0.5f in camera.ground_plane_y_offset, we can offset by another 1.5f 
        // at skydome_sky_celing_y_offset of 500.  500 is our max allowable altitude
        glTranslatef( 0, -camera.ground_plane_y_offset - camera.GetCameraPosition().y /c amera.skydome_sky_celing_y_offset/1.5f, 0);

        skyDome->Draw();                
        glEnable(GL_LIGHTING);
        glDepthMask(GL_TRUE);       
        glEnable(GL_CULL_FACE);
        glPopMatrix();
    }

    void GetAccumulatedRotationMatrix(GLfloat (&accumulated_rotation_matrix)[16])
    {
        glGetFloatv(GL_MODELVIEW_MATRIX, accumulated_rotation_matrix);
        // zero out translation is in elements m12, m13, m14
        accumulated_rotation_matrix[12] = 0;
        accumulated_rotation_matrix[13] = 0;
        accumulated_rotation_matrix[14] = 0;
    }

    GLfloat GROUND_PLANE_WIDTH = 1000.0f;

    void FlatGroundPlane_Draw(void) 
    {   

        glEnable(GL_TEXTURE_2D);            
        glBindTexture( GL_TEXTURE_2D, concreteTextureId); 
        glBegin(GL_QUADS);  


        glNormal3f(0, 1, 0);

        glTexCoord2d(0, 0);


        // repeat 1000 times for a plane 1000 times in width
        GLfloat textCoord = GROUND_PLANE_WIDTH;

        glVertex3f( -GROUND_PLANE_WIDTH, 0, -GROUND_PLANE_WIDTH);

        // go beyond 1 for texture coordinate so it repeats
        glTexCoord2d(0, textCoord);

        glVertex3f( -GROUND_PLANE_WIDTH, 0, GROUND_PLANE_WIDTH);

        glTexCoord2d(textCoord, textCoord);
        glVertex3f( GROUND_PLANE_WIDTH, 0, GROUND_PLANE_WIDTH);

        glTexCoord2d(textCoord, 0);
        glVertex3f( GROUND_PLANE_WIDTH, 0, -GROUND_PLANE_WIDTH);

        glEnd();

        glDisable(GL_TEXTURE_2D);
    }

    Void Init()
    {
        concreteTextureId = modelParser->LoadTiledTextureFromFile(concreteTexturePath);
    }

    ModelParser::LoadTiledTextureFromFile(string texturePath)
    {
        RGBImage image; // wrapping 2-d array of data
        image.LoadData(texturePath);
        GLuint texture_id;
        UploadTiledTexture(texture_id, image);
        image.ReleaseData();
        return texture_id;
    }


    void ModelParser::UploadTiledTexture(unsigned int &iTexture, const RGBImage &img)
    {
        glGenTextures(1, &iTexture); // create the texture
        glBindTexture(GL_TEXTURE_2D, iTexture);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        // the texture would wrap over at the edges (repeat)
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, img.Width(), img.Height(), GL_RGB, GL_UNSIGNED_BYTE, img.Data());

}
Community
  • 1
  • 1
frank
  • 1,283
  • 1
  • 19
  • 39
  • Regarding [2], the horizon getting curvier as you increase in altitude is what happens in real life as well. So perhaps that isn't so bad. – Matt Fichman Mar 31 '14 at 20:09
  • @MattFichman, thanks Matt, yeah it doesn't look too bad, except maybe at higher altitudes relative to the circle size, then it becomes quite curved. But the altitude could be limited. – frank Apr 02 '14 at 18:19

1 Answers1

1

Try using a randomized heightmap rather than using a flat plane. Not only will this look more realistic, it will make the edge of the ground plane invisible due to the changes in elevation. You can also try adding in some vertex fog, to blur the area where the skybox and ground plane meet. That's roughly what I did here.

A lot of 3D rendering relies on tricks to make things look realistic. If you look at most games, they have either a whole bunch of foreground objects that obscure the horizon, or they have "mountains" in the distance (a la heightmaps) that also obscure the horizon.

Another idea is to map your ground plane onto a sphere, so that it curves down like the earth does. That might make the horizon look more earthlike. This is similar to what you did with the circular ground plane.

Matt Fichman
  • 5,458
  • 4
  • 39
  • 59
  • @MattRichman, thanks for the tips. That is similar to what I have read, different techniques to obscure the view. Occasionally I will see some ocean to sky scene that appears infinite, and there would not be any obscuring objects though. – frank Apr 02 '14 at 18:30