Skybox无法渲染

时间:2014-05-12 18:04:03

标签: opengl textures freeimage skybox

我尝试在我的场景中渲染天空盒,但它渲染黑色像纹理没有正确加载。我使用FreeImage库来加载纹理:

#include <FreeImage.h>

这是我的Skybox课程:

#include "Skybox.h"


CSkybox::CSkybox(){
    el::Logger* logger = el::Loggers::getLogger("Skybox");
}

void CSkybox::init(string home_dir, string pos_x, string neg_x, string pos_y, string neg_y, string pos_z, string neg_z)
{
    cubeFilesPaths[0] = home_dir+pos_x;
    cubeFilesPaths[1] = home_dir+neg_x;
    cubeFilesPaths[2] = home_dir+pos_y;
    cubeFilesPaths[3] = home_dir+neg_y;
    cubeFilesPaths[4] = home_dir+pos_z;
    cubeFilesPaths[5] = home_dir+neg_z;

    loadShaders("shaders/skyboxShader.vp", "shaders/skyboxShader.fp");

    glGenTextures(1, &cubeTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);

    for(int i = 0; i < 6; i++){        
        verify(readTexture(i), "Texture "+cubeFilesPaths[i]+" not loaded"); 
    }

    CLOG(INFO, "Skybox")<<"Skybox texture loaded.";

    vao.createVAO();
    vao.bindVAO();
}

void CSkybox::loadShaders(string vsPath, string fsPath){
    verify(skyboxVertexShader.loadShader(vsPath, GL_VERTEX_SHADER), "Skybox vertex shader not loaded");
    verify(skyboxFragmentShader.loadShader(fsPath, GL_FRAGMENT_SHADER), "Skybox fragment shader not loaded");

    skyboxShaderProgram.createProgram();
    verify(skyboxShaderProgram.addShaderToProgram(&skyboxVertexShader), "Skybox vertex shader not added to a program");
    verify(skyboxShaderProgram.addShaderToProgram(&skyboxFragmentShader), "Skybox fragment shader not added to a program");

    verify(skyboxShaderProgram.linkProgram(), "Shader program not linked"); 
}

void CSkybox::render(glm::mat4 viewMatrix){
    //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    //glDisable(GL_CULL_FACE);

    skyboxShaderProgram.bindProgram();
    vao.bindVAO();

    skyboxShaderProgram.setUniform("view_matrix", &viewMatrix);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);

    glDisable(GL_DEPTH_TEST);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glEnable(GL_DEPTH_TEST);

    vao.unbindVAO();
    //glEnable(GL_CULL_FACE);
    skyboxShaderProgram.unbindProgram();
    //glPolygonMode(GL_FRONT, GL_FILL);
}

void CSkybox::release(){
    glDeleteTextures(1, &cubeTexture);
    skyboxShaderProgram.deleteProgram();
    skyboxVertexShader.deleteShader();
    skyboxFragmentShader.deleteShader();
    vao.releaseVAO();
}

bool CSkybox::readTexture(int i){
    cout<<"Reading: "<<i<<endl;

    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
    FIBITMAP* dib(0);

    fif = FreeImage_GetFileType(cubeFilesPaths[i].c_str(), 0); // Check the file signature and deduce its format

    if(fif == FIF_UNKNOWN) // If still unknown, try to guess the file format from the file extension
        fif = FreeImage_GetFIFFromFilename(cubeFilesPaths[i].c_str());

    if(fif == FIF_UNKNOWN) // If still unknown, return failure
        return false;

    if(FreeImage_FIFSupportsReading(fif)) // Check if the plugin has reading capabilities and load the file
        dib = FreeImage_Load(fif, cubeFilesPaths[i].c_str());
    if(!dib)
        return false;

    BYTE* bits = FreeImage_GetBits(dib); // Retrieve the image data

    // If somehow one of these failed (they shouldn't), return failure
    if(bits == NULL || FreeImage_GetWidth(dib) == 0 || FreeImage_GetHeight(dib) == 0)
        return false;

    cout<<FreeImage_GetBPP(dib)<<endl;

    GLenum format = FreeImage_GetBPP(dib) == 24 ? GL_BGR : FreeImage_GetBPP(dib) == 8 ? GL_LUMINANCE : 0;
    GLenum internalFormat = FreeImage_GetBPP(dib) == 24 ? GL_RGB : GL_DEPTH_COMPONENT;
    GLsizei iWidth = FreeImage_GetWidth(dib);
    GLsizei iHeight = FreeImage_GetHeight(dib);

    cout<<iWidth<<endl;
    cout<<iHeight<<endl;

    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat, iWidth, iHeight, 0, format, GL_UNSIGNED_BYTE, bits);

    GLenum error = glGetError();
    if(error!= GL_NO_ERROR){
        cout<<error<<endl;
    }

    FreeImage_Unload(dib);
    return true;
}

void CSkybox::verify(bool value, string message){
    if(!value){
        CLOG(ERROR, "Skybox")<<"Error: "<<message;
    }
}

顶点着色器:

#version 430 core

out VS_OUT
{
    vec3 tc;
} vs_out;

uniform mat4 view_matrix;

void main(void)
{
    vec3[4] vertices = vec3[4](vec3(-1.0, -1.0, 1.0),
                               vec3( 1.0, -1.0, 1.0),
                               vec3(-1.0,  1.0, 1.0),
                               vec3( 1.0,  1.0, 1.0));

    vs_out.tc = mat3(view_matrix) * vertices[gl_VertexID];

    gl_Position = vec4(vertices[gl_VertexID], 1.0);
}

和片段着色器:

#version 430 core

layout (binding = 0) uniform samplerCube tex_cubemap;

in VS_OUT
{
    vec3    tc;
} fs_in;

layout (location = 0) out vec4 color;

void main(void)
{
    color = texture(tex_cubemap, fs_in.tc);
}

不幸的是,render()方法只渲染一个黑色矩形。如果我对片段着色器中的其他颜色或顶点着色器中的顶点坐标进行硬编码,则矩形会更改颜色和位置。我使用着色器和vao辅助类来渲染粒子,所以它们可能很好,问题在于纹理加载。

最终效果如下:

enter image description here

1 个答案:

答案 0 :(得分:3)

您至少有两个名为cubeEnum

的变量

cubeEnum构造函数中的函数作用域声明了CSkybox

CSkybox::CSkybox(){
    el::Logger* logger = el::Loggers::getLogger("Skybox");

    GLenum  cubeEnum[6] = {  GL_TEXTURE_CUBE_MAP_POSITIVE_X,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
        GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };
}

cubeEnum使用的另一个范围声明了另一个readTexture (...)

glTexImage2D(cubeEnum[i], 0, internalFormat, iWidth, iHeight, 0, format, GL_UNSIGNED_BYTE, bits);

我怀疑另一个名为cubeEnum的数组未初始化,因此您将垃圾传递给glTexImage2D (...)。但是,简单的事实是,您首先不需要数组。

这组特殊的枚举是顺序的,因此您可以编写以下内容:

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat, iWidth, iHeight, 0, format, GL_UNSIGNED_BYTE, bits);

并删除所有名为cubeEnum的单独变量。然后,您将在不同范围内隐藏同名变量将不再重要。


更新

此外,您在立方体贴图上使用默认纹理缩小过滤器:GL_NEAREST_MIPMAP_LINEAR,该贴图没有适当的mipmap LOD集(默认情况下GL纹理具有 1000 LOD,您只能使用定义LOD 0 )。在 &#34; mipmap不完整&#34; 纹理上使用该过滤器会导致未定义的行为,这就是黑色纹理的原因。