LibGDX: Как я могу добиться плоского затененного вида с OpenGL 2.0?
Поэтому я пытаюсь добиться стиля "Polygon Art/Low Poly" с помощью LibGDX. Я начну с построения модели из треугольников.
Затем с помощью вершинного шейдера я вычисляю цвета для каждой вершины на основе высоты.
Проблема в том, что местность закрашена Гуро, когда я хочу, чтобы она была плоской, вот так:
Я знаю, что в более высоких версиях OpenGL в glsl есть "плоское" ключевое слово, которое отключает интерполяцию цветов между вершинами. Из того, что я прочитал в Интернете и в этом посте: , я думаю, что мне нужно, чтобы каждый треугольник на местности был отделен друг от друга? Мне также нужно рассчитать нормаль на треугольник? Я не мог понять код в другом Stackru, но это то, что я пытался сделать:
оригинал
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, но я не могу понять, почему он не работает. Любая помощь будет великолепна, так как это был очень расстраивающий день. Большое спасибо!
1 ответ
Плоское и плавное затенение обычно определяется нормалями вершин и тем, как цвета интерполируются по всему лицу.
Обычно в гладкой модели нормали в каждой вершине усредняются для каждой грани в том же месте. Нормаль в каждой общей точке расположения вершин одинакова для каждой грани. Это то, что делает освещение плавным, потому что на краях нет резких изменений.
В плоской затененной модели нормали вершин не совпадают с соседними гранями, и вместо этого каждая нормаль вершин совпадает с нормалями граней. Это создает резкие изменения в нормальном значении на краю.
Как правило, это можно изменить в любом используемом пакете трехмерного моделирования или слегка изменив код обычной генерации, если ландшафт генерируется процедурно.
На следующем рисунке показана разница между плоскими и гладкими нормалями. Темные синие линии представляют средние сглаженные нормали, а более светлые (голубые) линии представляют резкую границу нормали.
Вы должны быть в состоянии нарисовать все треугольники вместе в одном вызове. Вам не нужно разбивать сетку.