我正在学习opengl,并按照https://learnopengl.com/In-Practice/2D-Game/Breakout上的2D游戏教程进行操作,一旦进入到应该在屏幕上显示某些内容的部分,就什么也没画。经过几天的挫败,我最终得以将问题缩小到在程序停止之前调用的Shader类析构函数。但是,当我将所有绘图代码放在一个文件中时,没有调用析构函数,并且一切都绘制良好。我最近通过在资源管理器中从getter返回指针来解决析构函数问题。但是,它仍然不会绘制。我的代码在这里:
Main.cpp
#include <iostream>
#include <GL/glew.h>
#include <SFML/Graphics.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "Game.hpp"
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "Test", sf::Style::Default, sf::ContextSettings(3, 3));
if (!glewInit() == GLEW_OK) {
std::cout << "Failed to initialize GLEW!";
return -1;
}
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Game::Game game(800.f, 600.f);
game.__init__();
sf::Clock clock;
float deltaTime = 0.f;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
}
glClearColor(0.1f, 0.1f, 0.1f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
game.render();
window.display();
}
Resource::ResourceManager::__delete__();
return 0;
}
Game.hpp
#pragma once
#include "Resources/ResourceManager.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <map>
namespace Game {
enum class GameState {
TITLE,
ACTIVE,
PAUSED,
WIN,
LOOSE
};
class Game
{
public:
Game(float w_width, float w_height);
~Game();
void __init__();
void setKey(sf::Keyboard::Key key, bool isPressed);
void update();
void render();
private:
GLuint _vao;
float _w_width;
float _w_height;
std::map<sf::Keyboard::Key, bool> _key_states;
};
};
Game.cpp
#include "Game.hpp"
namespace Game {
Game::Game(float w_width, float w_height)
{
_w_width = w_width;
_w_height = w_height;
}
Game::~Game()
{
}
void Game::__init__()
{
glm::mat4 Projection = glm::ortho(0.f, _w_width, _w_height, 0.f, -1.f, 1.f);
glm::mat4 Model = glm::scale(glm::mat4(1.f), glm::vec3(100.f, 70.f, 1.f));
Resource::ResourceManager::addShader(0, "Shaders/simpleVertexShader.glsl", "Shaders/simpleFragmentShader.glsl");
Resource::ResourceManager::addTexture(0, "Textures/block.png");
Resource::ResourceManager::addTexture(1, "Textures/block_solid.png");
Resource::ResourceManager::addTexture(2, "Textures/background.jpg");
Resource::Shader* main_shader = Resource::ResourceManager::getShader(0);
main_shader->setMat4("Projection", Projection);
main_shader->setMat4("Model", Model);
main_shader->setVec3("Color", glm::vec3(0.1, 0.8, 0.1));
glGenVertexArrays(1, &_vao);
GLfloat vertex_data[] = {
0.f, 0.f, 0.f, 0.f,
1.f, 0.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 1.f,
0.f, 1.f, 0.f, 1.f,
0.f, 0.f, 0.f, 0.f
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
glBindVertexArray(_vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Game::setKey(sf::Keyboard::Key key, bool isPressed)
{
_key_states[key] = isPressed;
}
void Game::update()
{
}
void Game::render()
{
Resource::Texture* texture = Resource::ResourceManager::getTexture(0);
Resource::Shader* shader = Resource::ResourceManager::getShader(0);
texture->bind();
shader->use();
glBindVertexArray(_vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
};
ResourceManager.hpp
#pragma once
#include <unordered_map>
#include <fstream>
#include <string>
#include <iostream>
#include "Shader.hpp"
#include "Texture.hpp"
namespace Resource {
class ResourceManager {
public:
static void addShader(uint8_t id, std::string vertexShaderSource, std::string fragmentShaderSource);
static void addTexture(uint8_t id, std::string imageSource);
static Shader* getShader(uint8_t id);
static Texture* getTexture(uint8_t id);
static void __delete__();
private:
ResourceManager() {}
static std::string _loadShaderFromFile(std::string shaderSource);
public:
static std::unordered_map<uint8_t, Shader*> _shaders;
static std::unordered_map<uint8_t, Texture*> _textures;
};
};
ResourceManager.cpp
#include "ResourceManager.hpp"
namespace Resource {
std::unordered_map<uint8_t, Shader*> ResourceManager::_shaders;
std::unordered_map<uint8_t, Texture*> ResourceManager::_textures;
void ResourceManager::addShader(uint8_t id, std::string vertexShaderSource, std::string fragmentShaderSource)
{
_shaders[id] = new Shader(_loadShaderFromFile(vertexShaderSource).c_str(), _loadShaderFromFile(fragmentShaderSource).c_str());
}
void ResourceManager::addTexture(uint8_t id, std::string imageSource)
{
_textures[id] = new Texture(imageSource);
}
Shader* ResourceManager::getShader(uint8_t id)
{
return _shaders[id];
}
Texture* ResourceManager::getTexture(uint8_t id)
{
return _textures[id];
}
void ResourceManager::__delete__()
{
for (auto iter : _shaders) {
delete iter.second;
}
for (auto iter : _textures) {
delete iter.second;
}
}
std::string ResourceManager::_loadShaderFromFile(std::string shaderSource)
{
std::ifstream file(shaderSource);
if (!file.is_open()) {
std::cout << "Failed to load shader: " << shaderSource << "!" << std::endl;
return "";
}
std::string line;
std::string lines;
while (std::getline(file, line)) {
lines += line + '\n';
}
return lines;
}
};
Shader.hpp
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
namespace Resource {
class Shader {
public:
Shader(const char* vertexShaderSource, const char* fragmentShaderSource);
Shader();
~Shader();
void use();
void setMat4(const char* location, glm::mat4 matrix);
void setVec3(const char* location, glm::vec3 vector);
void setVec4(const char* location, glm::vec4 vector);
void printID();
Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
private:
GLuint _id;
};
};
Shader.cpp
#include "Shader.hpp"
#include <iostream>
namespace Resource {
Shader::Shader(const char* vertexShaderSource, const char* fragmentShaderSource)
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
_id = glCreateProgram();
glAttachShader(_id, vertexShader);
glAttachShader(_id, fragmentShader);
glLinkProgram(_id);
glDetachShader(_id, vertexShader);
glDetachShader(_id, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
Shader::Shader()
{
}
Shader::~Shader()
{
glDeleteProgram(_id);
}
void Shader::use()
{
glUseProgram(_id);
}
void Shader::setMat4(const char* location, glm::mat4 matrix)
{
glUniformMatrix4fv(glGetUniformLocation(_id, location), 1, GL_FALSE, &matrix[0][0]);
}
void Shader::setVec3(const char* location, glm::vec3 vector)
{
glUniform3fv(glGetUniformLocation(_id, location), 1, &vector[0]);
}
void Shader::setVec4(const char* location, glm::vec4 vector)
{
glUniform4fv(glGetUniformLocation(_id, location), 1, &vector[0]);
}
void Shader::printID()
{
std::cout << _id << std::endl;
}
};
Texture.hpp
#pragma once
#include <GL/glew.h>
#include <SFML/Graphics/Image.hpp>
namespace Resource {
class Texture {
public:
Texture(std::string image_src);
Texture();
~Texture();
void bind();
Texture(const Texture&) = delete;
Texture& operator=(const Texture&) = delete;
private:
GLuint _id;
};
}
Texture.cpp
#include "Texture.hpp"
namespace Resource {
Texture::Texture(std::string image_src)
{
glGenTextures(1, &_id);
bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
sf::Image texture;
texture.loadFromFile(image_src);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.getSize().x, texture.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.getPixelsPtr());
}
Texture::Texture()
{
}
Texture::~Texture()
{
glDeleteTextures(1, &_id);
}
void Texture::bind()
{
glBindTexture(GL_TEXTURE_2D, _id);
}
};
我对c ++还是有些陌生,因此如果可以做出任何明显的改进,请提前抱歉。
答案 0 :(得分:1)
glUniform*
指定当前程序对象的统一变量的值。
这意味着您必须调用glUseProgram
来将propper程序对象安装为当前渲染状态的一部分,否则您可以通过glUniform*
来设置统一值。
这意味着您必须安装main_shader
,因为您必须在方法Game::__init__
中设置制服的值才能解决此问题:
main_shader->use();
main_shader->setMat4("Projection", Projection);
main_shader->setMat4("Model", Model);
main_shader->setVec3("Color", glm::vec3(0.1, 0.8, 0.1));
或者,您可以使用glProgramUniform*
(自OpenGL 4.1起),它允许您指定应将值设置为的程序对象。
第二个问题是GL_ARRAY_BUFFER
不是glDrawArrays
的有效枚举常量。如果您通过glGetError
检查OpenGL错误,则会得到GL_INVALID_ENUM
错误。
您必须使用GL_TRIANGLES
:
glDrawArrays(GL_TRIANGLES, 0, 6);