等距平铺地图滚动



我这里有一个问题。我寻找这个问题的答案已经有一段时间了,试图自己解决,但没有结果。这个问题可能被问过很多次了,但无论我在哪里找到关于它的东西,总有一些东西我不清楚。所以:我正在使用SDL+OpenGL编写一款2D游戏。游戏以等距视角呈现。玩家看到的地图是由一个贴图组成的,假设是一个15x15的贴图(2D数组)。它是这样的:https://i.stack.imgur.com/sOxcP.png

X和Y是每个贴图的索引,但除此之外,这些贴图有自己的X和Y坐标(北顶点,用绿点标记[0][0]贴图),它们被绘制在其中。

我的问题是,我想为这个添加滚动。如果这张地图是100 × 100个贴图,那么它的绘制速度就会很慢,因为所有的贴图都是在屏幕外绘制的。我不想这样做。

让我们看一下,例如,在这个:https://i.stack.imgur.com/cPb7V.jpg

蓝色矩形是我的屏幕(800x600,不可调整大小)。整个地图的尺寸是8000x6000,贴图是在屏幕上绘制的。我知道,我只需要画那些标记为绿色的瓷砖,但我的问题是:

我如何确定哪些瓷砖(我的意思是,哪些索引)必须绘制?

我感谢所有试图帮助我的人。

但是不管我用什么技术,它只是…

为什么不呢?屏幕外的整个三角形被剔除,所以你损失的只是顶点转移和转换时间。是的,你应该采取合理的步骤来确保你没有发送你可以轻易剔除的内容,但因为你只是在绘制一个简单的2D平铺图,所以这不会成为性能问题。即使是低端硬件。

这就是为什么过早优化是错误的。因为你把时间花在担心一些根本不是问题的事情上。

一般来说,您应该选择要绘制的贴图组。如果一个是可见的,就画出所有的。这样,你就不用花很多时间选择要画哪些贴图了。然后,您可以优化传输数据(即:将每个组放入缓冲对象中),并一次绘制整个组。

我在回答我自己的问题,因为我不能发布超过2个链接(因为我是新人),而且我不能发布任何图像。

我做了一些测试:

在100x100的情况下运行得很好,在150x150的情况下也运行得很好,在200x200的情况下它会掉到地上,而在500x500的情况下它完全是灾难:http://imgur.com/msAx4l&EJ9Qw&iKXFZ&ybFt0(图库中的4个屏幕)

嗯,我在想一个不需要任何检验的解决方案,只需要一些数学方程。例如,在我的另一款游戏(很久以前写的)中,使用方形而不是菱形贴图,所以很容易确定绘制贴图的索引。它是这样的:https://i.stack.imgur.com/bD12V.png

画图程序:

//CameraXposition and CameraYposition is position of left-top corner of camera on map.
//Single tile height and width is 100, so if CameraXposition is 1456, then I start drawing from
//tile with index of 14 ((int)(1456/100) == 14).
//CAMERA_WIDTH is 800 and CAMERA_HEIGHT is 600 (screen resolution).
for(int x = (int)CameraXposition/100; x < ((CameraXposition+CAMERA_WIDTH)/100); ++x)
{
    for(int y = (int)CameraYposition/100; y < ((CameraYposition+CAMERA_HEIGHT)/100); y++)
    {
        //Draw(tiles[x][y]);
    }
}

这里,在等距视图中,它不是那么简单,但我不知道如何确定这个起始索引和tile的范围。

这是我当前的绘图代码:

void GraphicEngine::Render(Map &m)
{
    //camX and camY isn't coordinates of camera, they are coordinates of
    //starting point (everything is drawed according to that point)
    //it changes as I move mouse.
    //zoomFactor is basically a zoom variable, it's float and its minimum is 0.5 and maximum is 1.5.
    //It changes as I scroll my mousewheel. The smaller it is, the smaller is everything that's drawed,
    //so more tiles can be drawed on screen (becouse they are smaller) 
    //Not very good, but works.
    glTranslatef(camX*zoomFactor, camY*zoomFactor, 0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glBegin(GL_QUADS);
        for(int i = 0; i < m.get_width(); ++i)
        {
            for(int j = m.get_height()-1; j>=0; --j)
            {
                glTexCoord2f(0, 0);
                glVertex3f((m.get_fields()[i][j]->get_pX()-30)*zoomFactor, (m.get_fields()[i][j]->get_pY()+15)*zoomFactor, 0);
                glTexCoord2f(1, 0);
                glVertex3f((m.get_fields()[i][j]->get_pX())*zoomFactor, (m.get_fields()[i][j]->get_pY())*zoomFactor, 0);
                glTexCoord2f(1, 1);
                glVertex3f((m.get_fields()[i][j]->get_pX()+30)*zoomFactor, (m.get_fields()[i][j]->get_pY()+15)*zoomFactor, 0);
                glTexCoord2f(0, 1);
                glVertex3f((m.get_fields()[i][j]->get_pX())*zoomFactor,( m.get_fields()[i][j]->get_pY()+30)*zoomFactor, 0);
            }
        }
    glEnd();
    glLoadIdentity();
}

我会在渲染所有贴图和检查每个贴图之间选择一个折衷的解决方案。

在屏幕坐标中找到角块。这将为您提供可视瓷砖的最小和最大X:Y位置。现在只渲染这些范围内的贴图。GPU将剪辑看不见的贴图,但你不需要发送所有的8000x6000贴图来渲染,而只需要发送其中的一部分。

如上所述,过早优化是错误的,所以除非你的地图至少是800x600块,否则我会尝试先在其他地方搜索瓶颈。例如,按纹理将瓷砖批处理到显示列表或VBO中似乎是一个更好的主意。

最新更新