OpenGL / GLSL : 큐브 맵으로 렌더링?


13

장면을 큐브 맵에 렌더링하는 방법을 알아 내려고 노력 중입니다. 나는 이것에 조금 붙어 있었고 당신에게 도움을 청할 것이라고 생각했습니다. 저는 OpenGL을 처음 사용하며 FBO를 처음 사용합니다.

현재 cubemap bmp 파일을 사용하는 실제 예제가 있으며 조각 셰이더의 samplerCube 샘플 유형이 GL_TEXTURE1에 연결되어 있습니다. 셰이더 코드를 전혀 변경하지 않습니다. 나는 cubemap bmp 파일을로드하는 함수를 호출하지 않고 아래 코드를 사용하여 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프레임 버퍼 만 지우도록 변경하면 어떻게됩니까 ?
Nicol Bolas

예. 나는 두 번 패스하고 있습니다. 위의 코드 중 하나, 실제로는 6 번의 호출입니다. 그런 다음 프레임 버퍼 0으로 렌더링 할 때 drawSpheres를 호출하고 표시됩니다.
Joey Green

또한 배경을 흰색으로 설정했습니다. 최소한 텍스처에 흰색이 나타나지 않습니까?
Joey Green

정상적인 FBO에서 코드가 제대로 작동합니까? 내가 그것을 이해하는 방법은, 큐브 맵은 불과 6 개 텍스처해야하며, 별도로 각 .. 렌더링해야 할 것
야리 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은 때때로 텍스처 완성도와 밉맵 피라미드에 대해 까다로울 수 있기 때문에 좋은 습관입니다. 규칙을 기억하는 대신 종교적으로 올바른 값으로 설정했습니다.

주요 그리기 기능은 다음과 같습니다.

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. 매번 투영 행렬을 설정했습니다. 그것들은 불필요한 것입니다. 현재 FBO 및 깊이 렌더 버퍼와 마찬가지로을 display호출하는 루프 전에 다시 설정할 수 있습니다 DrawFace.

그러나 나는 또한 각 얼굴마다 다른 버퍼를 지 웁니다 (각 얼굴마다 다른 색상이 있기 때문에).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.