OpenGL纹理不会绘制
Posted
技术标签:
【中文标题】OpenGL纹理不会绘制【英文标题】:OpenGL Texture won't draw 【发布时间】:2016-12-17 15:06:22 【问题描述】:我按照 opengl 教程创建了一个更加面向对象的版本。 我想绘制一个纹理,但唯一有效的是 glClearColor 命令。我不知道为什么它不起作用。我什么都试过了。代码如下:
Sprite.cpp
#include "Sprite.h"
#include <SOIL\SOIL.h>
Sprite::Sprite(const char* texturePath, float x, float y, GLuint width, GLuint height)
Sprite::init(texturePath, x, y, width, height);
Sprite::~Sprite()
void Sprite::init(const char* texturePath, float x, float y, GLuint width, GLuint height)
Logger::info("Initializing Sprite...");
_x = x;
_y = y;
_width = width;
_height = height;
// Build and compile our shader program
// Set up vertex data (and buffer(s)) and attribute pointers
const GLfloat vertices[] =
// Positions // Colors // Texture Coords
_x, _y, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
_x, _y + _height, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
_x + _width, _y, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
_y + _width, _y + _height, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
;
/*GLfloat 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
;
*/
constexpr GLuint indices[] = // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
;
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);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// TexCoord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(0); // Unbind VAO
// Load and create a texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // All upcoming GL_TEXTURE_2D operations now have effect on this texture object
// Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT (usually basic wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Load image, create texture and generate mipmaps
int twidth, theight;
unsigned char* image = SOIL_load_image(texturePath, &twidth, &theight, 0, SOIL_LOAD_RGB);
if (image == 0)
Logger::fatalError("Image is null!");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture.
//_texture2 = texture2;
Logger::info("Sprite initialization succesful!");
void Sprite::draw(Shader *shader)
/* glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _texture1);
glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture1"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _texture2);
glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture2"), 1);
*/
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Bind Texture
glBindTexture(GL_TEXTURE_2D, texture);
if (texture == 0)
Logger::fatalError("texture1 is null");
if (shader == 0)
Logger::fatalError("shader is null");
if (VAO == 0)
Logger::fatalError("VAO is null");
// Activate shader
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, texture);
//glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture"), 0);
//shader->Use();
// Draw container
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
Shader.cpp
#include "Shader.h"
Shader::Shader(const GLchar* vertexShaderPath, const GLchar* fragmentShaderPath)
std::string vertexCode;
std::string fragmentCode;
std::ifstream vertexShaderFile;
std::ifstream fragmentShaderFile;
// ensures ifstream objects can throw exceptions:
vertexShaderFile.exceptions(std::ifstream::badbit);
fragmentShaderFile.exceptions(std::ifstream::badbit);
try
// Open files
vertexShaderFile.open(vertexShaderPath);
fragmentShaderFile.open(fragmentShaderPath);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vertexShaderFile.rdbuf();
fShaderStream << fragmentShaderFile.rdbuf();
// close file handlers
vertexShaderFile.close();
fragmentShaderFile.close();
// Convert stream into GLchar array
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
catch (std::ifstream::failure e)
Logger::info("ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ");
const GLchar* vertexShaderCode = vertexCode.c_str();
const GLchar* fragmentShaderCode = fragmentCode.c_str();
Shader::compileShaders(vertexShaderCode, fragmentShaderCode);
void Shader::compileShaders(const GLchar* vertexShaderCode, const GLchar* fragmentShaderCode)
Logger::info("Compiling Shaders...");
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertexShaderCode, NULL);
glCompileShader(vertex);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
Logger::fatalError("ERROR::SHADER::VERTEX::COMPILATION_FAILED");
;
// Similiar for Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragmentShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
Logger::fatalError("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED");
;
// Shader Program
this->_programID = glCreateProgram();
glAttachShader(this->_programID, vertex);
glAttachShader(this->_programID, fragment);
glLinkProgram(this->_programID);
// Print linking errors if any
glGetProgramiv(this->_programID, GL_LINK_STATUS, &success);
if (!success)
glGetProgramInfoLog(this->_programID, 512, NULL, infoLog);
Logger::fatalError("ERROR::SHADER::PROGRAM::LINKING_FAILED");
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
Logger::info("Shader compilation succesful!");
void Shader::Use()
glUseProgram(this->_programID);
Shader::~Shader()
MainGame.cpp
#include "MainGame.h"
MainGame::MainGame()
_window = nullptr;
_screenWidth = 1024;
_screenHeight = 768;
_gameState = GameState::PLAY;
MainGame::~MainGame()
void MainGame::run()
initSystems();
gameLoop();
void MainGame::initSystems()
//Initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
//Create Window
_window = SDL_CreateWindow("Half Life 3", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _screenWidth, _screenHeight, SDL_WINDOW_OPENGL);
//glViewport(0, 0, _screenWidth, _screenHeight);
if (_window == nullptr)
Logger::fatalError("SDL Window could not be created!");
SDL_GLContext glContext = SDL_GL_CreateContext(_window);
if (glContext == nullptr)
Logger::fatalError("SDL_GL context could not be created");
GLenum error = glewInit();
if (error != GLEW_OK)
Logger::fatalError("Could not initialize glew!");
Logger::info("Initialization succesful");
//Double Buffer: Smooth, no flickering
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
glClearColor(0, 0, 1, 1.0);
Shader shader("Shaders/Shader.vert", "Shaders/Shader.frag");
_shader = &shader;
Sprite sprite("Textures/wall.jpg", 0.5f, 0.5f, 100, 100);
_texture = &sprite;
void MainGame::gameLoop()
while (_gameState != GameState::EXIT)
processInput();
drawGame();
void MainGame::processInput()
SDL_Event evnt;
while (SDL_PollEvent(&evnt) == true)
switch (evnt.type)
case SDL_QUIT:
_gameState = GameState::EXIT;
// std::cout << "Quit Event" << std::endl;
break;
case SDL_MOUSEMOTION:
// std::cout << "x: " << evnt.motion.x << " y: " << evnt.motion.y << std::endl;
break;
void MainGame::drawGame()
// glClearDepth(1.0);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//_shader->Use();
// Bind Textures using texture units
_texture->draw(_shader);
// Swap the screen buffers
SDL_GL_SwapWindow(_window);
片段着色器:
#version 330 core
in vec3 ourColor;
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture;
void main()
color = texture(ourTexture, TexCoord);
顶点着色器:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
gl_Position = vec4(position, 1.0f);
ourColor = color;
TexCoord = texCoord;
控制台日志:
Initialization succesful
Compiling Shaders...
Shader compilation succesful!
Initializing Sprite...
Sprite initialization succesful!
您看,一切都正确加载并正确初始化并且没有错误。它仍然只显示 glClearColor。 怎么了?
【问题讨论】:
在您的 sprite.cpp 中,//Activate shader
注释下的行是否应该被注释掉?
@James Bean 是的,但是“// Draw container”下的行没有被注释掉
首先,正如@JamesBean 已经指出的那样,您正在尝试在没有激活任何程序的情况下进行绘制。其次,您的shader
和sprite
对象只是initSystems
中的局部变量,获取它们的地址并将其存储以备后用对您没有帮助。
你还没有设置投影矩阵。
@derhass 谢谢,现在可以了:D
【参考方案1】:
空白屏幕效果在 Open GL 图形中很常见。这意味着视图、相机、照明或其他东西的设置方式使您什么也看不见。
解决方法是注释掉你所有的代码,除了明确哪些有效(这是重要的第一步,你至少得到了 Open GL 输出)。然后添加代码,直到您在屏幕上看到一些东西,anything。
然后,您可以将 anything ) 逐渐转移到您想看到的内容,方法是重新注释代码,如果返回到空白屏幕效果,请再次注释掉。
【讨论】:
以上是关于OpenGL纹理不会绘制的主要内容,如果未能解决你的问题,请参考以下文章
使用 OpenGL / LWJGL 绘制纹理四边形使用旧纹理