3

我面临一个问题,许多开发人员可能已经找到了解决方案。我有一个小项目,地板设计有小立方体(100X100)。如果我超过这个限制,我的游戏就会出现严重的减速和 Lagues!

这是我绘制地板的方式:

//Function to draw my ground ( 100 X 100 X 1)
    public void DrawGround(GameTime gameTime)
    {
        // Copy any parent transforms.
        Matrix[] transforms = new Matrix[this.model.Bones.Count];
        this.model.CopyAbsoluteBoneTransformsTo(transforms);

        //loop 1 cube high
        for (int a = 0; a < 1; a++)
        {
            //loop 100 along cube
            for (int b = 0; b < 100; b++)
            {
                //loop 100 cubic wide
                for (int c = 0; c < 100; c++)
                {
                    // Draw the model. A model can have multiple meshes, so loop.
                    foreach (ModelMesh mesh in this.model.Meshes)
                    {
                        // This is where the mesh orientation is set, as well 
                        // as our camera and projection.
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.EnableDefaultLighting();
                            effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateTranslation(this.position);
                            effect.View = this.view;
                            effect.Projection = this.projection;


                        }

                        // Draw the mesh, using the effects set above.
                        mesh.Draw();
                    }
                }
            }
        }
    }

我认为最好使用[VertexBuffer]“显卡的内存”,但我还没有找到我想做的教程......

你能给我一个在我的函数“DrawGround”中使用[VertexBuffer]的例子吗? 在此处输入图像描述 非常感谢你!

4

1 回答 1

7

tl;博士;

使用硬件实例来绘制立方体。可以选择使用View Frustum Culling以避免绘制不可见的实例。通过阅读Riemer 的教程开始使用顶点和索引缓冲区。


实例化

这个想法是,顶点和索引缓冲区绑定到设备一次,然后在一次绘制调用中绘制多次。实例是一个小数据包,仅包含模型实例的唯一信息。该实例数据被写入一个额外的顶点缓冲区,并与包含实际顶点和索引的缓冲区一起绑定到设备。

你怎么能利用它?

在您的情况下,您将具有以下设置:

  • 包含立方体网格索引的 IndexBuffer
  • 包含立方体网格顶点的 VertexBuffer
  • 第二个 VertexBuffer 包含您要绘制的所有立方体的变换
  • 考虑实例数据的特殊输入布局

由于您的立方体仅在其位置上有所不同,您甚至不必将完整的变换矩阵发送到着色器。只需发送实例位置并将其添加到顶点位置。您还可以发送其他数据,例如每个实例的颜色。

你如何实施它?

一个快速的谷歌搜索给了我很多关于xna instancing的结果,所以这应该让你开始。这里有两个看起来很有希望的随机结果:


截锥体剔除

在任何时候,场景中只有一小部分网格实际上是可见的。一个物体可能被另一个物体遮挡,或者它完全位于玩家的视野之外。在绘制它们之前移除那些不可见的网格的过程称为剔除。View Frustum Culling 解决了第二种情况:

所有不与相机体积相交的体积都是不可见的。

相机的体积是多少?正交投影具有框形式的包围体。对于透视投影,这个盒子是锥形的,一个金字塔,被近平面和远平面裁剪;因此查看截锥体

你怎么能利用它?

使用截锥体来识别当前帧中不可见的实例。仅绘制与相机的视锥体相交的那些立方体。当玩家仰望天空时,您的渲染负载可能会减少多达 100%。;-)

您可以将其与空间层次结构(四叉树八叉树)相结合,以减少平截头体相交计算的数量。

你如何实施它?

Xna 提供了一个BoundingBox Structure以及一个BoundingFrustum Class。您所要做的就是使用它们。


一个小小的缺点

结合视锥体剔除硬件实例化可能会很棘手。剔除实例意味着您还必须从实例缓冲区中删除它们 => 这意味着重新创建整个事物。也许考虑计算立方体可见性并仅每隔几帧或当相机快速移动时更新实例缓冲区。您最终如何以及在哪个扩展范围内实施这些技术取决于您并且取决于您的要求。


我刚刚意识到您想知道顶点缓冲区是如何工作的:

顶点缓冲区

在将三角形绘制到屏幕上之前,必须准备好图形设备。这包括绑定着色器、采样器、纹理,当然还有绑定几何数据。当进行绘图调用时,图形设备运行着色器并将输出写入渲染目标。

目前,您正在使用 XNA 的内置抽象,它简化了流程(并从您那里获得了所有控制权)。绑定着色器、常量、输入布局等目前都隐藏在您的 Effect 类中,而 Mesh 类负责事物的几何方面。

'mesh.Draw()' 有什么作用?

创建网格时会创建两个缓冲区,一个VertexBuffer和一个IndexBuffer。创建这个缓冲区的成本很高,所以最好只做一次。当您调用 draw 方法时,缓冲区将绑定到设备,然后进行绘图调用。正如您在代码中正确注释的那样,必须首先设置效果状态。

但您也可以创建自己的顶点和索引缓冲区:

// Instantiate the VertexBuffer
var vertexBuffer = new VertexBuffer(
    device, 
    VertexPositionColorNormal.VertexDeclaration, 
    vertices.Length, 
    BufferUsage.WriteOnly
);

// Write data to the buffer
vertexBuffer.SetData(vertices);

// Instantiate the IndexBuffer
var indexBuffer = new IndexBuffer(
    device, 
    typeof(int), 
    indices.Length,      
    BufferUsage.WriteOnly
);

// Write data to the buffer
indexBuffer.SetData(indices);

...并将它们手动绑定到设备:

device.Indices = myIndexBuffer;
device.SetVertexBuffer(myVertexBuffer);

此代码直接取自Riemer 的 XNA 教程

看看这个网站,当我第一次开始图形编程时,它真的帮了我很多。

于 2013-01-21T13:07:55.133 回答