在openGL中渲染PNG纹理时黑屏

问题描述 投票:0回答:1

当尝试在 OpenGL 中将 PNG 文件渲染为纹理时,我只绘制黑屏。

如果我将纹理坐标数据直接输入片段着色器中的颜色,我可以渲染一个着色立方体。

我还检查过:

[unsigned char* image] 正在填充数据。

顶点列表 = 36 * 3 个浮点数 (-1.0 - 1.0)。

tex 坐标列表 = 36 * 2 个浮点数 (0.0 - 1.0)。

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

using namespace std;

float rotation = 0.0f;
glm::mat4 trans = glm::mat4(1.0f);

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GLFW_TRUE);
    }
    else if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS) {
        rotation += 12.0f;
        trans = glm::rotate(glm::mat4(1.0f), glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f));
    }
    else if (key == GLFW_KEY_LEFT && action == GLFW_PRESS) {
        rotation -= 12.0f;
        trans = glm::rotate(glm::mat4(1.0f), glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f));
    }
}

float x_rot = 0.0f;
float y_rot = 0.0f;
float z_rot = 0.0f;

float x_spd = 0.1f;
float y_spd = 0.05f;
float z_spd = 0.03f;

void do_rotate() {
    x_rot += x_spd;
    y_rot += y_spd;
    z_rot += z_spd;
    trans = glm::mat4(1.0f);
    trans = glm::rotate(trans, glm::radians(x_rot), glm::vec3(1.0f, 0.0f, 0.0f));
    trans = glm::rotate(trans, glm::radians(y_rot), glm::vec3(0.0f, 1.0f, 0.0f));
    trans = glm::rotate(trans, glm::radians(z_rot), glm::vec3(0.0f, 0.0f, 1.0f));
}

struct model {
    GLint tex_id;
    vector<glm::vec3> v_list, n_list, f_list, tris, texVs;
    vector<glm::vec2> t_list;
    float *triA, *texA;
    int triCount;

    model();

    void load_obj(string path);
    void create_tris();
    void find_tri_points(size_t pos, string* line, size_t* offset);
    void find_tex_points(size_t pos, string* line, size_t* offset);
    void find_f_list(size_t pos, string* line, size_t* offset);

    void print_v_list();
    void print_f_list();
    void print_t_list();
    void print_tris();
    void print_texVs();

    void print_triA();
    void print_texA();

    ~model();
};

model::model() {
    triA = nullptr;
    texA = nullptr;
    triCount = 0;
    tex_id = -1;
}

model::~model() {
    delete[] triA;
    delete[] texA;
}

void model::find_tri_points(size_t pos, string* line, size_t* offset) {
    glm::vec3 tVec;
    std::string item;
    int index = 0;
    while (pos != std::string::npos) {
        pos = (*line).find(' ', *offset);
        item = (*line).substr(*offset, pos - *offset);
        tVec[index] = std::stof(item);
        *offset = pos + 1;
        index += 1;
    }
    v_list.push_back(tVec);
}

void model::find_tex_points(size_t pos, string* line, size_t* offset) {
    glm::vec2 tVec;
    std::string item;
    int index = 0;
    while (pos != std::string::npos) {
        pos = (*line).find(' ', *offset);
        item = (*line).substr(*offset, pos - *offset);
        tVec[index] = std::stof(item);
        *offset = pos + 1;
        index += 1;
    }
    t_list.push_back(tVec);
}

void model::find_f_list(size_t pos, string* line, size_t* offset) {
    glm::vec3 vPoints;
    glm::vec3 fPoints;
    std::string face;
    int index = 0;
    while (pos != std::string::npos) {
        pos = (*line).find(' ', *offset);
        face = (*line).substr(*offset, pos - *offset);

        vPoints[index] = std::stof(face.substr(0, face.find('/')));
        fPoints[index] = std::stof(face.substr(face.find('/') + 1, face.find('/', face.find('/') + 1)));
        *offset = pos + 1;
        index += 1;
    }
    tris.push_back(vPoints);
    texVs.push_back(fPoints);
}

void model::load_obj(string path) {
    std::ifstream ifile(path);
    if (ifile.is_open()) {
        std::string line;
        while (std::getline(ifile, line)) {
            std::string item;
            size_t pos = line.find(' ');
            if (pos != std::string::npos) {
                item = line.substr(0, pos);
            }

            size_t offset = pos + 1;

            std::vector<glm::vec3>* list = nullptr;
            if (item == "v") {
                find_tri_points(pos, &line, &offset);
            }else if (item == "vn") {
                //list = &n_list;
            }else if (item == "vt") {
                find_tex_points(pos, &line, &offset);
            }else if (item == "f") {
                find_f_list(pos, &line, &offset);
            }
        }
        create_tris();
    }else {
        cout << "Failed to open: " << path << "\n";
    }
    ifile.close();
}

void model::create_tris() {
    triCount = tris.size();
    triA = new float[tris.size() * 9];
    texA = new float[tris.size() * 6];
    int arrayIndex = 0;
    for (vector<glm::vec3>::iterator it = tris.begin(); it != tris.end(); it++) {
        for (int i = 0; i < 3; i++) {
            int current_v = (*it)[i] - 1;
            for (int j = 0; j < 3; j++) {
                triA[(arrayIndex * 9) + (i * 3) + j] = v_list[current_v][j] * 0.5f;
            }
        }
        arrayIndex++;
    }
    arrayIndex = 0;
    for (vector<glm::vec3>::iterator it = texVs.begin(); it != texVs.end(); it++) {
        for (int i = 0; i < 3; i++) {
            int current_t = (*it)[i] - 1;
            for (int j = 0; j < 2; j++) {
                texA[(arrayIndex * 6) + (i * 2) + j] = t_list[current_t][j];
            }
        }
        arrayIndex++;
    }
}

void model::print_v_list() {
    cout << "V List:\n";
    for (vector<glm::vec3>::iterator it = v_list.begin(); it != v_list.end(); it++) {
        cout << (*it)[0] << ", " << (*it)[1] << ", " << (*it)[2] << '\n';
    }
}
void model::print_f_list() {
    cout << "F List:\n";
    for (vector<glm::vec3>::iterator it = f_list.begin(); it != f_list.end(); it++) {
        cout << (*it)[0] << ", " << (*it)[1] << ", " << (*it)[2] << '\n';
    }
}
void model::print_t_list() {
    cout << "T List:\n";
    for (vector<glm::vec2>::iterator it = t_list.begin(); it != t_list.end(); it++) {
        cout << (*it)[0] << ", " << (*it)[1] << '\n';
    }
}
void model::print_tris() {
    cout << "Tris:\n";
    for (vector<glm::vec3>::iterator it = tris.begin(); it != tris.end(); it++) {
        cout << (*it)[0] << ", " << (*it)[1] << ", " << (*it)[2] << '\n';
    }
}
void model::print_texVs() {
    cout << "TexVs:\n";
    for (vector<glm::vec3>::iterator it = texVs.begin(); it != texVs.end(); it++) {
        cout << (*it)[0] << ", " << (*it)[1] << ", " << (*it)[2] << '\n';
    }
}
void model::print_triA() {
    if (triA != nullptr) {
        cout << "TriA:\n";
        for (int i = 0; i < (triCount * 9); i++) {
            if((i % 3) == 0){
                cout << '\n' << (i / 3) << "  ";
            }
            cout << triA[i] << " ";
        }
    }
}
void model::print_texA() {
    if (texA != nullptr) {
        cout << "TexA\n";
        for (int i = 0; i < (triCount * 6); i++) {
            if ((i % 2) == 0) {
                cout << '\n' << (i / 2) << "  ";
            }
            cout << texA[i] << " ";
        }
    }
}

int init() {
    if (!glfwInit()) {
        printf("Unable to initialse GLFW.");
        return 0;
    }
    else {
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    }
    return 1;
}

int create_window(GLFWwindow** win) {
    *win = glfwCreateWindow(640, 480, "Test", NULL, NULL);  //windowed
    //GLFWwindow* window = glfwCreateWindow(640, 480, "Test", glfwGetPrimaryMonitor(), NULL);   //fullscreen
    if (!*win) {
        printf("Unable to create Window.");
        return 0;
    }
    else {
        glfwMakeContextCurrent(*win);
        printf("Window created succesfully.");
        glfwSetKeyCallback(*win, key_callback);

        glewExperimental = GL_TRUE;
        glewInit();

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
    }
    return 1;
}

void create_object(GLuint* vertexBuffer, GLuint* texBuffer, GLuint* vertexArrayObject, float* points, float* texCoords, int count) {
    glGenBuffers(1, vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, *vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, count * 9 * sizeof(float), points, GL_STATIC_DRAW);

    glGenBuffers(1, texBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, *texBuffer);
    glBufferData(GL_ARRAY_BUFFER, count * 6 * sizeof(float), texCoords, GL_STATIC_DRAW);

    glGenVertexArrays(1, vertexArrayObject);

    glBindVertexArray(*vertexArrayObject);
    glBindBuffer(GL_ARRAY_BUFFER, *vertexBuffer);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, *texBuffer);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, NULL);
}

void create_shaders(GLuint* vs, GLuint* fs, GLuint* shader_programme, const char* vertex_shader, const char* fragment_shader) {
    *vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(*vs, 1, &vertex_shader, NULL);
    glCompileShader(*vs);

    *fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(*fs, 1, &fragment_shader, NULL);
    glCompileShader(*fs);

    *shader_programme = glCreateProgram();
    glAttachShader(*shader_programme, *fs);
    glAttachShader(*shader_programme, *vs);
    glBindAttribLocation(*shader_programme, 0, "vp");
    glBindAttribLocation(*shader_programme, 1, "texCoords");
    glLinkProgram(*shader_programme);

    GLint testVal;
    glGetShaderiv(*vs, GL_COMPILE_STATUS, &testVal);
    if (testVal == GL_FALSE)
    {
        char infolog[1024];
        glGetShaderInfoLog(*vs, 1024, NULL, infolog);
        printf("The vertex shader failed to compile with the error:\n");
        printf(infolog);
    }
    glGetShaderiv(*fs, GL_COMPILE_STATUS, &testVal);
    if (testVal == GL_FALSE)
    {
        char infolog[1024];
        glGetShaderInfoLog(*fs, 1024, NULL, infolog);
        printf("The fragment shader failed to compile with the error:\n");
        printf(infolog);
    }
}

int main() {
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    
    int width, height, channels;
    string path = "..\\cube_col_2.png";
    //string path = "C:\\Users\\ricar\\Documents\\3d\\project\\test\\cube_col_2.png";
    
    unsigned char* image =
        stbi_load(path.c_str(), &width, &height, &channels, 0);
    cout << width << " " << height << " " << channels << "\n";
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    if (image) {
        cout << "Image created\n";
        stbi_image_free(image);
        
    }else {
        cout << "Error creating image.\n";
    }
    
    //glBindTexture(GL_TEXTURE_2D, 0);
    
    model newObj;
    newObj.load_obj("..\\cube.obj");
    //newObj.load_obj("C:\\Users\\ricar\\Documents\\3d\\project\\test\\cube.obj");

    if (init()){
        GLFWwindow* window;
        if(create_window(&window)){

            GLuint vertexBuffer;
            GLuint texBuffer;
            GLuint vertexArrayObject = 0;

            create_object(&vertexBuffer, &texBuffer, &vertexArrayObject, newObj.triA, newObj.texA, newObj.triCount);

            const char* vertex_shader =
                "#version 330 core\n"
                "in vec3 vp;"
                "in vec2 texCoords;"
                "out vec2 v_texCoords;"
                "uniform mat4 trans;"
                "void main(){"
                "  v_texCoords = texCoords;"
                "  gl_Position = trans * vec4(vp, 1.0);"
                "}";

            const char* fragment_shader =
                "#version 330 core\n"
                "in vec2 v_texCoords;"
                "uniform sampler2D tex;"
                "out vec4 frag_colour;"
                "void main(){"
                "  frag_colour = vec4(v_texCoords, 1.0, 1.0);"
                "  frag_colour = texture(tex, v_texCoords);"
                "}";

            GLuint vs = glCreateShader(GL_VERTEX_SHADER);
            GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
            GLuint shader_programme = glCreateProgram();
            
            create_shaders(&vs, &fs, &shader_programme, vertex_shader, fragment_shader);
            glUseProgram(shader_programme);
            GLint uniTrans = glGetUniformLocation(shader_programme, "trans");
            glUniform1i(glGetUniformLocation(shader_programme, "tex"), 0);

            while (!glfwWindowShouldClose(window)) {
                do_rotate();
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                glBindVertexArray(vertexArrayObject);
                glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));
                glDrawArrays(GL_TRIANGLES, 0, newObj.triCount * 9);

                glfwSwapBuffers(window);
                glfwPollEvents();
            }
        }
        glfwDestroyWindow(window);
    }
    glfwTerminate();
    return 0;
}
c++ opengl glsl glfw stb-image
1个回答
0
投票

GL 函数(如

glTexImage2D()
)需要当前的 GL 上下文 才能工作。

将纹理创建代码移至调用glfwMakeContextCurrent()之后的某个时间,例如在

if(create_window())
块内。
    

© www.soinside.com 2019 - 2024. All rights reserved.