Java libgdx中的多维数据集批处理问题

Java libgdx中的多维数据集批处理问题,java,api,3d,libgdx,batching,Java,Api,3d,Libgdx,Batching,我正试图开发一个游戏,我在屏幕上渲染多达300个立方体。当为每个多维数据集创建新的modelInstance时,modelBatch的性能非常糟糕。据我所知,没有3d批处理将所有立方体批处理到一个绘图调用。所以我拼命地想把它们分批 这个问题与这个问题直接相关: 答案是成功地批量处理了所有的立方体,但当添加环境以获得一些照明时,立方体似乎缺少了边,或者其他地方出了问题 这是一张照片: 这是我的多维数据集类(基本上是从上面的答案复制过来的) 公共类多维数据集{ 整数指数; int vertexFl

我正试图开发一个游戏,我在屏幕上渲染多达300个立方体。当为每个多维数据集创建新的modelInstance时,modelBatch的性能非常糟糕。据我所知,没有3d批处理将所有立方体批处理到一个绘图调用。所以我拼命地想把它们分批

这个问题与这个问题直接相关:

答案是成功地批量处理了所有的立方体,但当添加环境以获得一些照明时,立方体似乎缺少了边,或者其他地方出了问题

这是一张照片:

这是我的多维数据集类(基本上是从上面的答案复制过来的)

公共类多维数据集{
整数指数;
int vertexFloatSize;
int-posOffset;
int-norOffset;
布尔色;
int-colOffset;
私有向量3位置=新向量3();
私有Matrix4 rotationTransform=新Matrix4().idt();
专用颜色=新颜色();
公共浮动半宽、半高、半深;
私有布尔值=false;
私有布尔colorDirty=false;
静态最终矢量3=新矢量3();
静态最终矢量3角010=新矢量3();
静态最终矢量3角100=新矢量3();
静态最终矢量3角110=新矢量3();
静态最终矢量3 CORNER001=新矢量3();
静态最终矢量3 CORNER011=新矢量3();
静态最终矢量3 CORNER101=新矢量3();
静态最终矢量3=新矢量3();
静态最终矢量3[]面0={CORNER000,CORNER100,CORNER110,CORNER010};
静态最终矢量3[]面1={CORNER101,CORNER001,CORNER011,CORNER111};
静态最终矢量3[]面2={CORNER000,CORNER010,CORNER011,CORNER001};
静态最终矢量3[]面3={CORNER101,CORNER111,CORNER110,CORNER100};
静态最终矢量3[]面4={CORNER101,CORNER100,CORNER000,CORNER001};
静态最终矢量3[]面5={CORNER110,CORNER111,CORNER011,CORNER010};
静态最终向量3[][]面={FACE0,FACE1,FACE2,FACE3,FACE4,FACE5};
静态最终向量3 NORMAL0=新向量3();
静态最终向量3 NORMAL1=新向量3();
静态最终矢量3法线2=新矢量3();
静态最终向量3 NORMAL3=新向量3();
静态最终向量3 NORMAL4=新向量3();
静态最终向量3 NORMAL5=新向量3();
静态最终向量3[]法线={NORMAL0,NORMAL1,NORMAL2,NORMAL3,NORMAL4,NORMAL5};
浮动[]网格顶点;
公共多维数据集(浮点x、浮点y、浮点z、浮点宽度、浮点高度、浮点深度、整数索引、,
顶点属性顶点属性,浮点[]网格顶点){
位置设置(x,y,z);
此值为0.halfWidth=宽度/2;
这一点。半高=高度/2;
此值为0.halfDepth=深度/2;
这个指数=指数;
this.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字节
posOffset=getVertexAttribute(用法.Position,VertexAttribute).offset/4;
norOffset=getVertexAttribute(Usage.Normal,vertexAttribute).offset/4;
VertexAttribute colorAttribute=getVertexAttribute(用法.Color,VertexAttribute);
hasColor=colorAttribute!=null;
如果(hasColor){
colOffset=colorAttribute.offset/4;
这个.setColor(Color.WHITE);
}
transformDirty=true;
}
公共空心集合尺寸(浮动x、浮动y、浮动z){
这个半宽度=x/2;
这个半高=y/2;
这个半深=z/2;
}
公共void集合索引(int索引){
这个指数=指数;
transformDirty=true;
colorDirty=true;
}
/**
*移动和/或旋转后调用此选项。
*/
公共无效更新(){
if(colorDirty&&hasColor){

对于(int faceIndex=0;faceIndex,我发现了几个问题:

  • 已禁用混合和/或着色器未设置alpha值

  • 你不是在剔除背面

  • 因此,在创建新材质时,不要仅使用
    新材质()
    ,而要使用:

    new Material(
        IntAttribute.createCullFace(GL20.GL_FRONT),//For some reason, libgdx ModelBuilder makes boxes with faces wound in reverse, so cull FRONT
        new BlendingAttribute(1f), //opaque since multiplied by vertex color
        new DepthTestAttribute(false), //don't want depth mask or rear cubes might not show through
        ColorAttribute.createDiffuse(Color.WHITE) //white since multiplied by vertex color
        );
    
    您还需要按距离摄影机的距离对立方体进行排序,以使其Alpha正确分层。这是一个支持排序的更新立方体类。它必须能够独立于顶点数组跟踪颜色,以防其索引更改:

    public class Cube implements Comparable<Cube>{
    
        private int index;
        int vertexFloatSize;
        int posOffset;
        int norOffset;
        boolean hasColor;
        int colOffset;
        private Vector3 position = new Vector3();
        private Matrix4 rotationTransform = new Matrix4().idt();
        public float halfWidth, halfHeight, halfDepth;
        private boolean transformDirty = false;
        private boolean colorDirty = false;
        private Color color = new Color();
        float camDistSquared;
    
        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};
    
        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;
    
    
        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, meshVertices);
        }
        transformDirty = true;
        }
    
        public void updateCameraDistance(Camera cam){
        camDistSquared = cam.position.dst2(position);
        }
    
        /**
         * Call this after moving and/or rotating.
         */
        public void update(float[] meshVertices){
    
        if (transformDirty){
            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;
            }
            }
        }
    
        if (colorDirty){
            colorDirty = false;
    
            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;
            }
            }
        }
        }
    
        public Cube setColor(Color color, float[] meshVertices){
        if (hasColor){
            this.color.set(color);
            colorDirty = true;
    
        }
        return this;
        }
    
        public void setIndex(int index){
        if (this.index != index){
            transformDirty = true;
            colorDirty = true;
            this.index = index;
        }
        }
    
        public Cube translate(float x, float y, float z){
        position.add(x,y,z);
        transformDirty = true;
        return this;
        }
    
        public Cube translateTo(float x, float y, float z){
        position.set(x,y,z);
        transformDirty = true;
        return this;
        }
    
        public Cube rotate(float axisX, float axisY, float axisZ, float degrees){
        rotationTransform.rotate(axisX, axisY, axisZ, degrees);
        transformDirty = true;
        return this;
        }
    
        public Cube rotateTo(float axisX, float axisY, float axisZ, float degrees){
        rotationTransform.idt();
        rotationTransform.rotate(axisX, axisY, axisZ, degrees);
        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;
        }
    
        @Override
        public int compareTo(Cube other) {
        //the cube has a lower index than a cube that is closer to the camera
        if (camDistSquared>other.camDistSquared)
            return -1;
        return camDistSquared<other.camDistSquared ? 1 : 0;
        }
    }
    

    非常感谢你的回答。情况好多了。不过我注意到了另一个问题。我更新了我的问题。你能看一看吗?在接受你的回答之前,你想让我再加一笔赏金吗?假设地板应该是透明的,你需要将它排序到立方体的中间。因为它有不同的尺寸,我需要为地板上方和下方的立方体制作单独的模型可能是最简单的。然后按从远到近的顺序提交三个模型。但是如果你的地板不透明,那么你只需要在绘制透明材料之前绘制它。透明材料的问题是,你永远不能依赖深度测试……你必须绘制所有这些都是从远到近的。不能回到中间插入一些东西。如果地板与多个立方体相交,你可能需要把它分解成六个单独的矩形,然后把立方体层分解成更多的模型,这样你就可以按顺序适当地画出它们。让我们暂时忘记透明度。eo是完全不透明的。它们按照你所说的方式对每一帧进行排序。如果我对深度测试的理解至少有一点正确,我认为没有进行深度测试。在视频中,一些立方体应该穿过大平面的一半。你看不到发生这种情况,它们要么被完全画在大平面的前面,要么在大平面的中间根本没有绘制。我给你的这条线:
    newdepthTestAttribute(false)
    关闭深度测试。如果绘制透明立方体,你必须关闭深度测试。啊,完全错过了。Fina
    new Material(
        IntAttribute.createCullFace(GL20.GL_FRONT),//For some reason, libgdx ModelBuilder makes boxes with faces wound in reverse, so cull FRONT
        new BlendingAttribute(1f), //opaque since multiplied by vertex color
        new DepthTestAttribute(false), //don't want depth mask or rear cubes might not show through
        ColorAttribute.createDiffuse(Color.WHITE) //white since multiplied by vertex color
        );
    
    public class Cube implements Comparable<Cube>{
    
        private int index;
        int vertexFloatSize;
        int posOffset;
        int norOffset;
        boolean hasColor;
        int colOffset;
        private Vector3 position = new Vector3();
        private Matrix4 rotationTransform = new Matrix4().idt();
        public float halfWidth, halfHeight, halfDepth;
        private boolean transformDirty = false;
        private boolean colorDirty = false;
        private Color color = new Color();
        float camDistSquared;
    
        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};
    
        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;
    
    
        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, meshVertices);
        }
        transformDirty = true;
        }
    
        public void updateCameraDistance(Camera cam){
        camDistSquared = cam.position.dst2(position);
        }
    
        /**
         * Call this after moving and/or rotating.
         */
        public void update(float[] meshVertices){
    
        if (transformDirty){
            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;
            }
            }
        }
    
        if (colorDirty){
            colorDirty = false;
    
            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;
            }
            }
        }
        }
    
        public Cube setColor(Color color, float[] meshVertices){
        if (hasColor){
            this.color.set(color);
            colorDirty = true;
    
        }
        return this;
        }
    
        public void setIndex(int index){
        if (this.index != index){
            transformDirty = true;
            colorDirty = true;
            this.index = index;
        }
        }
    
        public Cube translate(float x, float y, float z){
        position.add(x,y,z);
        transformDirty = true;
        return this;
        }
    
        public Cube translateTo(float x, float y, float z){
        position.set(x,y,z);
        transformDirty = true;
        return this;
        }
    
        public Cube rotate(float axisX, float axisY, float axisZ, float degrees){
        rotationTransform.rotate(axisX, axisY, axisZ, degrees);
        transformDirty = true;
        return this;
        }
    
        public Cube rotateTo(float axisX, float axisY, float axisZ, float degrees){
        rotationTransform.idt();
        rotationTransform.rotate(axisX, axisY, axisZ, degrees);
        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;
        }
    
        @Override
        public int compareTo(Cube other) {
        //the cube has a lower index than a cube that is closer to the camera
        if (camDistSquared>other.camDistSquared)
            return -1;
        return camDistSquared<other.camDistSquared ? 1 : 0;
        }
    }
    
    for (Cube cube : mBatchedCubes){
        cube.updateCameraDistance(camera);
    }
    mBatchedCubes.sort();
    int index = 0;
    for (Cube cube : mBatchedCubes){
        cube.setIndex(index++);
    }