OpenGL / GLSL: Візуалізувати карту кубів?


13

Я намагаюся розібратися, як відобразити свою сцену на карту кубів. Я трохи застряг у цьому і подумав, що попрошу вас, допомогти. Я новачок у OpenGL, і це перший раз, коли я використовую FBO.

На даний момент у мене є робочий приклад використання файлу bmp кубічної карти, а тип вибірки samplerCube у шейдері фрагмента додається до GL_TEXTURE1. Я взагалі не змінюю код шейдера. Я просто змінюю той факт, що я не буду викликати функцію, яка завантажувала файл bema cubemap і намагалася використовувати код нижче, щоб передати кубічну карту.

Нижче ви бачите, що я також знову додаю текстуру до GL_TEXTURE1. Це так, коли я встановлюю форму:

glUniform1i(getUniLoc(myProg, "Cubemap"), 1);

він може отримати доступ до нього в моєму фрагменті шейдера через uniform samplerCube Cubemap.

Я називаю нижченаведену функцію так:

cubeMapTexture = renderToCubeMap(150, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);

Тепер я розумію в циклі малювання нижче, що я не змінюю напрямок перегляду, щоб дивитися вниз по осі + x, -x, + y, -y, + z, -z. Я справді просто хотів побачити щось, що працює, перш ніж це здійснити. Я подумав, що я повинен хоч щось побачити на своєму об’єкті так, як зараз код.

Я нічого не бачу, просто прямо чорний. Я зробив свій фон білим досі об'єкт чорним. Я зняв освітлення та фарбування, щоб просто пробувати текстуру кубічної карти та все ще чорну.

Я думаю, що проблемою можуть бути типи формату при встановленні моєї текстури, яка є GL_RGB8, GL_RGBA, але я також спробував:

GL_RGBA, GL_RGBA GL_RGB, GL_RGB

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

Я також намагався прив’язати текстуру карти куба в кожному розіграші, що я хочу використовувати карту куба:

glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexture);

Крім того, я не створюю буфер глибини для FBO, який я бачив у більшості прикладів, тому що я хочу лише буфер кольорів для своєї карти куба. Я фактично додав один, щоб побачити, чи це проблема, і все-таки отримав ті самі результати. Я міг би це роздути, коли спробував.

Будемо вдячні за будь-яку допомогу, яка може направити мене в правильному напрямку.

GLuint renderToCubeMap(int size, GLenum InternalFormat, GLenum Format, GLenum Type)
    {

    // color cube map
    GLuint textureObject;
    int face;
    GLenum status;

    //glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE1);
    glGenTextures(1, &textureObject);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureObject);
    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 (face = 0; face < 6; face++) {
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, InternalFormat, size, size, 0, Format, Type, NULL);
    }

    // framebuffer object
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, textureObject, 0);

    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    printf("%d\"\n", status);
        printf("%d\n", GL_FRAMEBUFFER_COMPLETE);

    glViewport(0,0,size, size);

    for (face = 1; face < 6; face++) {

        drawSpheres();
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, textureObject, 0);

    }

     //Bind 0, which means render to back buffer, as a result, fb is unbound
       glBindFramebuffer(GL_FRAMEBUFFER, 0);

       return textureObject;
    }

Ви перевірили, чи ваша drawSpheresфункція насправді показує щось видиме? Функція насправді щось малює? Що станеться, якщо ви зміните drawSpheresпросто очистити фреймбуфер?
Нікол Болас

Так. Я роблю два проходи. Один у наведеному вище коді, насправді на 6 дзвінків вище. Тоді я викликаю drawSpheres під час візуалізації в framebuffer 0, і він відображається.
Джої Грін

Також я встановив фон для білого. Чи не принаймні білий колір з'явиться в текстурі?
Joey Green

Чи добре працює ваш код для нормальної ФБО? Як я це розумію, карта куба повинна містити лише шість текстур, і вам доведеться візуалізувати кожну окремо ..
Jari Komppa

Відповіді:


10

Ну, я не можу гарантувати, що це допоможе тобі зрозуміти, що відбувається. Ви просто не розмістили достатньо інформації про те, що ви робите, щоб виявити будь-які конкретні помилки. Хоча я дуже швидко можу виправити одне з ваших:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, textureObject, 0);

...

for (face = 1; face < 6; face++) {
    drawSpheres();
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, textureObject, 0);
}

Це зателефонує лише drawSpheres п'ять разів. Я здогадуюсь, ти хотів зателефонувати йому 6 разів.

Але я можу розмістити робочу відповідь. Зауважте, що цей код розроблений так, щоб він працював поряд з моєю серією підручників , тому він посилається на код, якого немає. Але це в основному такі речі, як створення сіток тощо; нічого справді важливого.

Ось важливі моменти. Шейдери для об’єкта основної сфери.

Вершина шейдера:

#version 330

layout(std140) uniform;

layout(location = 0) in vec4 position;
layout(location = 2) in vec3 normal;

out vec3 modelSpaceNormal;

uniform Projection
{
    mat4 cameraToClipMatrix;
};

uniform mat4 modelToCameraMatrix;

void main()
{
    gl_Position = cameraToClipMatrix * (modelToCameraMatrix * position);
    modelSpaceNormal = normal;
}

Фрагмент шейдер:

#version 330

in vec3 modelSpaceNormal;

uniform samplerCube cubeTexture;

out vec4 outputColor;

void main()
{
    outputColor = texture(cubeTexture, modelSpaceNormal);
//  outputColor = vec4(normalize(modelSpaceNormal), 1.0);
}

Створення текстури кубічної карти, яка буде використовуватись як ціль візуалізації:

void CreateCubeTexture()
{
    glGenTextures(1, &g_cubeTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    std::vector<GLubyte> testData(CUBE_TEXTURE_SIZE * CUBE_TEXTURE_SIZE * 256, 128);
    std::vector<GLubyte> xData(CUBE_TEXTURE_SIZE * CUBE_TEXTURE_SIZE * 256, 255);

    for(int loop = 0; loop < 6; ++loop)
    {
        if(loop)
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGBA8,
                CUBE_TEXTURE_SIZE, CUBE_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &testData[0]);
        }
        else
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGBA8,
                CUBE_TEXTURE_SIZE, CUBE_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &xData[0]);
        }
    }

    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

Я фактично заповнюю текстуру даними (замість того, щоб передавати NULL в glTexImage2D) в якості допоміжного засобу. Це гарантує, що все працювало до початку використання текстури як цілі візуалізації.

Також зауважте, що я надаю BASE_LEVEL та MAX_LEVEL. Я завжди роблю це зі своїми текстурами відразу після створення. Це просто хороша звичка, оскільки OpenGL може бути розбірливим часом щодо повноти текстури та піраміди mipmap. Замість того, щоб пам’ятати правила, я просто релігійно встановлював їх правильні цінності.

Ось основна функція малювання:

void display()
{
    //Draw the cubemap.
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_framebuffer);
    glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, g_depthbuffer);

    for(int loop = 0; loop < 6; ++loop)
        DrawFace(loop);

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

    //Draw the main scene.
    //The projection matrix is in a uniform buffer.
    ProjectionBlock projData;
    projData.cameraToClipMatrix = glm::perspective(90.0f,
        (g_viewportSize.x / (float)g_viewportSize.y), g_fzNear, g_fzFar);

    glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, (GLsizei)g_viewportSize.x, (GLsizei)g_viewportSize.y);

    glClearColor(0.75f, 0.75f, 1.0f, 1.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack modelMatrix;
    modelMatrix.ApplyMatrix(g_viewPole.CalcMatrix());

    if(g_pSphere)
    {
        glutil::PushStack push(modelMatrix);

        glUseProgram(g_progMain.theProgram);
        glUniformMatrix4fv(g_progMain.modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelMatrix.Top()));

        glActiveTexture(GL_TEXTURE0 + g_cubeTexUnit);
        glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

        g_pSphere->Render("lit");

        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

        glUseProgram(0);
    }

    glutPostRedisplay();
    glutSwapBuffers();
}

Це робить посилання на те DrawFace, що малює задану грань кубічної карти. Це реалізується наступним чином:

void DrawFace(int iFace)
{
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + iFace, g_cubeTexture, 0);

    GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
    if(status != GL_FRAMEBUFFER_COMPLETE)
        printf("Status error: %08x\n", status);

    //The projection matrix is in a uniform buffer.
    ProjectionBlock projData;
    projData.cameraToClipMatrix = glm::perspective(90.0f, 1.0f, g_fzNear, g_fzFar);

    glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, (GLsizei)CUBE_TEXTURE_SIZE, (GLsizei)CUBE_TEXTURE_SIZE);

    const glm::vec4 &faceColor = g_faceColors[iFace];
    glClearColor(faceColor.x, faceColor.y, faceColor.z, faceColor.w);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(g_pSphere)
    {
        glutil::MatrixStack modelMatrix;
        modelMatrix.Translate(g_faceSphereLocs[iFace]);

        glUseProgram(g_progUnlit.theProgram);
        glUniformMatrix4fv(g_progUnlit.modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelMatrix.Top()));

        const glm::vec4 &sphereColor = g_faceSphereColors[iFace];
        glUniform4fv(g_progUnlit.objectColorUnif, 1, glm::value_ptr(sphereColor));

        glActiveTexture(GL_TEXTURE0 + g_cubeTexUnit);
        glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

        g_pSphere->Render("flat");

        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
        glUseProgram(0);
    }
}

Ця функція посилається на набір глобальних таблиць, які я використовую для надання кожному обличчю виразного кольору фону, виразного кольору сфери та для правильного розміщення сфери (у просторі камери) для цього обличчя.

Найважливіші моменти для DrawFaceцих.

Як правило, якщо я не маю певних знань про те, що встановлено стан, я встановлюю цей стан. Я встановлюю вікно перегляду кожного разу, коли дзвоню DrawFace. Я встановлюю матрицю проекції кожного разу. Це зайві; Я міг би встановити їх displayперед циклом, який дзвонить DrawFace, так само, як я це роблю з поточним FBO та глибинним рендербуфером.

Але я також очищаю буфери, які відрізняються для кожного обличчя (оскільки кожне обличчя має різний колір).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.