我认为OpenGL(我使用的是OpenGL 4.0)支持顶点缓冲对象,这是(纠正我,如果我错了)一个动态的方式来绘制顶点,绑定它们类似于纹理绑定时,你可以释放一个动态的像素数组绑定到一个纹理,你仍然能够绘制它,即使在数组中的像素数据丢失。我尝试着创造一款迷你的《我的世界》,但是在绘制了256x256x60的世界(游戏邦注:即256个宽度和高度以及60个方块深度)后,游戏便彻底陷入了困境。我试着只画256x256x6,但它仍然没有快,例如,Minecraft运行。我用下面的方法画了a块:
void DrawBlock(double x, double y, double z, float xx, float yy, float zz)
{
// Render a color-cube consisting of 6 quads with different colors
xx = xx / 2;
yy = yy / 2;
zz = zz / 2;
x -= xx;
y -= yy;
z -= zz;
glBegin(GL_QUADS); // Begin drawing the color cube with 6 quads
// Top face (y = z + zz)
// Define vertices in counter-clockwise (CCW) order with normal pointing out
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex3f(x + xx, y + yy, z - zz);
glVertex3f(x - xx, y + yy, z - zz);
glVertex3f(x - xx, y + yy, z + zz);
glVertex3f(x + xx, y + yy, z + zz);
// Bottom face (y = z - zz)
glColor3f(1.0f, 0.5f, 0.0f); // Orange
glVertex3f(x + xx, y - yy, z + zz);
glVertex3f(x - xx, y - yy, z + zz);
glVertex3f(x - xx, y - yy, z - zz);
glVertex3f(x + xx, y - yy, z - zz);
// Front face (z = z + zz)
glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex3f(x + xx, y + yy, z + zz);
glVertex3f(x - xx, y + yy, z + zz);
glVertex3f(x - xx, y - yy, z + zz);
glVertex3f(x + xx, y - yy, z + zz);
// Back face (z = z - zz)
glColor3f(1.0f, 1.0f, 0.0f); // Yellow
glVertex3f(x + xx, y - yy, z - zz);
glVertex3f(x - xx, y - yy, z - zz);
glVertex3f(x - xx, y + yy, z - zz);
glVertex3f(x + xx, y + yy, z - zz);
// Left face (x = z - zz)
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex3f(x - xx, y + yy, z + zz);
glVertex3f(x - xx, y + yy, z - zz);
glVertex3f(x - xx, y - yy, z - zz);
glVertex3f(x - xx, y - yy, z + zz);
// Right face (x = z + zz)
glColor3f(1.0f, 0.0f, 1.0f); // Magenta
glVertex3f(x + xx, y + yy, z - zz);
glVertex3f(x + xx, y + yy, z + zz);
glVertex3f(x + xx, y - yy, z + zz);
glVertex3f(x + xx, y - yy, z - zz);
glEnd(); // End of drawing color-cube
}
,当x, y和z数据在一个名为"Block"的结构数组中时。除了画画,我什么也没做,只是因为画画总是卡住,显示函数每次运行时总是调用DrawBlock()
256x256x6或256x256x60次。我如何使用VBO动态地做到这一点?我在网上查了一下,但出现了一些未定义的函数,比如glGenBuffersARB()
等等。有一个简单立方体的示例代码吗?
如果您正在绘制256x256x6块而没有任何优化,如果您使用上述方式,您将进行393216绘制调用。
Minecraft是使用块加载和渲染。你应该加载一个数据块并渲染一个数据块,只需要一个draw调用。意味着一个顶点缓冲对象保存一个块。这可以通过大量的优化来实现。我也尝试过类似的东西,使用一次渲染调用,在一个64*64*256块的块上获得了近600 FPS。
我已经从硬盘中加载了块,每个块存储一个比特(0如果不活动,1如果活动),然后我处理了块,跳过了不活动的块,以及所有不可见的块(块的所有侧面都被其他块覆盖)。下一个优化是只渲染可见的一面。假设有一个block (2D)
x
xB
x
B是你的块,x是当前块周围的其他块。所以不需要创建所有4条边(8个三角形- 24个角- 72个浮点数),只需要创建右侧(2个三角形- 6个角- 18个浮点数)。我将浮点数附加到缓冲区(向量或其他动态数据结构)。现在将此数据结构的内容上传到VBO,然后立即呈现整个块。还有很多改进,但你只需要减少"网格"/"块"中的顶点数量。
如果你使用更多的块,你也可以添加很多其他的优化,不要渲染不可见或空块。
之后,你可以看看"延迟着色"。这可以提高你的帧率。使用延迟着色,你只对玩家可见的部分进行着色。不可见的方块(Minecraft中的隧道或被山覆盖的方块)不会被遮蔽。
我推荐阅读这个:https://sites.google.com/site/letsmakeavoxelengine/它还没有完成,但基本的解释和作者展示了一些代码,以及一些更多的细节。
我还建议深入研究一下VertexBufferObjects和现代OpenGL。(如果你想使用旧的OpenGL,请查看"display lists")
如果没有"显示列表"或"VBO",每次调用渲染时三角形都会一次又一次地复制到GPU -这是非常慢的。因此,使用VBO复制它们一次,然后告诉OpenGL:这是列表,它已经在设备上,只需渲染它!