2015-10-13 4 views
3

Итак, я пытаюсь достичь стиля Polygon Art/Low Poly с помощью LibGDX. Я начинаю с построения модели из треугольников.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; 
} 

Проблема новый код не что-то ... Я посмотрел API для ModelBuilder, MeshBuilder, Mesh и VertexAttribute/s, но я не могу понять, почему он не работает. Любая помощь была бы замечательной, поскольку это был очень неприятный день. Большое спасибо!

+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, который выглядит так, как вы пытаетесь сделать (у него есть (boolean), чтобы быть гладким или плоским) – Xoppa

+0

Хорошо, спасибо большое.Я взглянул на эти примеры, но мне понадобится время, чтобы их разобрать. Если у меня возникнут вопросы, можете ли вы ответить на них? – JahrudZ

ответ

5

Плоское и гладкое затенение обычно определяется по нормалям вершин и тому, как цвета интерполируются по лицу.

Обычно в гладкой модели нормали в каждой вершине усредняются для каждой граничной точки в одном и том же месте. Нормальный для каждого общего расположения вершин одинаковый для каждого лица. Это то, что делает освещение гладким, потому что нет резких изменений на краях.

В плоских заштрихованных нормалях вершин модели не совпадают смежные грани, и вместо этого каждая нормали вершин совпадают с нормалями лица. Это создает резкие изменения в нормальном значении на краю.

Обычно это может быть изменено в любом пакете 3D-моделирования, который вы используете, или путем изменения вашего нормального кода генерации, если рельеф создается процедурно.

На следующем рисунке показана разница между плоскими и гладкими нормалями. Более темные синие линии представляют собой средние сглаженные нормали, а более светлые (голубые) линии представляют суровое физическое лицо.

vertex vs faces

Вы должны быть в состоянии сделать все треугольники в одном розыгрыше вызова. Вам не нужно разделять сетку.

+1

Если нормали каждой вершины должны соответствовать нормали лица, как может одна вершина, которая разделяется несколькими лицами, имеет нормальный характер со всеми из них? Спасибо за ваш быстрый ответ :) – JahrudZ

+2

@JahrudZ Это хороший вопрос, вы правы. Если вы используете структуру данных стиля glDrawElements, то она организована для совместного использования данных вершин, и вы не можете указать уникальный нормальный для каждой вершины, однако с этой моделью вы также не можете указать уникальные UV-координаты, которые обычно требуются для большинства 3D-моделей. Вместо этого вы можете дублировать вершинные и нормальные данные для каждого лица и рисовать с помощью glDrawArrays. Если это не имеет смысла, я могу уточнить больше. –

+0

@JahrudZ В вашем примере похоже, что вы уже используете неиндексированную структуру данных стиля glDrawArrays, поэтому вам нужно просто изменить функцию CalcNormal. –