Черный экран при рендеринге текстуры PNG в openGL

При попытке визуализировать PNG-файл как текстуру в OpenGL я рисую только черный экран.

Если я передам данные координат текса прямо в цвет во фрагментном шейдере, я смогу визуализировать закрашенный куб.

Я также проверил это:

[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;
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для работы функций GL (например, glTexImage2D()) требуется текущий GL-контекст.

Переместите код создания текстуры куда-нибудь после вызова glfwMakeContextCurrent(), например, внутри блока if (create_window()).

Другие вопросы по теме