我有一组简单的2D对象,主要由两个三角形组成。
虽然对象非常简单,但每个对象都是使用模板操作绘制的
所以每个对象都需要它自己的drawTriangles()
调用。
存储和处理这些对象及其顶点和索引缓冲区的最佳方法是什么?
我可以想到几种不同的方法:
在启动时创建一个大的顶点和索引缓冲区并将每个对象添加到它,例如:
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);
}
}
除了只在需要时重新上传每个对象的顶点数据,您还可以执行与数字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);
}
}
}
您还可以创建一个新的顶点缓冲区,每个帧上只包含可见对象:
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);
}
}
另一种选择是为每个对象创建单独的顶点缓冲区:
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
似乎所有顶点都是手工转换的,并且每帧都重建并上传整个顶点缓冲区。
答案 0 :(得分:0)
无论如何,您都需要在每个帧上传数据,因为Stage3D需要知道在哪里绘制。最终通过减少绘制调用开始优化。您可以使用byteArray而不是未更改的数据以及对已更改的数据使用Vector来加速数据上载。上传向量较慢但设置向量数据较快,上传bytearray更快但设置bytearray数据较慢(因此仅用于缓存数据)。您也不需要每次都创建索引和顶点缓冲区。使用舒适的长度创建一次,只有当长度变得太小时才创建新的。所有这些都可以很好地加速一切,但仍然会减少绘制调用的速度(在25次以上的绘制调用后你应该开始看到下行)。