У меня есть массив простых 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
Кажется, что все вершины предварительно трансформируются вручную, и весь буфер вершин перестраивается и загружается каждый кадр.