【问题标题】:OpenGL connecting a skydome and a flat ground plane连接天穹和平坦地平面的 OpenGL
【发布时间】:2014-03-31 16:14:56
【问题描述】:

我正在使用 OpenGL 和 GLUT 构建一个简单的城市,我创建了一个带纹理的天穹,现在我想将它与一个平面连接起来以呈现地平线的外观。为了给出相对大小,天穹的半径为 3.0,深度遮罩关闭,它只应用了相机旋转并位于相机上方。一座建筑物的大小约为 30.0,我从 y=500.0 向下看。

我有一个 1000x1000 的地平面,我正在使用 1024x1024 分辨率的纹理进行纹理处理,当我靠在地面上时,近距离看起来不错。我的纹理加载了纹理坐标为 1000 的 GL_REPEAT 以重复 1000 次。

将天穹与平坦的地平面连接起来是我遇到的一些问题。我将列出我尝试过的一些事情。

问题:

1) 当我旋转我的航向时,由于飞机的方形特性,我看到的边缘就像所附图片一样,而不是平坦的地平线。

2) 我尝试了一个圆形地平面,但我得到了一个曲线地平线,当我飞起来时变得更加弯曲。

3)为了避免无限天穹和我有限尺寸的平面之间的黑色间隙,我限制了我可以飞多远,并在我上升时稍微向下移动天穹,所以我不当我在高处时,看到无限天穹和我的平面之间的黑色间隙。当间隙在不同位置的大小变化时(即圆形外接正方形),是否有其他方法可以将飞机淡入天穹并处理间隙?我尝试应用地平线的雾色,但在白色的地面上出现了紫色的雾气。

4) 如果我将地面作为天穹半球的底盖,那么当我放大和缩小时看起来很奇怪,看起来带纹理的地面正在滑动并与我的建筑物断开连接。

5) 我试图通过设置 w=0 来使用消失点概念绘制无限大的平面。 Rendering infinitely large plane 地平线看起来确实很平坦,但正确地纹理化似乎很困难,所以我被单一颜色困住了。

6) 我正在禁用天穹的照明,如果我想为我的地平面启用照明,那么在某个俯仰角,我的飞机会看起来是黑色的,但我的天空仍然是完全亮的,而且看起来不自然。

7) 如果我把我的飞机变大,比如 10000x10000,那么地平线看起来会很平坦,但是,如果我按箭头键调整我的航向,地平线会在稳定之前摇晃几秒钟,什么是导致它,我该如何防止它。与此相关的一个问题,似乎平铺和纹理 1000x1000 地平面和 10000x10000 不会影响我的帧速率,这是为什么呢?更多的平铺不是意味着更多的工作吗?

8)我阅读了一些基于数学的方法来计算剪切矩形来绘制地平线,但我想知道是否有更简单的方法http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/a-super-simple-method-for-creating-infinite-sce-r2769

我读到的关于地平线的大多数帖子都会说,使用天空盒,使用天空穹顶,但我还没有遇到过关于将天空穹顶与大型地平面很好地合并的具体教程。指向这样一个教程的指针会很棒。随意通过指出数字来回答问题的任何部分,我不想分解它们,因为它们都是相关的。谢谢。

这是我设置的一些相关代码:

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());

}

【问题讨论】:

  • 关于 [2],随着高度的增加,地平线会变得越来越弯曲,这也是现实生活中发生的事情。所以也许这还不错。
  • @MattFichman,谢谢马特,是的,它看起来并不算太糟糕,除非可能在相对于圆圈大小更高的高度,然后它变得非常弯曲。但高度可能会受到限制。

标签: opengl glut


【解决方案1】:

尝试使用随机高度图而不是平面。这不仅看起来更逼真,而且由于高程的变化,它会使地平面的边缘不可见。您还可以尝试添加一些顶点雾,以模糊天空盒和地平面相交的区域。这大致就是我所做的here

很多 3D 渲染都依赖技巧来使事物看起来逼真。如果您查看大多数游戏,它们要么有一大堆遮挡地平线的前景物体,要么在远处有“山”(例如高度图),它们也遮挡了地平线。

另一个想法是将你的地平面映射到一个球体上,这样它就会像地球一样向下弯曲。这可能会使地平线看起来更像地球。这与您对圆形地平面所做的类似。

【讨论】:

  • @MattRichman,感谢您的提示。这与我所读到的类似,不同的技术来模糊视图。偶尔我会看到一些看起来无穷无尽的海洋到天空的场景,但不会有任何模糊的物体。
猜你喜欢
  • 2012-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多