【问题标题】:Problems with generated mesh/model using normals and texture, libgdx 3d api使用法线和纹理生成的网格/模型的问题,libgdx 3d api
【发布时间】:2014-04-28 13:14:13
【问题描述】:

一段时间以来,我一直在弄清楚为什么我无法从高度图图像生成带有法线的纹理网格。我正在使用 TerrainTest (http://libgdx.googlecode.com/svn/trunk/tests/gdx-tests/src/com/badlogic/gdx/tests/TerrainTest.java) 代码,并且只添加了用于生成法线和 tex 坐标的代码:

private void calcNormals(short[] indices, float[] verts) {

      Vector3 point1=new Vector3(), point2=new Vector3(), point3=new Vector3();

       for (int i = 0; i < indices.length; i += 3) {
           int i1 = getPositionStart(indices[i + 0]);
           int i2 = getPositionStart(indices[i + 1]);
           int i3 = getPositionStart(indices[i + 2]);

           point1.set(verts[i1 + 0], verts[i1 + 1], verts[i1 + 2]);
           point2.set(verts[i2 + 0], verts[i2 + 1], verts[i2 + 2]);
           point3.set(verts[i3 + 0], verts[i3 + 1], verts[i3 + 2]);

           Vector3 v1 = new Vector3().set(point2).sub(point1);
            Vector3 v2 = new Vector3().set(point3).sub(point1);
            Vector3 nor = v1.crs(v2).nor();

           addNormal(indices[i + 0], verts, nor.x, nor.y, nor.z);
           addNormal(indices[i + 1], verts, nor.x, nor.y, nor.z);
           addNormal(indices[i + 2], verts, nor.x, nor.y, nor.z);
       }

   }

我在修改后的 buildVertices() 方法中添加的纹理坐标:

public void buildVertices() {
    int heightPitch = height + 1;
    int widthPitch = width + 1;

    int idx = 0;
    int hIdx = 0;

    Gdx.app.log("DBG","height map size="+heightMap.length);
    for (int z = 0; z < heightPitch; z++) {
        for (int x = 0; x < widthPitch; x++) {

            // POSITION
            vertices[idx++] = x;
            vertices[idx++] = heightMap[hIdx++] * strength;
            vertices[idx++] = z;

            // NORMAL, skip these for now
            idx += 3;

            // COLOR
            vertices[idx++] = Color.WHITE.toFloatBits();

            // TEXTURE
            vertices[idx++] = (x / (float) width);
            vertices[idx++] = (z / (float) height);

        }
    }
}

这是我在 TerrainTest.TerrainChunk 类中更改的唯一代码。

然后我创建一个网格:

 int vertexSize = 3 + 3 + 1 + 2;
  TerrainChunk chunk = new TerrainChunk(4, 4, vertexSize, "textures/heightmap.png", 10);
            groundMesh = new Mesh(true, chunk.vertices.length / 3, chunk.indices.length, 
        new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE), 
        new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE),
        new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE), 
        new VertexAttribute(Usage.TextureCoordinates, 2,  ShaderProgram.TEXCOORD_ATTRIBUTE));

  groundMesh.setVertices(chunk.vertices);
  groundMesh.setIndices(chunk.indices);

之后,我只从 Mesh 创建一个 btBvhTriangleMeshShape 和一个模型:

Material material = new Material(ColorAttribute.createDiffuse(Color.WHITE), ColorAttribute.createSpecular(Color.WHITE),
        FloatAttribute.createShininess(16f));

  Model result = new Model();

  int chunkNum = 0;
  MeshPart meshPart = new MeshPart();
  meshPart.id = "terrainChunk" + chunkNum;
  meshPart.indexOffset = 0;
  meshPart.numVertices = groundMesh.getNumIndices();
  meshPart.primitiveType = GL20.GL_TRIANGLES;
  meshPart.mesh = groundMesh;

  btTriangleIndexVertexArray bttiva = new btTriangleIndexVertexArray(meshPart);
  btBvhTriangleMeshShape heightFieldShape = new btBvhTriangleMeshShape(bttiva, true);

  NodePart nodePart = new NodePart();
  nodePart.material = material;
  nodePart.meshPart = meshPart;

  Node node = new Node();
  node.id = "terrainNode" + chunkNum;
  node.parts.add(nodePart);

  result.meshes.add(groundMesh);
  result.materials.add(material);
  result.nodes.add(node);
  result.meshParts.add(meshPart);
  result.manageDisposable(groundMesh);

我使用 DebugDrawModes.DBG_DrawNormals | 渲染 Mesh 和 btShape DebugDrawModes.DBG_DrawWireframe 所以我可以看到 btShape 的线和法线。

无论我做什么,网格和刚体的法线都指向下方 (-y),并且网格的纹理在其底部以均匀的颜色(如纹理的平均颜色)绘制。奇怪的是,无论我是否更改法线计算(即使用 -normal.y 而不是 +normal.y),debugdraw 的法线都不会改变!并且网格只能从下面看到。我已经打印了 groundMesh.getVertices() 中的所有数据,一切对我来说似乎都是正确的。下面是为每个顶点打印的 9 个组件(2x2 TerrainChunk 用于测试):

DBG: Vertex: 0.0,9.803922,0.0,0.07673953,0.9784201,0.19184695,-1.7014117E38,0.0,0.0
DBG: Vertex: 1.0,9.725491,0.0,0.15213917,0.96989024,0.19017535,-1.7014117E38,0.5,0.0
DBG: Vertex: 2.0,9.6470585,0.0,0.07541871,0.96157986,0.26396275,-1.7014117E38,1.0,0.0
DBG: Vertex: 0.0,9.607843,1.0,0.11272618,0.9581794,0.2630302,-1.7014117E38,0.0,0.5
DBG: Vertex: 1.0,9.529411,1.0,0.21905276,0.93097335,0.29206917,-1.7014117E38,0.5,0.5
DBG: Vertex: 2.0,9.372549,1.0,0.14450188,0.9212023,0.36125556,-1.7014117E38,1.0,0.5
DBG: Vertex: 0.0,9.333333,2.0,0.11272618,0.9581794,0.2630302,-1.7014117E38,0.0,1.0
DBG: Vertex: 1.0,9.215687,2.0,0.21905276,0.93097335,0.29206917,-1.7014117E38,0.5,1.0
DBG: Vertex: 2.0,8.980392,2.0,0.21905276,0.93097335,0.29206917,-1.7014117E38,1.0,1.0

法线(索引 3,4 和 5)都指向上方!但是 debugdraw 的法线指向下方,并且网格只能从下方看到。

如果我改变法线的计算方式,使其产生一些其他值,我可以在打印顶点的内容时看到这一点得到确认,但调试绘图和网格保持不变..这怎么可能,它完全就像网格忽略正常值。

【问题讨论】:

    标签: opengl 3d libgdx rendering mesh


    【解决方案1】:

    问题

    这似乎是渲染管道中某个地方的问题。背面剔除的法线似乎不是由提供的法线决定的,而是由三角形的缠绕决定的(由顶点顺序引起)。

    解决方法

    对此的解决方法是,在构建网格时更改您提供索引的顺序。

    例如,在 LibGDX TerrainTest(您的代码基于该测试)中,索引是在 buildIndices 方法中创建的:

    indices[idx++] = i1;
    indices[idx++] = i2;
    indices[idx++] = i3;
    
    indices[idx++] = i3;
    indices[idx++] = i4;
    indices[idx++] = i1;
    

    像这样更改每个三角形的最后两个索引的顺序:

    indices[idx++] = i1;
    indices[idx++] = i3; //i3 is exchanged
    indices[idx++] = i2; //with i2
    
    indices[idx++] = i3;
    indices[idx++] = i1; //i1 is exchanged
    indices[idx++] = i4; //with i4
    

    这将改变三角形的“缠绕”,它现在应该可以正确地为您呈现。

    解决方案

    解决方案是在 LibGDX bugtracker 中提交一个错误,以便他们修复它,因为我认为这不是预期的行为。

    (PS:我希望这还不算太晚,但由于这让我很头疼,我想也许它可以帮助一些人。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-14
      • 2019-12-20
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 2019-11-12
      • 2022-11-05
      • 1970-01-01
      相关资源
      最近更新 更多