Не отображаются текстуры на модели?
Начал изучать OpenGL, и столкнулся с проблемой, что текстуры на модели не отображается, сплошной чёрный цвет. Полностью скопировал код из руководства, но результат тот же.
В чём может быть проблема?
Основной код:
#include<filesystem>
namespace fs = std::filesystem;
//------------------------------
#include<iostream>
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include<stb/stb_image.h>
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
#include"Texture.h"
#include"shaderClass.h"
#include"VAO.h"
#include"VBO.h"
#include"EBO.h"
const unsigned int width = 800;
const unsigned int height = 800;
// Vertices coordinates
GLfloat vertices[] =
{ // COORDINATES / COLORS / TexCoord //
-0.5f, 0.0f, 0.5f, 0.83f, 0.70f, 0.44f, 0.0f, 0.0f,
-0.5f, 0.0f, -0.5f, 0.83f, 0.70f, 0.44f, 5.0f, 0.0f,
0.5f, 0.0f, -0.5f, 0.83f, 0.70f, 0.44f, 0.0f, 0.0f,
0.5f, 0.0f, 0.5f, 0.83f, 0.70f, 0.44f, 5.0f, 0.0f,
0.0f, 0.8f, 0.0f, 0.92f, 0.86f, 0.76f, 2.5f, 5.0f
};
// Indices for vertices order
GLuint indices[] =
{
0, 1, 2,
0, 2, 3,
0, 1, 4,
1, 2, 4,
2, 3, 4,
3, 0, 4
};
int main()
{
// Initialize GLFW
glfwInit();
// Tell GLFW what version of OpenGL we are using
// In this case we are using OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Tell GLFW we are using the CORE profile
// So that means we only have the modern functions
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create a GLFWwindow object of 800 by 800 pixels, naming it "YoutubeOpenGL"
GLFWwindow* window = glfwCreateWindow(width, height, "konec", NULL, NULL);
// Error check if the window fails to create
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// Introduce the window into the current context
glfwMakeContextCurrent(window);
//Load GLAD so it configures OpenGL
gladLoadGL();
// Specify the viewport of OpenGL in the Window
// In this case the viewport goes from x = 0, y = 0, to x = 800, y = 800
glViewport(0, 0, width, height);
// Generates Shader object using shaders default.vert and default.frag
Shader shaderProgram("default.vert", "default.frag");
// Generates Vertex Array Object and binds it
VAO VAO1;
VAO1.Bind();
// Generates Vertex Buffer Object and links it to vertices
VBO VBO1(vertices, sizeof(vertices));
// Generates Element Buffer Object and links it to indices
EBO EBO1(indices, sizeof(indices));
// Links VBO attributes such as coordinates and colors to VAO
VAO1.LinkAttrib(VBO1, 0, 3, GL_FLOAT, 8 * sizeof(float), (void*)0);
VAO1.LinkAttrib(VBO1, 1, 3, GL_FLOAT, 8 * sizeof(float), (void*)(3 * sizeof(float)));
VAO1.LinkAttrib(VBO1, 2, 2, GL_FLOAT, 8 * sizeof(float), (void*)(6 * sizeof(float)));
// Unbind all to prevent accidentally modifying them
VAO1.Unbind();
VBO1.Unbind();
EBO1.Unbind();
// Gets ID of uniform called "scale"
GLuint uniID = glGetUniformLocation(shaderProgram.ID, "scale");
/*
* I'm doing this relative path thing in order to centralize all the resources into one folder and not
* duplicate them between tutorial folders. You can just copy paste the resources from the 'Resources'
* folder and then give a relative path from this folder to whatever resource you want to get to.
* Also note that this requires C++17, so go to Project Properties, C/C++, Language, and select C++17
*/
std::string parentDir = (fs::current_path().fs::path::parent_path()).string();
std::string texPath = "/Resources/1/";
// Texture
Texture brickTex((parentDir + texPath + "brick.png").c_str(), GL_TEXTURE_2D, GL_TEXTURE0, GL_RGBA, GL_UNSIGNED_BYTE);
brickTex.texUnit(shaderProgram, "tex0", 0);
// Original code from the tutorial
/*Texture brickTex("brick.png", GL_TEXTURE_2D, GL_TEXTURE0, GL_RGBA, GL_UNSIGNED_BYTE);
brickTex.texUnit(shaderProgram, "tex0", 0);*/
// Variables that help the rotation of the pyramid
float rotation = 0.0f;
double prevTime = glfwGetTime();
// Enables the Depth Buffer
glEnable(GL_DEPTH_TEST);
// Main while loop
while (!glfwWindowShouldClose(window))
{
// Specify the color of the background
glClearColor(0.07f, 0.13f, 0.17f, 1.0f);
// Clean the back buffer and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Tell OpenGL which Shader Program we want to use
shaderProgram.Activate();
// Simple timer
double crntTime = glfwGetTime();
if (crntTime - prevTime >= 1 / 60)
{
rotation += 0.5f;
prevTime = crntTime;
}
// Initializes matrices so they are not the null matrix
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 proj = glm::mat4(1.0f);
// Assigns different transformations to each matrix
model = glm::rotate(model, glm::radians(rotation), glm::vec3(0.0f, 1.0f, 0.0f));
view = glm::translate(view, glm::vec3(0.0f, -0.5f, -2.0f));
proj = glm::perspective(glm::radians(45.0f), (float)width / height, 0.1f, 100.0f);
// Outputs the matrices into the Vertex Shader
int modelLoc = glGetUniformLocation(shaderProgram.ID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
int viewLoc = glGetUniformLocation(shaderProgram.ID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
int projLoc = glGetUniformLocation(shaderProgram.ID, "proj");
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
glfwSwapInterval(1);
// Assigns a value to the uniform; NOTE: Must always be done after activating the Shader Program
glUniform1f(uniID, 0.5f);
// Binds texture so that is appears in rendering
brickTex.Bind();
// Bind the VAO so OpenGL knows to use it
VAO1.Bind();
// Draw primitives, number of indices, datatype of indices, index of indices
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(int), GL_UNSIGNED_INT, 0);
// Swap the back buffer with the front buffer
glfwSwapBuffers(window);
// Take care of all GLFW events
glfwPollEvents();
}
// Delete all the objects we've created
VAO1.Delete();
VBO1.Delete();
EBO1.Delete();
brickTex.Delete();
shaderProgram.Delete();
// Delete window before ending the program
glfwDestroyWindow(window);
// Terminate GLFW before ending the program
glfwTerminate();
return 0;
}
Код для текстур:
#include"Texture.h"
Texture::Texture(const char* image, GLenum texType, GLenum slot, GLenum format, GLenum pixelType)
{
// Assigns the type of the texture ot the texture object
type = texType;
// Stores the width, height, and the number of color channels of the image
int widthImg, heightImg, numColCh;
// Flips the image so it appears right side up
stbi_set_flip_vertically_on_load(true);
// Reads the image from a file and stores it in bytes
unsigned char* bytes = stbi_load(image, &widthImg, &heightImg, &numColCh, 0);
// Generates an OpenGL texture object
glGenTextures(1, &ID);
// Assigns the texture to a Texture Unit
glActiveTexture(slot);
glBindTexture(texType, ID);
// Configures the type of algorithm that is used to make the image smaller or bigger
glTexParameteri(texType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Configures the way the texture repeats (if it does at all)
glTexParameteri(texType, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(texType, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Extra lines in case you choose to use GL_CLAMP_TO_BORDER
// float flatColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
// glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, flatColor);
// Assigns the image to the OpenGL Texture object
glTexImage2D(texType, 0, GL_RGBA, widthImg, heightImg, 0, format, pixelType, bytes);
// Generates MipMaps
glGenerateMipmap(texType);
// Deletes the image data as it is already in the OpenGL Texture object
stbi_image_free(bytes);
// Unbinds the OpenGL Texture object so that it can't accidentally be modified
glBindTexture(texType, 0);
}
void Texture::texUnit(Shader& shader, const char* uniform, GLuint unit)
{
// Gets the location of the uniform
GLuint texUni = glGetUniformLocation(shader.ID, uniform);
// Shader needs to be activated before changing the value of a uniform
shader.Activate();
// Sets the value of the uniform
glUniform1i(texUni, unit);
}
void Texture::Bind()
{
glBindTexture(type, ID);
}
void Texture::Unbind()
{
glBindTexture(type, 0);
}
void Texture::Delete()
{
glDeleteTextures(1, &ID);
}
И ещё:
#ifndef TEXTURE_CLASS_H
#define TEXTURE_CLASS_H
#include<glad/glad.h>
#include<stb/stb_image.h>
#include"shaderClass.h"
class Texture
{
public:
GLuint ID;
GLenum type;
Texture(const char* image, GLenum texType, GLenum slot, GLenum format, GLenum pixelType);
// Assigns a texture unit to a texture
void texUnit(Shader& shader, const char* uniform, GLuint unit);
// Binds a texture
void Bind();
// Unbinds a texture
void Unbind();
// Deletes a texture
void Delete();
};
#endif
Шейдеры:
VAO
#include"VAO.h"
// Constructor that generates a VAO ID
VAO::VAO()
{
glGenVertexArrays(1, &ID);
}
// Links a VBO Attribute such as a position or color to the VAO
void VAO::LinkAttrib(VBO& VBO, GLuint layout, GLuint numComponents, GLenum type, GLsizeiptr stride, void* offset)
{
VBO.Bind();
glVertexAttribPointer(layout, numComponents, type, GL_FALSE, stride, offset);
glEnableVertexAttribArray(layout);
VBO.Unbind();
}
// Binds the VAO
void VAO::Bind()
{
glBindVertexArray(ID);
}
// Unbinds the VAO
void VAO::Unbind()
{
glBindVertexArray(0);
}
// Deletes the VAO
void VAO::Delete()
{
glDeleteVertexArrays(1, &ID);
}
#ifndef VAO_CLASS_H
#define VAO_CLASS_H
#include<glad/glad.h>
#include"VBO.h"
class VAO
{
public:
// ID reference for the Vertex Array Object
GLuint ID;
// Constructor that generates a VAO ID
VAO();
// Links a VBO Attribute such as a position or color to the VAO
void LinkAttrib(VBO& VBO, GLuint layout, GLuint numComponents, GLenum type, GLsizeiptr stride, void* offset);
// Binds the VAO
void Bind();
// Unbinds the VAO
void Unbind();
// Deletes the VAO
void Delete();
};
#endif
VBO
#include"VBO.h"
// Constructor that generates a Vertex Buffer Object and links it to vertices
VBO::VBO(GLfloat* vertices, GLsizeiptr size)
{
glGenBuffers(1, &ID);
glBindBuffer(GL_ARRAY_BUFFER, ID);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
}
// Binds the VBO
void VBO::Bind()
{
glBindBuffer(GL_ARRAY_BUFFER, ID);
}
// Unbinds the VBO
void VBO::Unbind()
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Deletes the VBO
void VBO::Delete()
{
glDeleteBuffers(1, &ID);
}
#ifndef VBO_CLASS_H
#define VBO_CLASS_H
#include<glad/glad.h>
class VBO
{
public:
// Reference ID of the Vertex Buffer Object
GLuint ID;
// Constructor that generates a Vertex Buffer Object and links it to vertices
VBO(GLfloat* vertices, GLsizeiptr size);
// Binds the VBO
void Bind();
// Unbinds the VBO
void Unbind();
// Deletes the VBO
void Delete();
};
#endif
Shaderclass:
#include"shaderClass.h"
// Reads a text file and outputs a string with everything in the text file
std::string get_file_contents(const char* filename)
{
std::ifstream in(filename, std::ios::binary);
if (in)
{
std::string contents;
in.seekg(0, std::ios::end);
contents.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());
in.close();
return(contents);
}
throw(errno);
}
// Constructor that build the Shader Program from 2 different shaders
Shader::Shader(const char* vertexFile, const char* fragmentFile)
{
// Read vertexFile and fragmentFile and store the strings
std::string vertexCode = get_file_contents(vertexFile);
std::string fragmentCode = get_file_contents(fragmentFile);
// Convert the shader source strings into character arrays
const char* vertexSource = vertexCode.c_str();
const char* fragmentSource = fragmentCode.c_str();
// Create Vertex Shader Object and get its reference
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
// Attach Vertex Shader source to the Vertex Shader Object
glShaderSource(vertexShader, 1, &vertexSource, NULL);
// Compile the Vertex Shader into machine code
glCompileShader(vertexShader);
// Checks if Shader compiled succesfully
compileErrors(vertexShader, "VERTEX");
// Create Fragment Shader Object and get its reference
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// Attach Fragment Shader source to the Fragment Shader Object
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
// Compile the Vertex Shader into machine code
glCompileShader(fragmentShader);
// Checks if Shader compiled succesfully
compileErrors(fragmentShader, "FRAGMENT");
// Create Shader Program Object and get its reference
ID = glCreateProgram();
// Attach the Vertex and Fragment Shaders to the Shader Program
glAttachShader(ID, vertexShader);
glAttachShader(ID, fragmentShader);
// Wrap-up/Link all the shaders together into the Shader Program
glLinkProgram(ID);
// Checks if Shaders linked succesfully
compileErrors(ID, "PROGRAM");
// Delete the now useless Vertex and Fragment Shader objects
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
// Activates the Shader Program
void Shader::Activate()
{
glUseProgram(ID);
}
// Deletes the Shader Program
void Shader::Delete()
{
glDeleteProgram(ID);
}
// Checks if the different Shaders have compiled properly
void Shader::compileErrors(unsigned int shader, const char* type)
{
// Stores status of compilation
GLint hasCompiled;
// Character array to store error message in
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &hasCompiled);
if (hasCompiled == GL_FALSE)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "SHADER_COMPILATION_ERROR for:" << type << "\n" << infoLog << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &hasCompiled);
if (hasCompiled == GL_FALSE)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "SHADER_LINKING_ERROR for:" << type << "\n" << infoLog << std::endl;
}
}
}