Проблема с шейдером OpenGL (ничего не отображается) - PullRequest
0 голосов
/ 17 декабря 2018

Я довольно новичок в OpenGL, и я следовал этому уроку по шейдерам https://learnopengl.com/Getting-started/Textures. Я не могу заставить мой работать, так как экран в итоге просто черный.Этот код использует glew и glut вместо glfw, как в учебнике.

Что происходит?

  • У меня есть список вершин, который я затем сохраняю в VBO, и его атрибуты связываются с помощью VAO
  • Установка атрибутов вершин в порядке 3 вершина + 3 цвета + 2 текс-координаты
  • glEnable(GL_TEXTURE_2D);
  • удостоверился, что GL_TEXTURE0 активен, поэтому следующий вызов к
  • glBindTexture(GL_TEXTURE_2D, texture) связан с этим текстурным блоком.
  • Я загружаю текстуру с помощью stbi_load function
  • Загружаю текстуру с glTexImage2D с параметрами (width, height, texture_data), которые были переданы в stbi_load заранее как указатели, так чтозагружает их.
  • Создание вершинного шейдера, присоединение источника (в VertexShaders.h), компиляция шейдера, ошибки печати шейдера (не отображаются)
  • Создание фрагментного шейдера, подключение источника (в FragmentShaders.h), скомпилировать шейдер, вывести ошибки шейдера (не отображаются)
  • Создать программу шейдера (ourShader), присоединить вершинный шейдер и фрагментный шейдер.Соедините программу «ourShader» и снова напечатайте ошибки (не отображаются).

Замечания:

  • Проекция выполняется с gluPerspective, около плоскости отсечения 0.1 и далеко1000 (поскольку он смотрит вниз -z, он не должен обрезать объект, я также перевожу объект следующим образом: glTranslatef(0, 0, -10))
  • Текстура загружается (файл существует, он генерирует байтовые данные, когда я загружаю егочто касается изображения текстуры, то это (512x512) https://github.com/JoeyDeVries/LearnOpenGL/blob/master/resources/textures/container.jpg

Это обратный вызов myDisplay:

void myDisplay(void)
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glEnable(GL_TEXTURE_2D);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
glTranslatef(0, 0, -10);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glUseProgram(ourShader);
glBindVertexArray(VAO); 
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glutSwapBuffers();
}

Основная настройка

int main(){
//glut initialization stuff...left this out



float vertices[] = {
        // positions          // colors           // texture coords
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // top right
         0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // bottom left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f    // top left 
    };
    float texCoords[] = {
    0.0f, 0.0f,  // lower-left corner  
    1.0f, 0.0f,  // lower-right corner
    0.5f, 1.0f   // top-center corner
    };

    unsigned int indices[] = {
       0, 1, 3, // first triangle
       1, 2, 3  // second triangle
    };

    //frameBuffer
    glGenBuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR: Framebuffer not bound" << std::endl;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    //glDeleteFramebuffers(1, &fbo);


    //VAO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

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

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Vertex Attributes 
    glEnableVertexAttribArray(0); //pozicija
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(0));
    glEnableVertexAttribArray(1); //boja
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2); //boja
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, texture);

    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);

    std::string path = "C:\\Projects\\Myproj\\container.jpg";
    bool success = loadTexture(path,texture_data,&tex_width, &tex_height, &nchannels);
    if (success) 
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else 
    {
        std::cout << "ERROR::STBI::FAILED TO LOAD TEXTURE" << std::endl;
    }

    stbi_image_free(texture_data);

    int success_f;
    char infoLog[512];

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    getShaderStatus(vertexShader, &success_f, infoLog);

    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    getShaderStatus(fragmentShader, &success_f, infoLog);


    ourShader = glCreateProgram();
    glAttachShader(ourShader, vertexShader);
    glAttachShader(ourShader, fragmentShader);
    glLinkProgram(ourShader);
    getShaderStatus(ourShader, &success_f, infoLog);

    glUseProgram(ourShader);
    glUniform1i(glGetUniformLocation(ourShader, "ourTexture"), 0);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    glutMainLoop();
}

VertexШейдер

const char* vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 aPos;\n"
"layout(location = 1) in vec3 aColor;\n"
"layout(location = 2) in vec2 aTexCoord;\n"
"out vec3 ourColor;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n"
"ourColor = aColor;\n"
"TexCoord = aTexCoord;\n"
"}\n";

Фрагментный шейдер

const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
"FragColor = texture(ourTexture, TexCoord);\n"
"}\n";

Журнал обновлений - решено

  • Не нужно glEnable (GL_TEXTURE_2D) при реализациишейдер
  • Преобразование проекции, вида и модели, перейдите внутрь шейдера, используйте

    glm::projection glm::lookat

  • Включить атрибуты (цвет, текстура)перед рендерингом

  • Freeglut поддержка OpenGL API (> = 3.2)

glutInitContextVersion(3, 3); glutInitContextProfile(GLUT_CORE_PROFILE);

Окончательный код here: [https://pastebin.com/D8DgPqaT]

Психоделические шейдеры: [https://pastebin.com/vtJ3Cr6i]

1 Ответ

0 голосов
/ 17 декабря 2018

glEnable(GL_TEXTURE_2D) не требуется при использовании шейдера, потому что погода используется или не используется в текстуре (фрагмент).
Ваш код шейдера определяет, применяется ли текстура илине.glEnable(GL_TEXTURE_2D) предназначен для использования устаревшего конвейера с фиксированными функциями , без только шейдера.

Также используется стек матриц с фиксированными функциями (glMatrixMode, glLoadIdentity, gluPerspective,...) бесполезно.Вы должны использовать Uniform переменных (типа mat4).Эти функции изменяют матрицы в стеке матриц с фиксированными функциями.Эти матрицы применяются к координатам вершин с фиксированной функцией, которые устанавливаются glVertex или glVertexPointer, но только в случае отсутствия кода шейдера.
Если имеетсяВ шейдере вы должны сами выполнять преобразования матриц.
В GLSL существуют встроенные формы, такие как gl_ModelViewMatrix, gl_ProjectionMatrix или gl_ModelViewProjectionMatrix, которые позволяют вам получать доступ к матрицам в стеке матриц фиксированных функций.Но эта униформа тоже устарела и больше не доступна в GLSL #version 330 core.

. Напишите шейдер с двумя униформами mat4 u_proj и mat4 u_view.Преобразуйте координату вершины с помощью кода шейдера.

#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

uniform mat4 u_proj;
uniform mat4 u_view;

void main()
{
    gl_Position = u_proj * u_view * vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;
}

Получить Однородные местоположения после связывания программы:

GLint proj_loc = glGetUniformLocation(ourShader, "u_proj");
GLint view_loc = glGetUniformLocation(ourShader, "u_view");

Рассчитать матрицу проекции и матрицу вида.Я рекомендую использовать библиотеку OpenGL Matmatics (GLM) , которая предназначена для выполнения взаимосвязанных вычислений OpenGL и GLSL и основана на OpenGL Shading Language (GLSL) .См. Также glm::perspective и glm::lookAt:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

glm::mat4 proj = glm::perspective(glm::radians(fov_degrees)), aspect, near, far);
glm::mat4 view = glm::lookAt(eye, target, up);

Установите униформу после установки программы (glUseProgram) glUniformMatrix4fv:

glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(proj));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(view));

Просмотр кода [https://pastebin.com/KWDxcEen] и шейдеров [https://pastebin.com/yq3rQEga]

Если шейдер был успешно скомпилирован, необходимо проверить glGetShaderiv

glGetShaderiv(shader_ID, GL_COMPILE_STATUS, &status);

в сравнении, чтобы проверить, была ли программа успешно связана, что должно бытьпроверяется glGetProgramiv

glGetProgramiv(program_ID, GL_LINK_STATUS, success_f);

Координаты текстуры массива состоят из кортежей размером 2 (u, v):

glVertexAttribPointer(2,
    2,                 // <---- 2 instead of 3 
    GL_FLOAT,
    GL_FALSE,
    8 * sizeof(GLfloat),
    (void*)(6 * sizeof(GLfloat))
); 

Третий параметриз glDrawArrays - количество вершин, но не количество примитивов:

glDrawArrays(GL_TRIANGLES, 0, 6); // <---- 6 instead of 2

2-й параметр loadTexture должен быть выходным параметром.Это должна быть ссылка (unsigned char *& buff):

bool loadTexture(
   const std::string &filename,
   unsigned char*& buff,           // < ---- unsigned char*&
   int* w, int* h, int* nc);

Состояние, если атрибут вершины включен или отключен, сохраняется в Vertex Array Object .Нет необходимости делать это снова в функции дисплея:

void myDisplay(void) 
{

    // ....

    glBindVertexArray(VAO);

    // unecessary:
    //glEnableVertexAttribArray(0);
    //glEnableVertexAttribArray(1); 
    //glEnableVertexAttribArray(2); 

Наконец, я рекомендую добавить [glutPostRedisplay()] (https://www.opengl.org/resources/libraries/glut/spec3/node20.html) вызов функции дисплея (myDisplay), для постоянного обновления сцены.

...