2015-10-13 50 views
3

所以我试图用LibGDX实现“Polygon Art/Low Poly”风格。我首先构建一个由三角形组成的模型。LibGDX:如何用OpenGL 2.0实现平坦的阴影效果?

1

然后与顶点着色器,我计算用于基于高度每个顶点的颜色。

2

问题是,地势体着色时,我希望它是平面着色这样的:

3

我知道,与更高版本的OpenGL有一个“平” glsl中的关键字将禁用顶点之间的颜色插值。从我在线阅读和在这篇文章中看到:http://i.stack.imgur.com/DrNx9.jpg,我认为我需要让地形中的每个三角形彼此分开?我还需要计算每个三角形的正常值?我无法理解在其他StackOverflow的代码,但是这是我试图做的:

原始

public Model getWorld(){ 
    returnWorld = new Model(); 
    modelBuilder = new ModelBuilder(); 
    modelBuilder.begin(); 
    worldMeshBuilder = modelBuilder.part("worldPart", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material()); 
    pieceMeshBuilder = new MeshBuilder(); 
    meshPiece = new Mesh(false, 3, 3, 
      new VertexAttribute(Usage.Position, 3, "a_position"), 
      new VertexAttribute(Usage.Normal, 3, "a_normal"), 
      new VertexAttribute(Usage.ColorPacked, 4, "a_color")); 
    Vector3 vectorCopy = new Vector3(); 
    for(int i = 0; i < world.length - 1; i++){ 
     for(int j = 0; j < world[0].length - 1; j++){ 
      if((i + j) % 2 == 0){ 
       pieceMeshBuilder.begin(Usage.Position | Usage.Normal, renderType); 
       pieceMeshBuilder.triangle(
        vectorCopy = verticies[i][j], 
        vectorCopy = verticies[i][j + 1], 
        vectorCopy = verticies[i + 1][j + 1] 
       ); 
       worldMeshBuilder.addMesh(pieceMeshBuilder.end()); 
       pieceMeshBuilder.begin(Usage.Position | Usage.Normal, renderType); 
       pieceMeshBuilder.triangle(
         vectorCopy = verticies[i + 1][j + 1], 
         vectorCopy = verticies[i + 1][j], 
         vectorCopy = verticies[i][j] 
       ); 
       worldMeshBuilder.addMesh(pieceMeshBuilder.end()); 
      } else { 
       pieceMeshBuilder.begin(Usage.Position | Usage.Normal, renderType); 
       pieceMeshBuilder.triangle(
        vectorCopy = verticies[i][j], 
        vectorCopy = verticies[i][j + 1], 
        vectorCopy = verticies[i + 1][j] 
       ); 
       worldMeshBuilder.addMesh(pieceMeshBuilder.end()); 
       pieceMeshBuilder.begin(Usage.Position | Usage.Normal, renderType); 
       pieceMeshBuilder.triangle(
         vectorCopy = verticies[i + 1][j + 1], 
         vectorCopy = verticies[i + 1][j], 
         vectorCopy = verticies[i][j + 1] 
       ); 
       worldMeshBuilder.addMesh(pieceMeshBuilder.end()); 
      } 
     } 
    } 
    returnWorld = modelBuilder.end(); 
    return returnWorld; 
} 

现在:

public Model getWorld(){ 
    returnWorld = new Model(); 
    modelBuilder = new ModelBuilder(); 
    modelBuilder.begin(); 
    worldMeshBuilder = modelBuilder.part("worldPart", GL20.GL_LINES, Usage.Position | Usage.Normal, new Material()); 

    for(int i = 0; i < world.length - 1; i++){ 
     for(int j = 0; j < world[0].length - 1; j++){ 

      Vector3 normal1 = calcNormal(verticies[i][j], verticies[i + 1][j], verticies[i + 1][j + 1]); 
      Vector3 normal2 = calcNormal(verticies[i][j], verticies[i + 1][j + 1], verticies[i][j + 1]); 

      if((i + j) % 2 == 0){ 
       meshPiece = new Mesh(false, 18, 3, 
         new VertexAttribute(Usage.Position, 3, "a_position"), 
         new VertexAttribute(Usage.Normal, 3, "a_normal")//, 
         //new VertexAttribute(Usage.ColorPacked, 4, "a_color") 
         ); 
       worldMeshBuilder.addMesh(meshPiece.setVertices(new float[] { 
         verticies[i][j].x, verticies[i][j].y, verticies[i][j].z, normal1.x, normal1.y, normal1.z, 
         verticies[i + 1][j].x, verticies[i + 1][j].y, verticies[i + 1][j].z, normal1.x, normal1.y, normal1.z, 
         verticies[i + 1][j + 1].x, verticies[i + 1][j + 1].y, verticies[i + 1][j + 1].z, normal1.x, normal1.y, normal1.z, 
        })); 
       meshPiece = new Mesh(false, 18, 3, 
         new VertexAttribute(Usage.Position, 3, "a_position"), 
         new VertexAttribute(Usage.Normal, 3, "a_normal")//, 
         //new VertexAttribute(Usage.ColorPacked, 4, "a_color") 
         ); 
       worldMeshBuilder.addMesh(meshPiece.setVertices(new float[] { 
         verticies[i][j].x, verticies[i][j].y, verticies[i][j].z, normal2.x, normal2.y, normal2.z, 
         verticies[i + 1][j + 1].x, verticies[i + 1][j + 1].y, verticies[i + 1][j + 1].z, normal2.x, normal2.y, normal2.z, 
         verticies[i][j + 1].x, verticies[i][j + 1].y, verticies[i][j + 1].z, normal2.x, normal2.y, normal2.z, 
        })); 
      } else { 
       meshPiece = new Mesh(false, 18, 3, 
         new VertexAttribute(Usage.Position, 3, "a_position"), 
         new VertexAttribute(Usage.Normal, 3, "a_normal")//, 
         //new VertexAttribute(Usage.ColorPacked, 4, "a_color") 
         ); 
       worldMeshBuilder.addMesh(meshPiece.setVertices(new float[] { 
         verticies[i][j].x, verticies[i][j].y, verticies[i][j].z, normal1.x, normal1.y, normal1.z, 
         verticies[i + 1][j].x, verticies[i + 1][j].y, verticies[i + 1][j].z, normal1.x, normal1.y, normal1.z, 
         verticies[i][j + 1].x, verticies[i][j + 1].y, verticies[i][j + 1].z, normal1.x, normal1.y, normal1.z, 
        })); 
       meshPiece = new Mesh(false, 18, 3, 
         new VertexAttribute(Usage.Position, 3, "a_position"), 
         new VertexAttribute(Usage.Normal, 3, "a_normal")//, 
         //new VertexAttribute(Usage.ColorPacked, 4, "a_color") 
         ); 
       worldMeshBuilder.addMesh(meshPiece.setVertices(new float[] { 
         verticies[i + 1][j].x, verticies[i + 1][j].y, verticies[i + 1][j].z, normal2.x, normal2.y, normal2.z, 
         verticies[i + 1][j + 1].x, verticies[i + 1][j + 1].y, verticies[i + 1][j + 1].z, normal2.x, normal2.y, normal2.z, 
         verticies[i][j + 1].x, verticies[i][j + 1].y, verticies[i][j + 1].z, normal2.x, normal2.y, normal2.z, 
        })); 
      } 
     } 
    } 
    returnWorld = modelBuilder.end(); 
    return returnWorld; 
} 

问题是新的代码不渲染任何东西......我已经看过模型构建器,MeshBuilder,Mesh和VertexAttribute/s的API,但我无法弄清楚它为什么不起作用。任何帮助都会很棒,因为这是非常令人沮丧的一天。非常感谢!

+0

看一看https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/g3d/HeightMapTest.java它使用https://开头github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/g3d/HeightField.java,看起来像是你想要做的事情(它有(布尔)选项平滑或平坦) – Xoppa

+0

好的非常感谢。我看了一下这些例子,但是需要一些时间来剖析它们。如果我有任何问题,你可以回答他们吗? – JahrudZ

回答

5

平整和平滑的底纹通常由顶点法线和颜色如何插入整个脸部来确定。

通常在光滑模型中,每个顶点的法线在相同位置的每个脸点进行平均。每个共享顶点位置的法线对于每个面都是相同的。这是使照明平滑的原因,因为边缘没有突然的变化。

在平坦阴影模型中,顶点法线不匹配相邻面,而是每个顶点法线与面法线相同。这会在边缘处产生正常值的突然变化。

这通常可以在您使用的任何3D建模软件包中进行修改,或者在程序生成地形时稍微修改正常代代码。

下图显示了平滑和平滑法线之间的差异。较深的蓝线代表平滑的法线,较浅的(青色)线代表粗糙的脸法线。

vertex vs faces

您应该能够给所有的三角形画放在一个绘制调用。你不需要分割网格。

+1

如果每个顶点的法线都需要与面的法线匹配,那么多个面共享的顶点如何与它们共享一个法线?感谢您的快速回复:) – JahrudZ

+2

@JahrudZ这是一个很好的问题,你是对的。如果您使用glDrawElements样式的数据结构,那么它将被组织为共享顶点数据,并且您无法在每个顶点指定唯一的法线,但是使用此模型,您也无法指定大多数3D模型通常需要的唯一UV坐标。您可以改为为每个面复制顶点数据和正常数据,并使用glDrawArrays进行绘制。如果这没有意义,我可以详细阐述。 –

+0

@JahrudZ在你的例子中,它看起来像你已经在使用非索引的glDrawArrays风格的数据结构,所以你应该只能修改CalcNormal函数。 –