4

我有一组简单的二维对象,主要由两个三角形组成。尽管对象非常简单,但每个对象都是使用模板操作绘制的,因此每个对象都需要自己drawTriangles()调用。

存储和处理这些对象及其顶点和索引缓冲区的最佳方法是什么?

我可以想到几种不同的方法:

  1. 在启动时创建一个大的顶点和索引缓冲区并将每个对象添加到其中,例如:

    public function initialize():void{
        for each(object in objectList){
            vertexData.push(object.vertices);
            indexData.push(triangle1, triangle2);
        }
    
        indices  = context3D.createIndexBuffer( numTriangles * 3 );
        vertices = context3D.createVertexBuffer( numVertices, dataPerVertex );
        indices.uploadFromVector( indexData, 0, numIndices );
        vertices.uploadFromVector( vertexData, 0, numVertices );
    }
    

    在所有对象的渲染循环期间,检查哪些对象在屏幕上可见并更新它们的顶点。然后重新上传整个顶点缓冲区。然后循环遍历可见对象并使用单独调用绘制每个对象的三角形drawTriangles()

    public function onRender():void{
        for each(object in objectList){
            if(object.visibleOnScreen)
                object.updateVertexData();
        }
    
        vertices.uploadFromVector( vertexData, 0, numVertices );
    
        for each(object in objectsOnScreen){
            drawTriangles(indices, object.vertexDataOffset, object.numTriangles);
        }
    }
    
  2. 除了仅在需要时重新上传每个对象的顶点数据之外,您还可以执行类似于数字 1 的操作:

    public function onRender():void{
        for each(object in objectList){
            if(object.visibleOnScreen){
                if(object.hasChanged)
                    vertices.uploadFromVector( vertexData, object.vertexDataOffset, object.numTriangles );
                drawTriangles(indices, object.vertexDataOffset, object.numTriangles);
            }
        }
    }
    
  3. 您还可以创建一个新的顶点缓冲区,该缓冲区仅包含每帧上的可见对象:

    public function onRender():void{
        for each(object in objectList){
            if(object.visibleOnScreen){
                vertexData.push(object.vertices);
                indexData.push(triangle1, triangle2);
            }
        }
    
        indices  = context3D.createIndexBuffer( numTriangles * 3 );
        vertices = context3D.createVertexBuffer( numVertices, dataPerVertex );
        indices.uploadFromVector( indexData, 0, numIndices );
        vertices.uploadFromVector( vertexData, 0, numVertices );
    
        for each(object in objectsOnScreen){
            drawTriangles(indices, object.vertexDataOffset, object.numTriangles);
        }
    }
    
  4. 另一种选择是为每个对象创建单独的顶点缓冲区:

    public function initialize():void{
        for each(object in objectList){
            object.indices  = context3D.createIndexBuffer( object.numTriangles * 3 );
            object.vertices = context3D.createVertexBuffer( object.numVertices, dataPerVertex );
        }
    }
    
    public function onRender():void{
        for each(object in objectList){
            if(object.visibleOnScreen){
                if(object.hasChanged)
                    object.vertices.uploadFromVector( object.vertexData, 0, object.numTriangles );
                drawTriangles(indices, 0, object.numTriangles);
            }
        }
    }
    

我可以想象选项 1 会很慢,因为每个帧都需要上传整个顶点缓冲区。
选项 2 的优点是它只需要上传已更改但可能会遭受多次调用的顶点数据uploadFromVector

更新

我看过 Starling 框架源代码,特别是QuadBatch类: http:
//gamua.com/starling/
https://github.com/PrimaryFeather/Starling-Framework

似乎所有顶点都是事先手动转换的,并且每帧都会重建和上传整个顶点缓冲区。

4

1 回答 1

0

无论如何,您都需要在每一帧上上传数据,因为 Stage3D 需要知道在哪里绘制什么。最终优化从减少绘图调用开始。您可以通过对未更改的数据使用 byteArray 而不是对已更改的数据使用 Vector 来加速数据的上传。上传向量较慢但设置向量数据较快,上传字节数组较快但设置字节数组数据较慢(因此仅用于缓存数据)。您也不需要每次都创建索引和顶点缓冲区。以舒适的长度创建它们一次,仅当长度变得太小时才创建新的。所有这一切都应该很好地加速一切,但绘制调用的数量仍然会减慢一切(在 25 次以上的绘制调用之后,你应该开始看到不利的一面)。

于 2014-06-26T17:38:28.010 回答