Я пытаюсь разработать игру, в которой я отображаю до 300 кубов на экране. Производительность modelBatch при создании нового экземпляра модели для каждого куба ужасна. Насколько я знаю, не существует 3D-пакета, который объединяет все кубы в один вызов отрисовки. Поэтому я отчаянно пытаюсь их как-то объединить.
Этот вопрос напрямую связан с этим: LibGDX 3D увеличивает производительность
Опубликованный ответ успешно объединяет все кубы, но когда добавляется среда, чтобы получить некоторое освещение, кажется, что у кубов отсутствуют стороны или что-то еще с ними не так.
Вот картинка:
Вот мой класс куба (в значительной степени скопированный из ответа выше)
public class Cube {
int index;
int vertexFloatSize;
int posOffset;
int norOffset;
boolean hasColor;
int colOffset;
private Vector3 position = new Vector3();
private Matrix4 rotationTransform = new Matrix4().idt();
private Color color = new Color();
public float halfWidth, halfHeight, halfDepth;
private boolean transformDirty = false;
private boolean colorDirty = false;
static final Vector3 CORNER000 = new Vector3();
static final Vector3 CORNER010 = new Vector3();
static final Vector3 CORNER100 = new Vector3();
static final Vector3 CORNER110 = new Vector3();
static final Vector3 CORNER001 = new Vector3();
static final Vector3 CORNER011 = new Vector3();
static final Vector3 CORNER101 = new Vector3();
static final Vector3 CORNER111 = new Vector3();
static final Vector3[] FACE0 = {CORNER000, CORNER100, CORNER110, CORNER010};
static final Vector3[] FACE1 = {CORNER101, CORNER001, CORNER011, CORNER111};
static final Vector3[] FACE2 = {CORNER000, CORNER010, CORNER011, CORNER001};
static final Vector3[] FACE3 = {CORNER101, CORNER111, CORNER110, CORNER100};
static final Vector3[] FACE4 = {CORNER101, CORNER100, CORNER000, CORNER001};
static final Vector3[] FACE5 = {CORNER110, CORNER111, CORNER011, CORNER010};
static final Vector3[][] FACES = {FACE0, FACE1, FACE2, FACE3, FACE4, FACE5};
static final Vector3 NORMAL0 = new Vector3();
static final Vector3 NORMAL1 = new Vector3();
static final Vector3 NORMAL2 = new Vector3();
static final Vector3 NORMAL3 = new Vector3();
static final Vector3 NORMAL4 = new Vector3();
static final Vector3 NORMAL5 = new Vector3();
static final Vector3[] NORMALS = {NORMAL0, NORMAL1, NORMAL2, NORMAL3, NORMAL4, NORMAL5};
float[] meshVertices;
public Cube(float x, float y, float z, float width, float height, float depth, int index,
VertexAttributes vertexAttributes, float[] meshVertices){
position.set(x,y,z);
this.halfWidth = width/2;
this.halfHeight = height/2;
this.halfDepth = depth/2;
this.index = index;
this.meshVertices = meshVertices;
NORMAL0.set(0,0,-1);
NORMAL1.set(0,0,1);
NORMAL2.set(-1,0,0);
NORMAL3.set(1,0,0);
NORMAL4.set(0,-1,0);
NORMAL5.set(0,1,0);
vertexFloatSize = vertexAttributes.vertexSize/4; //4 bytes per float
posOffset = getVertexAttribute(Usage.Position, vertexAttributes).offset/4;
norOffset = getVertexAttribute(Usage.Normal, vertexAttributes).offset/4;
VertexAttribute colorAttribute = getVertexAttribute(Usage.Color, vertexAttributes);
hasColor = colorAttribute!=null;
if (hasColor){
colOffset = colorAttribute.offset/4;
this.setColor(Color.WHITE);
}
transformDirty = true;
}
public void setDimensions(float x, float y , float z){
this.halfWidth = x/2;
this.halfHeight = y/2;
this.halfDepth = z/2;
}
public void setIndex(int index){
this.index = index;
transformDirty = true;
colorDirty = true;
}
/**
* Call this after moving and/or rotating.
*/
public void update(){
if (colorDirty && hasColor){
for (int faceIndex= 0; faceIndex<6; faceIndex++){
int baseVertexIndex = (index*24 + faceIndex*4)*vertexFloatSize;//24 unique vertices per cube, 4 unique vertices per face
for (int cornerIndex=0; cornerIndex<4; cornerIndex++){
int vertexIndex = baseVertexIndex + cornerIndex*vertexFloatSize + colOffset;
meshVertices[vertexIndex] = color.r;
meshVertices[++vertexIndex] = color.g;
meshVertices[++vertexIndex] = color.b;
meshVertices[++vertexIndex] = color.a;
}
}
colorDirty = false;
}
if (!transformDirty){
return;
}
transformDirty = false;
CORNER000.set(-halfWidth,-halfHeight,-halfDepth).rot(rotationTransform).add(position);
CORNER010.set(-halfWidth,halfHeight,-halfDepth).rot(rotationTransform).add(position);
CORNER100.set(halfWidth,-halfHeight,-halfDepth).rot(rotationTransform).add(position);
CORNER110.set(halfWidth,halfHeight,-halfDepth).rot(rotationTransform).add(position);
CORNER001.set(-halfWidth,-halfHeight,halfDepth).rot(rotationTransform).add(position);
CORNER011.set(-halfWidth,halfHeight,halfDepth).rot(rotationTransform).add(position);
CORNER101.set(halfWidth,-halfHeight,halfDepth).rot(rotationTransform).add(position);
CORNER111.set(halfWidth,halfHeight,halfDepth).rot(rotationTransform).add(position);
NORMAL0.set(0,0,-1).rot(rotationTransform);
NORMAL1.set(0,0,1).rot(rotationTransform);
NORMAL2.set(-1,0,0).rot(rotationTransform);
NORMAL3.set(1,0,0).rot(rotationTransform);
NORMAL4.set(0,-1,0).rot(rotationTransform);
NORMAL5.set(0,1,0).rot(rotationTransform);
for (int faceIndex= 0; faceIndex<6; faceIndex++){
int baseVertexIndex = (index*24 + faceIndex*4)*vertexFloatSize;//24 unique vertices per cube, 4 unique vertices per face
for (int cornerIndex=0; cornerIndex<4; cornerIndex++){
int vertexIndex = baseVertexIndex + cornerIndex*vertexFloatSize + posOffset;
meshVertices[vertexIndex] = FACES[faceIndex][cornerIndex].x;
meshVertices[++vertexIndex] = FACES[faceIndex][cornerIndex].y;
meshVertices[++vertexIndex] = FACES[faceIndex][cornerIndex].z;
vertexIndex = baseVertexIndex + cornerIndex*vertexFloatSize + norOffset;
meshVertices[vertexIndex] = NORMALS[faceIndex].x;
meshVertices[++vertexIndex] = NORMALS[faceIndex].y;
meshVertices[++vertexIndex] = NORMALS[faceIndex].z;
}
}
}
public Cube setColor(Color color){
if (hasColor){
this.color.set(color);
colorDirty = true;
}
return this;
}
public void setAlpha(float alpha) {
if (hasColor){
this.color.set(this.color.r, this.color.g, this.color.b, alpha);
colorDirty = true;
}
}
public Cube translate(float x, float y, float z){
position.add(x,y,z);
transformDirty = true;
return this;
}
public Cube setPosition(float x, float y, float z){
position.set(x,y,z);
transformDirty = true;
return this;
}
public Cube setPosition(Vector3 position1) {
position.set(position1);
transformDirty = true;
return this;
}
public VertexAttribute getVertexAttribute (int usage, VertexAttributes attributes) {
int len = attributes.size();
for (int i = 0; i < len; i++)
if (attributes.get(i).usage == usage) return attributes.get(i);
return null;
}
public Vector3 getPosition() {
return this.position;
}
}
А вот тестовый пример, который я создал для проверки кубов.
public class TestCase {
ModelInstance mBatchedCubesModelInstance;
Mesh mBatchedCubesMesh;
float[] mBatchedCubesVertices;
Array<Cube> mBatchedCubes;
TestCase(){
int width = 5;
int height = 5;
int length = 5;
int numCubes = width*height*length;
ModelBuilder mb = new ModelBuilder();
mb.begin();
MeshPartBuilder mpb = mb.part("cubes", GL20.GL_TRIANGLES, (Usage.Position | Usage.Normal | Usage.Color), new Material());
for (int i=0; i<numCubes; i++){
mpb.box(1, 1, 1);
}
Model model = mb.end();
mBatchedCubesModelInstance = new ModelInstance(model);
mBatchedCubesMesh = model.meshes.get(0);
VertexAttributes vertexAttributes = mBatchedCubesMesh.getVertexAttributes();
int vertexFloatSize = vertexAttributes .vertexSize / 4; //4 bytes per float
mBatchedCubesVertices = new float[numCubes * 24 * vertexFloatSize]; //24 unique vertices per cube
mBatchedCubesMesh.getVertices(mBatchedCubesVertices);
mBatchedCubes = new Array<Cube>(numCubes);
int cubeNum = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
mBatchedCubes.add(new Cube((x-(width/2f))*1.5f, -((y-(height/2f)) * 1.5f), -(z-(length/2f))*1.5f, 1,1,1, cubeNum++, vertexAttributes, mBatchedCubesVertices ).setColor(Colors.getMixedColor()));
}
}
}
}
public void render(ModelBatch batch, Environment environment){
for (Cube cube : mBatchedCubes){ //must update any changed cubes.
cube.update();
}
mBatchedCubesMesh.setVertices(mBatchedCubesVertices); //apply changes to mesh
if(environment!=null) batch.render(mBatchedCubesModelInstance,environment);
else batch.render(this.mBatchedCubesModelInstance);
}
}
Кубики даже не двигаются в моей игре, поэтому мне даже не нужна трансформация. Мне просто нужно установить цвета (включая альфа-канал) для каждого кадра. Пакетная сетка также должна работать с теневым отображением libgdx (надеюсь, она автоматически работает, когда у вас правильно пакетная модельInstance).
Может ли кто-нибудь сказать мне, что не так с моим кодом и почему некоторые лица не отображаются. Я понимаю, что могу многого попросить, поэтому я назначу награду за этот вопрос (50 баллов) через два дня.
EDIT: После ответа от Tenfour04 все стало намного лучше. Альфа-канал работает, проблема со странными лицами исчезла. Однако, когда я применил изменения к своей реальной игре, я заметил, что иногда мука рисуется поверх игрового ландшафта. Я обновил тест, чтобы проиллюстрировать проблему, добавив большую плоскость посередине кубов. Сделал видео: https://www.youtube.com/watch?v=LQhSMJfuyZY.
Я также хотел бы уточнить, что я не использую какой-либо пользовательский шейдер. Использование только методов ModelBatch.begin() и .end() без дополнительных вызовов openGl.
new DepthTestAttribute(false)
отключает тестирование глубины. Вы должны отключить его, если рисуете прозрачные кубы. - person Tenfour04   schedule 16.07.2014