OpenGL: как оптимизировать 2d-рендеринг с несколькими слоями, перекрывающими друг друга в 3D-режиме?

#c #opengl #3d #rendering #2d

#c #opengl #3D #рендеринг #2d

Вопрос:

Я знаю, как ускорить рендеринг в 3d, просто сначала отрисовав ближайшие плоскости.

Но как мне воспользоваться этим типом метода в 2d-режиме? Я не могу использовать тестирование глубины, потому что все они находятся на одном z-уровне.

Итак, я подумал, можно ли ускорить это, когда мне не нужно отображать невидимые части слоев «ниже». Возможно ли это?

Обратите внимание, что я выполняю рендеринг в 3D-режиме, могут быть 3D-объекты и 2d-объекты одновременно. Поэтому я не могу переключиться только на 2d-рендеринг, я всегда использую 3D-координаты для всего. И я могу поворачивать камеру по своему усмотрению, поэтому приемы, зависящие от конкретной камеры, неприемлемы.

Редактировать: я попробовал метод, предложенный Вилле: введите описание изображения здесь

( http://img815.imageshack.us/img815/7857/zfighting.png )

но, как вы видите, это приведет к z-битве.

Код, который я использовал для рендеринга, находится здесь:

 glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_POLYGON_OFFSET_FILL);

glColor4f(1,0,0,1);
DrawQuad(0, 0, 10, 10);

glColor4f(0,0,1,1);
DrawQuad(5, 5, 15, 15);

glDepthFunc(GL_LEQUAL);
  

Комментарии:

1. Тестирование глубины (с режимом по умолчанию GL_LESS) все равно будет работать, даже если все ваши 2d-объекты находятся на одном z-уровне. Пиксели не будут обновляться дважды.

2. @Вилле, это привело бы к z-битве. смотрите изображение, которое я опубликовал.

3. Вы правы, я думал, вы имели в виду 2d-объекты в стиле HUD и не поняли, что вы намеревались вращать камеру вокруг 2d-объектов тоже. Для этого я бы сначала отрисовал текстуру в орторежиме, как предлагает derkyjadex.

4. @Вилле, не будет ли рендеринг в текстуре излишеством …? я специально пытаюсь найти более быстрый метод, чем я использую atm: просто отключаю тестирование глубины. Но я надеялся, что смогу немного оптимизировать это, поскольку на самом деле это отрисовывает несколько бесполезных пикселей, которые никогда не видны…

Ответ №1:

Звучит так, как будто вы визуализируете все свои «2D» объекты на одной плоскости. Вы могли бы отобразить свои 2D-части в закадровый буфер кадров с ортографической проекцией и присвоить им разные значения Z, как предложил datenwolf. Затем отобразите текстуру фреймбуфера в вашей основной 3D-сцене.

Комментарии:

1. Или просто очистите буфер глубины и перерисуйте 2D-плоскости.

2. рендеринг в фреймбуфер выполняется быстрее, чем просто отключение проверки глубины?

3. Возможно, нет, у datenwolf, возможно, есть предложение получше. Но вы не отключаете проверку глубины, вы очищаете буфер глубины, чтобы OpenGL «забыл» об уже отрисованных 3D-объектах. Использование отдельного фреймбуфера эффективно делает то же самое, но вы можете сохранить свой буфер глубины 3D, если некоторые из 3D-объектов должны отображаться перед 2D-объектами.

Ответ №2:

Что вы понимаете под 2D-режимом? Вы имеете в виду ортографическую проекцию? Тогда у меня есть хорошие новости: тестирование глубины работает и там отлично. gluOrtho2D в основном такой же, как glOrtho (…, -1, 1); т. Е. вам нужно потратить диапазон Z -1 … 1.

РЕДАКТИРОВАТЬ из-за комментария:

Вполне возможно объединить рендеринг нескольких проекций в одном кадре:

 void render_perspective_scene(void);

void render_ortho_scene(void);

void render_HUD();

void display()
{
    float const aspect = (float)win_width/(float)win_height;

    glViewport(0,0,win_width,win_height);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-aspect*near/lens, aspect*near/lens, -near/lens, near/lens, near, far);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    render_perspective_scene();

    // just clear the depth buffer, so that everything that's
    // drawn next will overlay the previously rendered scene.
    glClear(GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-aspect*scale, aspect*scale, -scale, scale, 0, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    render_ortho_scene();

    // Same for the HUD, only that we render
    // that one in pixel coordinates.
    glClear(GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, win_width, 0, win_height, 0, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    render_HUD();
}
  

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

Комментарии:

1. «Обратите внимание, что я выполняю рендеринг в 3D-режиме, могут быть 3D-объекты и 2d-объекты одновременно. Итак, я не могу переключиться только на 2d-рендеринг «вы это читали?

2. Конечно, вы можете переключить это. Как, по-вашему, визуализируются игровые изображения?

3. HUD — это не то, чего я пытаюсь достичь здесь. Представьте, что у вас есть обычный 3D-мир, и затем вы визуализируете 3D-мир в 2D-режиме, если смотреть сверху, а затем поворачиваете камеру и видите, как мир сглаживается.

4. Хорошо, вы страдаете от серьезного заблуждения: OpenGL — это не график сцены. После того, как вы отправили некоторую геометрию в OpenGL, она просто растрирует ее до пикселей, а затем забывает о геометрии. Итак, переход к ортогональному рендерингу чего-либо, а затем поворот / переключение проекции не изменит то, что вы уже нарисовали в фреймбуфере. Итак, что вам на самом деле нужно сделать, это либо выполнить рендеринг текстур, затем нарисовать эти квадратики, либо сотворить какую-нибудь шейдерную магию, чтобы спроецировать геометрию плоско на эти плоскости, но при этом передать значения глубины, пригодные для тестирования глубины.

5. я пробовал с шейдерами, но это также потребовало отключения проверки глубины … я думаю, что для этого нет решения, не то чтобы мне это действительно нужно, но, как помешанный на оптимизации, я хотел бы знать каждый трюк: P