2012-04-06 4 views
2

Я делаю игру на основе вокселя, и для этого я создаю механизм рендеринга блоков.Как прекратить рендеринг невидимых лиц

Точка в том, что мне нужно создать много кубов. Каждый раз, когда я делаю более 16x16x16 кусок этих блоков, мой FPS сбрасывается с трудом, потому что он отображает все 6 граней всех этих кубов. Это 24 576 квадрациклов, и я этого не хочу.

Итак, мой вопрос: как остановить рендеринг вершин (или квадратов), которые не видны, и, следовательно, увеличить производительность моей игры?

Вот класс для визуализации блока:

public void renderBlock(int posx, int posy, int posz) { 
    try{ 
    //t.bind(); 
    glEnable(GL_CULL_FACE); 
    glCullFace(GL_BACK);// or even GL_FRONT_AND_BACK */); 

    glPushMatrix(); 

    GL11.glTranslatef((2*posx+0.5f),(2*posy+0.5f),(2*posz+0.5f));    // Move Right 1.5 Units And Into The Screen 6.0 
    GL11.glRotatef(rquad,1.0f,1.0f,1.0f); 

    glBegin(GL_QUADS);    // Draw A Quad 

    GL11.glColor3f(0.5f, 0.4f, 0.4f);    // Set The Color To Green 
    GL11.glTexCoord2f(0,0); 
    GL11.glVertex3f(1f, 1f,-1f);   // Top Right Of The Quad (Top) 
    GL11.glTexCoord2f(1,0); 
    GL11.glVertex3f(-1f, 1f,-1f);   // Top Left Of The Quad (Top) 
    GL11.glTexCoord2f(1,1); 
    GL11.glVertex3f(-1f, 1f, 1f);   // Bottom Left Of The Quad (Top) 
    GL11.glTexCoord2f(0,1); 
    GL11.glVertex3f(1f, 1f, 1f);   // Bottom Right Of The Quad (Top) 

    //GL11.glColor3f(1.2f,0.5f,0.9f);    // Set The Color To Orange 
    GL11.glTexCoord2f(0,0); 
    GL11.glVertex3f(1f,-1f, 1f);   // Top Right Of The Quad (Bottom) 
    GL11.glTexCoord2f(0,1); 
    GL11.glVertex3f(-1f,-1f, 1f);   // Top Left Of The Quad (Bottom) 
    GL11.glTexCoord2f(1,1); 
    GL11.glVertex3f(-1f,-1f,-1f);   // Bottom Left Of The Quad (Bottom) 
    GL11.glTexCoord2f(1,0); 
    GL11.glVertex3f(1f,-1f,-1f);   // Bottom Right Of The Quad (Bottom) 

    //GL11.glColor3f(1.0f,0.0f,0.0f);    // Set The Color To Red 
    GL11.glTexCoord2f(0,0); 
    GL11.glVertex3f(1f, 1f, 1f);   // Top Right Of The Quad (Front) 
    GL11.glTexCoord2f(1,0); 
    GL11.glVertex3f(-1f, 1f, 1f);   // Top Left Of The Quad (Front) 
    GL11.glTexCoord2f(1,1); 
    GL11.glVertex3f(-1f,-1f, 1f);   // Bottom Left Of The Quad (Front) 
    GL11.glTexCoord2f(0,1); 
    GL11.glVertex3f(1f,-1f, 1f);   // Bottom Right Of The Quad (Front) 

    //GL11.glColor3f(1f,0.5f,0.0f);    // Set The Color To Yellow 
    GL11.glTexCoord2f(0,0); 
    GL11.glVertex3f(1f,-1f,-1f);   // Bottom Left Of The Quad (Back) 
    GL11.glTexCoord2f(1,0); 
    GL11.glVertex3f(-1f,-1f,-1f);   // Bottom Right Of The Quad (Back) 
    GL11.glTexCoord2f(1,1); 
    GL11.glVertex3f(-1f, 1f,-1f);   // Top Right Of The Quad (Back) 
    GL11.glTexCoord2f(0,1); 
    GL11.glVertex3f(1f, 1f,-1f);   // Top Left Of The Quad (Back) 

    //GL11.glColor3f(0.0f,0.0f,0.3f);    // Set The Color To Blue 
    GL11.glTexCoord2f(0,1); 
    GL11.glVertex3f(-1f, 1f, 1f);   // Top Right Of The Quad (Left) 
    GL11.glTexCoord2f(1,1); 
    GL11.glVertex3f(-1f, 1f,-1f);   // Top Left Of The Quad (Left) 
    GL11.glTexCoord2f(1,0); 
    GL11.glVertex3f(-1f,-1f,-1f);   // Bottom Left Of The Quad (Left) 
    GL11.glTexCoord2f(0,0); 
    GL11.glVertex3f(-1f,-1f, 1f);   // Bottom Right Of The Quad (Left) 

    //GL11.glColor3f(0.5f,0.0f,0.5f);    // Set The Color To Violet 
    GL11.glTexCoord2f(0,0); 
    GL11.glVertex3f(1f, 1f,-1f);   // Top Right Of The Quad (Right) 
    GL11.glTexCoord2f(1,0); 
    GL11.glVertex3f(1f, 1f, 1f);   // Top Left Of The Quad (Right) 
    GL11.glTexCoord2f(1,1); 
    GL11.glVertex3f(1f,-1f, 1f);   // Bottom Left Of The Quad (Right) 
    GL11.glTexCoord2f(0,1); 
    GL11.glVertex3f(1f,-1f,-1f);   // Bottom Right Of The Quad (Right) 

    //rquad+=0.0001f; 
    glEnd(); 
    glPopMatrix(); 
    }catch(NullPointerException t){t.printStackTrace(); System.out.println("rendering block failed");} 
} 

Вот код, который делает их:

private void render() { 
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT|GL11.GL_DEPTH_BUFFER_BIT); 
    for(int y=0; y<32; y++){ 
    for(int x=0; x<16; x++){ 
     for(int z=0; z<16; z++) { 
     b.renderBlock(x, y, z); 

     } 
    } 
    } 
} 
+0

Кто-нибудь поможет? – TheMorfeus

+0

Возможный дубликат [Как сделать удаление лица в мире единичного куба a la Minecraft?] (Http://stackoverflow.com/questions/6319655/how-to-do-face-removal-in-a-unit- cube-world-a-la-minecraft) –

ответ

2

Я рекомендую, как сказал ulmangt, использовать VBO, но до этого вам нужно рассчитать только видимые лица.

Это может быть легко сделано (только один раз в начале), проверяя, является ли лицо соседним с пустым вокселом («воздух»). Если это так, добавьте этот квадрат (грань) в рендеринг.

Впоследствии вы просто выполняете эту проверку только у соседей измененных вокселей. Пример. Когда пользователь удаляет куб, проверьте 6 соседей этого воксела и добавьте эти квадратики в рендеринг. Сделайте обратный, когда добавлены вокселы, удалите соседние квадратики.

Так с 5x5x5 куб из вокселей, вместо 750 квадрациклов, вы в конечном итоге с 150.

Другие выгоды можно получить, просто рендеринга куски (группа вокселей) в представлении (игнорируя те на задней панели проигрывателя) и с использованием предела расстояния.

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

+0

Спасибо :) Теперь у вас есть идея, как определить, касается ли воксел вокселя? – TheMorfeus

+0

Ну, потоки вокселей будут всего лишь трехмерным массивом, заполненным типом вокселов (я думаю, что minecraft использовал байты для представления типа воксела в версиях indev, теперь не знаю). Самый простой способ, который приходит на ум, - просто перебрать весь массив и проверить соседей каждого воксела и добавить видимые квадратики в список. (TL; DR: Итерация через 3d массив вокселей, игнорирование вокселей типа «воздух», проверка соседей для воздушных вокселей, добавление видимых квадрациклов.) –

3

Ваш код имеет большую проблему производительности. Вы не должны использовать немедленный рендеринг OpenGL (glVertexXXX() calls), чтобы нарисовать такое большое количество вершин.

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

Вместо этого вы должны использовать Vertex Buffer Objects. Это позволит вам загружать всю вашу геометрию прямо на графическую карту, а затем нарисовать все ваши кубы одним вызовом метода Java (возможно, glDrawArrays).

+2

Это просто устранение проблемы меньшего размера. Проблема здесь в том, что он пытается сделать рендеринг вокселей грубым способом, у которого нет реальных шансов на работу. По крайней мере, не для любого размера ввода. – pmr

+0

Как это сделать? – TheMorfeus

1

Хорошая идея - НЕ использовать немедленный режим для рендеринга блоков, я использую списки отображения, потому что они самые простые для настройки и очень быстрые. Во-вторых, даже если вы все еще используете только немедленный режим, используйте только один вызов glBegin/glEnd при рисовании. Используйте текстурный атлас для текстур в будущем и к своему основному вопросу, который заключается в том, как остановить рендеринг невидимых лиц, It довольно просто. Как я это делаю, в основном делают шесть методов для каждого лица, которое возвращает логическое значение. Вы бы просто возвращались, если тип блока в направлении этого лица является воздушным блоком, если это так. Тогда это означает, что он вернет true, поэтому отрисуйте его. И в вашем методе рисования добавьте параметры «boolean backface, boolean topface ... etc» и оператор if, проверяющий, какую сторону рисовать.

надеюсь, что я помог, удачи!

+0

этот вопрос старше 2 лет, и я уже решил проблему с использованием списков отображения. Несмотря на это, я уже полностью ушел от этого проекта. – TheMorfeus

+0

Я не читал дату, Тем не менее, это поможет людям, ищущим ответы. – ABOODYFJ