c++ - 为什么我无法在 OpenGL 中显示纹理?

标签 c++ opengl

我试图在 OpenGL 中加载纹理,但我得到的只是黑色。我已经验证着色器在编译时返回 GL_TRUE。所以,我认为这不是问题...

一些注意事项:

我已经从 https://open.gl/content/code/c3_multitexture.txt 中获取并修改了代码.这是来自 https://open.gl/textures 的教程

我要加载的纹理来自 640 x 400 PGM 文件。您可以假设加载程序 pgmImage 正确加载了文件(我已经在 GDB 中验证了它)。 PGM 是 8 位黑白数据。在这里,我尝试仅将其用作红色 channel ,但我希望最终也能够将其显示为黑白。

我哪里错了?

谢谢!

使用 g++ 中的 -lglut -lGLU -lGL -lm -lGLEW 标志编译的代码(我知道有些不是必需的)。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>

// Include GLEW
#include <GL/glew.h>

//Glut
#include <GL/glut.h>

#include "shader.hpp"
#include "PGM.hpp"

GLuint programID;
GLuint output_image;

// Shader sources
const GLchar* vertexSource =
    "#version 450 core\n"
    "in vec2 position;"
    "in vec2 texcoord;"
    "out vec2 Texcoord;"
    "void main()"
    "{"
    "    Texcoord = texcoord;"
    "    gl_Position = vec4(position, 0.0, 1.0);"
    "}";
const GLchar* fragmentSource =
    "#version 450 core\n"
    "in vec2 Texcoord;"
    "out vec4 outColor;"
    "uniform sampler2D texData;"
    "void main()"
    "{"
    "    outColor = texture(texData, Texcoord);"
    "}";



void display()
{

    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);

    glClear(GL_COLOR_BUFFER_BIT);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glFlush();
    glutSwapBuffers();

}    


void reshape(int width,int height)
{
    double w2h = (height>0) ? (double)width/height : 1;
    //  Set viewport as entire window
    glViewport(0,0, width,height);

}



int main(int argc, char** argv)
{
    // Image setup

    PGM pgmImage;
    pgmImage.ReadFile("test.pgm");

    // Window Setup

    glutInitWindowSize(640, 400);
    glutInitWindowPosition (140, 140);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutInit(&argc, argv);

    glutCreateWindow( "OpenGL Application" );
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);

    glewExperimental = true; // Needed for core profile
    if (glewInit() != GLEW_OK) {
        fprintf(stderr, "Failed to initialize GLEW\n");
        return -1;
    }

    // Vertices & texture init

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint vbo;
    glGenBuffers(1, &vbo);

    GLfloat vertices[] = {
        // X    Y      S    T
        -0.5f,  0.5f, 0.0f, 0.0f, // Top-left
         0.5f,  0.5f, 1.0f, 0.0f, // Top-right
         0.5f, -0.5f, 1.0f, 1.0f, // Bottom-right
        -0.5f, -0.5f, 0.0f, 1.0f  // Bottom-left
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLuint ebo;
    glGenBuffers(1, &ebo);

    GLuint elements[] = {
        0, 1, 2,
        2, 3, 0
    };

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

    // Create shaders

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, NULL);
    glCompileShader(vertexShader);


    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShader);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glBindFragDataLocation(shaderProgram, 0, "outColor");
    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    // Vertex data specification
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);

    GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat)));

    // Load Textures

    //TODO: don't really need 2 textures, but just following along with example source code for now...
    GLuint textures[2];
    unsigned char* image;

    int width, height;

    width = pgmImage.GetWidth();
    height = pgmImage.GetHeight();
    image = (unsigned char *)pgmImage.GetData();

    glGenTextures(2, textures);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,  GL_RED_INTEGER,  GL_UNSIGNED_BYTE, image);


    glUniform1i(glGetUniformLocation(shaderProgram, "texData"), 0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Start program

    glutMainLoop();

    // Teardown

    glDeleteTextures(2, textures);

    glDeleteProgram(shaderProgram);
    glDeleteShader(fragmentShader);
    glDeleteShader(vertexShader);

    glDeleteBuffers(1, &ebo);
    glDeleteBuffers(1, &vbo);

    glDeleteVertexArrays(1, &vao);

    return 0;
}

最佳答案

正如您已经发现的,您的 glTexImage2D() 调用的internalFormatformat 不兼容:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, image);

GL_RED_INTEGER 用于整数纹理类型。对于具有归一化纹理的单分量纹理数据,正确的格式是 GL_RED:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, image);

对于新代码,我总是建议使用大小的内部类型,即使像 GL_RGB 这样的未大小的内部类型对于向后兼容性仍然有效。因此对于具有 3 个 8 位分量的归一化纹理:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, image);

您尝试使用 GL_R8UI 作为内部格式失败,因为使用整数纹理需要额外的更改,特别是在着色器代码中,您需要使用 usampler2D 作为采样器类型,并在对纹理进行采样时处理获取整数值。但就您而言,这并不是您一开始真正想要的。

关于c++ - 为什么我无法在 OpenGL 中显示纹理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39681470/

相关文章:

c++ - DirectX/C++ : Marching Cubes Indexing

c++ - 将 Coin3D SoOffscreenRenderer 转换为 QImage 并使用 OpenGL 进行渲染

c++ - 如何使用粒子和更深的对象处理 OpenGL 加法混合和深度测试

OpenGL 透明度无法正常工作

c++ - 平行于向上 vector 转换阴影时的 LookAt 矩阵

c++ - OpenGL 的 GLM 库没有幅度函数吗?

c++ - 需要帮助使用 QThread 的多线程应用程序

c++ - 将 "unsigned char *"转换为 "char *"(和字符串)

c++ - 明确检查 boost::log 过滤器?

c++ - 循环逻辑流程