无法使用 OpenGL 显示纹理

Posted

技术标签:

【中文标题】无法使用 OpenGL 显示纹理【英文标题】:Cannot get texture to appear using OpenGL 【发布时间】:2017-05-12 11:49:23 【问题描述】:

在我使用 opengl 4.5 的 Windows 计算机上,我似乎无法让我的纹理出现在屏幕上。我收到的只是黑屏。对于我的代码,我首先开发了一个小的 Vector 类来容纳所有顶点属性信息:

Vector3D.h

struct Position

    Position();
    Position(float x, float y, float z);
    float x;
    float y;
    float z;
;

Position::Position()


Position::Position(float x, float y, float z) :
    x(x), y(y), z(z)


struct Color

    GLubyte r;
    GLubyte g;
    GLubyte b;
    GLubyte a;
;

struct TextureCoordinate

    float u;
    float v;
;

struct Vector3D

    Vector3D();
    Vector3D(float x, float y, float z);

    Position position;
    Color color;
    TextureCoordinate textCoordinate;

    void setUV(float u, float v);
;

Vector3D::Vector3D()


Vector3D::Vector3D(float x, float y, float z) :
    position(x, y, z)


void Vector3D::setUV(float u, float v)

    this->textCoordinate.u = u;
    this->textCoordinate.v = v;

然后我有一个精灵类,通过它我使用 Init() 函数初始化顶点属性:

Sprite.cpp

void Sprite::Init(float x, float y, float width, float height)

    this->x = x;
    this->y = y;
    this->width = width;
    this->height = height;

    if (vboID == 0)
        glGenBuffers(1, &vboID);

    Vector3D vertexData[6]
        Vector3D x + width, y + height, 1.0f,
        Vector3D x, y + height, 1.0f ,
        Vector3D x, y, 1.0f,
        Vector3D x, y, 1.0f,
        Vector3D x + width, y, 1.0f,
        Vector3D x + width, y + height, 1.0f,
    ;

    for (int i = 0; i < 6; ++i)
    
        vertexData[i].color.r = 0;
        vertexData[i].color.g = 155;
        vertexData[i].color.b = 200;
    ;

    vertexData[0].setUV(1.0f, 1.0f);
    vertexData[1].setUV(0.0f, 1.0f);
    vertexData[2].setUV(0.0f, 0.0f);
    vertexData[3].setUV(0.0f, 0.0f);
    vertexData[4].setUV(1.0f, 0.0f);
    vertexData[5].setUV(1.0f, 1.0f);

    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

然后我在 sprite 类中有绘制函数,它显然会重新绑定以纠正 VBO 并绘制图像:

Sprite.cpp

void Sprite::Draw()

    glBindBuffer(GL_ARRAY_BUFFER, vboID);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textCoordinate));

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

最后,我在这里的 main 函数中调用上面的所有内容(我还使用 SDL 和图像加载库 stb):

main.cpp

int main(int agrc, char** argv)

    window.Initialize();
    playerSprite.Init(-1.0f, -1.0f, 1.0f, 1.0f);

    GameState gamestate GameState::PLAY ;

    SDL_Event evnt;

    int32 x, y, currentChannels;
    int32 forceChannels = 4;
    uchar8* imageData = 0;
    imageData = stbi_load("CharImage.png", &x, &y, &currentChannels, forceChannels);

    if (imageData == nullptr)
    
        LOG("ERROR: Could not load image file!");
    ;

    GLuint texture;
    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


    Blz::OpenGL::ShaderProgram colorShaderProgram;
    colorShaderProgram.Compile();
    colorShaderProgram.Link();
    colorShaderProgram.Bind();

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    while (gamestate != GameState::EXIT)
    
        unsigned int startTime = SDL_GetTicks();

        //Game Logic Update
        while (SDL_PollEvent(&evnt))
        
            switch (evnt.type)
            
            case SDL_QUIT:
                gamestate = GameState::EXIT;

            default:
                break;
            
        

        window.ClearBuffers();

        playerSprite.Draw();

        window.SwapBuffers();
    

    return 0;

另外,这是我的着色器:

顶点着色器

#version 430

layout(location=0) in vec3 vertexPosition;
layout(location=1) in vec2 textCoord;

out vec2 TextureCoord;

void main()

    gl_Position = vec4(vertexPosition, 1.0f);
    TextureCoord = textCoord;
; 

片段着色器

#version 430

out vec4 daColor;
in vec2 TextureCoord;

uniform sampler2D basicTexture;

void main()

    vec4 texel = texture(basicTexture, TextureCoord);
    daColor = texel;
;

【问题讨论】:

查看sizeof(vertexData)glBufferData()使用的错误号码。它必须是传递给 glBufferData 的数据大小(以字节为单位)。 而 sizeof(vertexData) 返回 144 数组中的字节数是否正确? 144 是结构的大小,而不是整个数据数组。 GL 对您的结构一无所知, glBufferData 只获取字节。您可以根据数据布局计算大小。另外,同样,查看如何读取缓冲区 (glVertexAttribPointer) @Ripi2 struct Vector3D 有 6 个浮点数,长度为 6*4 = 24 个字节。使用 6 个元素的向量,我们总共有 144 个字节 好吧,我会说之前我已经使用上面相同的代码将带有颜色数据的顶点位置发送到 opengl,并得到一个显示正确颜色的正方形。这让我觉得 glbufferdata 和 glvertexattribpointer 设置正确? 【参考方案1】:

在这样的时代,我希望有一个更好的替代跨平台图形编程的方法,因为 openGL 真的是一团糟。我的图像没有显示的原因是因为我正在设置参数:

glTextureParameteri()

而不是表面上正确的:

glTexParameteri()

........

【讨论】:

这两个函数做同样的事情,只是方式不同。 glTextureParameter 是一个 GL 4.5 DSA 函数,它接受 texture 进行修改。它不会影响绑定的纹理。相比之下,glTexParameter 对绑定纹理而不是给定纹理进行操作。这里唯一的“混乱”是为您尝试做的工作使用了错误的功能。 不,这是一个非常糟糕的命名约定。有两个功能不同的功能被命名,如果我曾经见过一个类似的设计缺陷。它会导致像我刚刚遇到的错误 但他们不做不同的事情。他们都在纹理上设置参数;您可以将完全相同的第二个和第三个参数传递给它们。它们之间的唯一区别是您如何提供它们设置参数的纹理。在 C++ 中,这些将是函数重载。 那么为什么不 glModfiyTexture() 呢?或类似的规定。我相信会让事情更清楚。 因为,尽管令人震惊(我在这里是认真的),OpenGL 实际上确实有一个reasonably consistent function naming convention。当然,对于“合理一致”的某些定义;)

以上是关于无法使用 OpenGL 显示纹理的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 OpenGL 渲染 FBX 导入的纹理模型

OpenGL纹理无法正常工作-黑屏[关闭]

在 Android 上使用 OpenGL ES 显示透明纹理的问题

opengl 纹理无法正确渲染

无法从 OpenGL 中的着色器访问先前渲染的纹理

OpenGL 纹理无法正常工作