java opengl libgdx glsl opengl-2.0

java - LibGDX: ¿Cómo puedo lograr un aspecto sombreado plano con OpenGL 2.0?



glsl opengl-2.0 (1)

Así que estoy tratando de lograr el estilo "Polygon Art / Low Poly" con LibGDX. Empiezo construyendo un modelo hecho de triángulos.

Luego, con el sombreador de vértices, calculo los colores de cada vértice según la altura.

El problema es que el terreno está sombreado por Gouraud cuando quiero que esté sombreado de esta manera:

Sé que con versiones superiores de OpenGL hay una palabra clave "plana" en glsl que desactivará la interpolación de colores entre vértices. Por lo que leí en línea y en esta publicación: http://i.stack.imgur.com/DrNx9.jpg , ¿creo que necesitaría que cada triángulo en el terreno estuviera separado el uno del otro? También necesitaría calcular el normal por triángulo? No pude entender el código en el otro StackOverflow, pero esto es lo que traté de hacer:

Original

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; }

Ahora:

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; }

El problema es que el nuevo código no muestra nada ... He examinado la API para ModelBuilder, MeshBuilder, Mesh y VertexAttribute / s, pero no puedo entender por qué no está funcionando. Cualquier ayuda sería genial, ya que este ha sido un día muy frustrante. ¡Muchas gracias!


El sombreado plano y liso suele estar determinado por las normales de los vértices y la forma en que se interpolan los colores en la cara.

Normalmente, en un modelo uniforme las promedios de cada vértice se promedian para cada punto frontal en la misma ubicación. Lo normal en cada ubicación de vértice compartido es el mismo para cada cara. Esto es lo que hace que la iluminación sea suave porque no hay cambios abruptos en los bordes.

En un modelo sombreado plano, las normales de los vértices no coinciden con las caras adyacentes y, en cambio, las normales de cada vértice son las mismas que las normales. Esto crea cambios abruptos en el valor normal en el borde.

Esto normalmente se puede modificar en cualquier paquete de modelado 3D que use o modificando ligeramente su código de generación normal si el terreno se genera de forma procesal.

La siguiente imagen muestra la diferencia entre las normales planas y lisas. Las líneas azules más oscuras representan las normales promedio suavizadas y las líneas más claras (cian) representan la cara dura normal.

Debería poder dibujar todos los triángulos juntos en una llamada de sorteo. No es necesario dividir la malla.