Рендеринг на кубическую карту - PullRequest
11 голосов
/ 20 января 2009

Согласно ARB_geometry_shader4 возможно отобразить сцену на 6 гранях карты куба с помощью геометрического шейдера и карты куба, прикрепленной к объекту кадрового буфера. Я хочу создать карту теней, используя этот способ. Однако, кажется, есть конфликт, который я не могу разрешить:

  1. Я могу только прикрепить текстуру с GL_DEPTH_COMPONENT в качестве внутреннего типа к GL_DEPTH_ATTACHMENT_EXT.
  2. Текстура глубины может быть только 1D или 2D.
  3. Если я хочу прикрепить карту куба, все остальные прикрепленные текстуры также должны быть картами куба.

Похоже, я не могу использовать какое-либо тестирование глубины, когда хочу рендерить на карту куба. Или что именно мне здесь не хватает?

РЕДАКТИРОВАТЬ: Похоже, что новые драйверы Nvidia (180.48) поддерживают карты куба глубины.

1 Ответ

12 голосов
/ 30 января 2009

Хорошо, чтобы ответить на некоторые другие вопросы здесь:

Конечно, можно использовать 6 FBO, по одному на каждое лицо. Или использовать один FBO и прикрепить каждое лицо, прежде чем рисовать на нем. В обоих случаях грань кубической карты будет обрабатываться как любая другая 2D-текстура, и вы можете использовать ее вместе с обычными 2D-текстурами или Renderbuffers. И, вероятно, нет большой разницы во всех возможных способах (если оборудование их поддерживает).

Однако также можно нарисовать все за один шаг, и, как мне было любопытно, как это делается, я провел некоторые исследования.

Чтобы создать FBO со всеми гранями карты куба, прикрепленными к одной точке присоединения, я использовал этот код (написанный на D):

// depth cube map
glGenTextures(1, &tDepthCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, tDepthCubeMap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT24,
        width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
}

// color cube map
glGenTextures(1, &tColorCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, tColorCubeMap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA,
        width, height, 0, GL_RGBA, GL_FLOAT, null);
}

// framebuffer object
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, tDepthCubeMap, 0);
glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, tColorCubeMap, 0);

glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

if (!isValidFBO()) {
    glDeleteFramebuffersEXT(1, &fbo);
    fbo = 0;
}
  • Если вы хотите иметь только карту глубины, вы должны изменить glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); на glDrawBuffer (GL_NONE); до его проверки (и до рисования к нему)
  • Для фильтров MIN и MAG должно быть установлено что-то допустимое (по умолчанию будет GL_NEAREST_MIPMAP_LINEAR)
  • ширина и высота всех текстур должны быть одинаковыми

Для рендеринга на грани кубической карты вам нужен геометрический шейдер. Следующий шейдер пропускает некоторые повороты, но должно быть понятно, что он делает. gl_Layer используется для направления примитива на правильную грань (0 = + X, 1 = -X, ...).

#version 120
#extension GL_EXT_geometry_shader4 : enable

void main(void) {
    int i, layer;
    for (layer = 0; layer < 6; layer++) {
        gl_Layer = layer;
        for (i = 0; i < 3; i++) {
            gl_Position = gl_PositionIn[i];
            EmitVertex();
        }
        EndPrimitive();
    }
}
...