Отображение карты куба

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

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

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

EDIT: Похоже, новые драйверы Nvidia (180.48) поддерживают карты кубов глубины.

Ответ 1

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

Конечно, можно использовать 6 FBOs, по одному для каждого лица. Или использовать один 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();
    }
}