OpenGL批处理渲染器在清除颜色后显示空白窗口,且没有OpenGL错误
我正在做一个项目,想实现一个批处理渲染器。
我尝试开启调试模式,但没有收到任何OpenGL信息,更别说错误信息了。我也尝试使用 RenderDoc 在程序运行时对其进行检查,但没有成功,因为我对RenderDoc中程序应该的样子不是很熟悉。就我从Visual Studio调试器看到的情况来看,我的顶点似乎被正确打包,我调用的任何函数都没有返回OpenGL错误。
这是我的代码库;它可以运行并显示一个蓝色窗口。它应该显示这个窗口以及屏幕中央的一个红色矩形,但我没有看到那个矩形。
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <string>
#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
#include <array>
//////////////////
// BEGIN SHADER //
//////////////////
class Shader
{
public:
Shader();
~Shader();
void use();
void setUniformMat4(const std::string name, glm::mat4 value);
private:
uint32_t m_rendererID;
};
Shader::Shader()
{
const char* vShaderCode = R"END(
#version 450 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
layout(location = 2) in vec2 a_TexCoord;
layout(location = 3) in float a_TexIndex;
layout(location = 4) in float a_TilingFactor;
uniform mat4 u_ViewProjection;
struct VertexOutput
{
vec4 Color;
vec2 TexCoord;
float TexIndex;
float TilingFactor;
};
layout (location = 0) out VertexOutput Output;
void main()
{
Output.Color = a_Color;
Output.TexCoord = a_TexCoord;
Output.TexIndex = a_TexIndex;
Output.TilingFactor = a_TilingFactor;
gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
}
)END";
const char* fShaderCode = R"END(
#version 450 core
layout(location = 0) out vec4 color;
struct VertexOutput
{
vec4 Color;
vec2 TexCoord;
float TexIndex;
float TilingFactor;
};
layout (location = 0) in VertexOutput Input;
layout (binding = 0) uniform sampler2D u_Textures[32];
void main()
{
vec4 texColor = Input.Color;
switch(int(Input.TexIndex))
{
case 0: texColor *= texture(u_Textures[ 0], Input.TexCoord * Input.TilingFactor); break;
case 1: texColor *= texture(u_Textures[ 1], Input.TexCoord * Input.TilingFactor); break;
case 2: texColor *= texture(u_Textures[ 2], Input.TexCoord * Input.TilingFactor); break;
case 3: texColor *= texture(u_Textures[ 3], Input.TexCoord * Input.TilingFactor); break;
case 4: texColor *= texture(u_Textures[ 4], Input.TexCoord * Input.TilingFactor); break;
case 5: texColor *= texture(u_Textures[ 5], Input.TexCoord * Input.TilingFactor); break;
case 6: texColor *= texture(u_Textures[ 6], Input.TexCoord * Input.TilingFactor); break;
case 7: texColor *= texture(u_Textures[ 7], Input.TexCoord * Input.TilingFactor); break;
case 8: texColor *= texture(u_Textures[ 8], Input.TexCoord * Input.TilingFactor); break;
case 9: texColor *= texture(u_Textures[ 9], Input.TexCoord * Input.TilingFactor); break;
case 10: texColor *= texture(u_Textures[10], Input.TexCoord * Input.TilingFactor); break;
case 11: texColor *= texture(u_Textures[11], Input.TexCoord * Input.TilingFactor); break;
case 12: texColor *= texture(u_Textures[12], Input.TexCoord * Input.TilingFactor); break;
case 13: texColor *= texture(u_Textures[13], Input.TexCoord * Input.TilingFactor); break;
case 14: texColor *= texture(u_Textures[14], Input.TexCoord * Input.TilingFactor); break;
case 15: texColor *= texture(u_Textures[15], Input.TexCoord * Input.TilingFactor); break;
case 16: texColor *= texture(u_Textures[16], Input.TexCoord * Input.TilingFactor); break;
case 17: texColor *= texture(u_Textures[17], Input.TexCoord * Input.TilingFactor); break;
case 18: texColor *= texture(u_Textures[18], Input.TexCoord * Input.TilingFactor); break;
case 19: texColor *= texture(u_Textures[19], Input.TexCoord * Input.TilingFactor); break;
case 20: texColor *= texture(u_Textures[20], Input.TexCoord * Input.TilingFactor); break;
case 21: texColor *= texture(u_Textures[21], Input.TexCoord * Input.TilingFactor); break;
case 22: texColor *= texture(u_Textures[22], Input.TexCoord * Input.TilingFactor); break;
case 23: texColor *= texture(u_Textures[23], Input.TexCoord * Input.TilingFactor); break;
case 24: texColor *= texture(u_Textures[24], Input.TexCoord * Input.TilingFactor); break;
case 25: texColor *= texture(u_Textures[25], Input.TexCoord * Input.TilingFactor); break;
case 26: texColor *= texture(u_Textures[26], Input.TexCoord * Input.TilingFactor); break;
case 27: texColor *= texture(u_Textures[27], Input.TexCoord * Input.TilingFactor); break;
case 28: texColor *= texture(u_Textures[28], Input.TexCoord * Input.TilingFactor); break;
case 29: texColor *= texture(u_Textures[29], Input.TexCoord * Input.TilingFactor); break;
case 30: texColor *= texture(u_Textures[30], Input.TexCoord * Input.TilingFactor); break;
case 31: texColor *= texture(u_Textures[31], Input.TexCoord * Input.TilingFactor); break;
}
color = texColor;
}
)END";
unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
m_rendererID = glCreateProgram();
glAttachShader(m_rendererID, vertex);
glAttachShader(m_rendererID, fragment);
glLinkProgram(m_rendererID);
glDeleteShader(vertex);
glDeleteShader(fragment);
}
Shader::~Shader()
{
glDeleteProgram(m_rendererID);
}
void Shader::use()
{
glUseProgram(m_rendererID);
}
void Shader::setUniformMat4(const std::string name, glm::mat4 value)
{
glUniformMatrix4fv(glGetUniformLocation(m_rendererID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}
///////////////////
// BEGIN TEXTURE //
///////////////////
class Texture
{
public:
Texture(uint32_t width, uint32_t height);
~Texture();
uint32_t getWidth() const { return m_width; }
uint32_t getHeight() const { return m_height; }
void setData(void* data, uint32_t size);
void bind(uint32_t slot = 0) const;
bool operator==(const Texture& other) const
{
return m_rendererID == ((Texture&)other).m_rendererID;
}
private:
std::string m_path;
uint32_t m_width, m_height;
uint32_t m_rendererID;
GLenum m_internalFormat, m_dataFormat;
};
Texture::Texture(uint32_t width, uint32_t height)
: m_width(width), m_height(height)
{
m_internalFormat = GL_RGBA8;
m_dataFormat = GL_RGBA;
glCreateTextures(GL_TEXTURE_2D, 1, &m_rendererID);
glTextureStorage2D(m_rendererID, 1, m_internalFormat, m_width, m_height);
glTextureParameteri(m_rendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(m_rendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_rendererID);
}
void Texture::setData(void* data, uint32_t size)
{
uint32_t bpp = m_dataFormat == GL_RGBA ? 4 : 3;
glTextureSubImage2D(m_rendererID, 0, 0, 0, m_width, m_height, m_dataFormat, GL_UNSIGNED_BYTE, data);
}
void Texture::bind(uint32_t slot) const
{
glBindTextureUnit(slot, m_rendererID);
}
//////////
// CODE //
//////////
const uint32_t RendererMaxQuads = 10000;
const uint32_t RendererMaxIndices = 6 * RendererMaxQuads;
const uint32_t RendererMaxVertexCount = 4 * RendererMaxQuads;
const uint32_t RendererMaxTextureSlots = 32;
struct Vertex {
glm::vec3 Position;
glm::vec4 Color;
glm::vec2 TexCoord;
float TexIndex;
float TilingFactor;
Vertex()
{
Position = { 0, 0, 0 };
Color = { 0,0,0,1 };
TexCoord = { 0, 0 };
TexIndex = 0;
TilingFactor = 1;
}
Vertex(glm::vec3 pos, glm::vec4 color, glm::vec2 texCoord, float texIndex, float tilingFactor)
{
Position = pos;
Color = color;
TexCoord = texCoord;
TexIndex = texIndex;
TilingFactor = tilingFactor;
}
};
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
Shader* TextureShader = nullptr;
Texture* WhiteTexture = nullptr;
std::array<Texture*, RendererMaxTextureSlots> TextureSlots;
std::array<Vertex, RendererMaxVertexCount> Verticies;
GLuint VAO = 0;
GLuint VBO = 0;
GLuint IndexBuffer = 0;
uint32_t VertexCount = 0;
uint32_t IndexCount = 0;
uint32_t TextureSlotIndex = 0;
void Flush()
{
if (VertexCount == 0)
{
// Nothing to draw
return;
}
TextureShader->use();
TextureShader->setUniformMat4("u_ViewProjection", glm::ortho(0, 800, 0, 600, -1, 1));
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, VertexCount * sizeof(Vertex), &Verticies);
// Bind textures
for (uint32_t i = 0; i < TextureSlotIndex; i++)
TextureSlots[i]->bind(i);
glDrawElements(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr);
}
void DrawQuad(glm::vec3 position, glm::vec2 size, glm::vec4 color)
{
if (VertexCount >= RendererMaxVertexCount - 4)
{
Flush();
VertexCount = 0;
IndexCount = 0;
TextureSlotIndex = 1; // 0 = WhiteTexture
}
// Add verticies
Verticies[VertexCount++] = {
position + glm::vec3(size.x, size.y, 0.0f), // Top Right
color,
{1, 1}, // Top Right
0, // White Texture
1 // No Tiling
};
Verticies[VertexCount++] = {
position + glm::vec3(-size.x, size.y, 0.0f), // Top Left
color,
{0, 1}, // Top Left
0, // White Texture
1 // No Tiling
};
Verticies[VertexCount++] = {
position + glm::vec3(size.x, -size.y, 0.0f), // Bottom Right
color,
{1, 0}, // Bottom Right
0, // White Texture
1 // No Tiling
};
Verticies[VertexCount++] = {
position + glm::vec3(-size.x, -size.y, 0.0f), // Bottom Left
color,
{0, 0}, // Bottom Left
0, // White Texture
1 // No Tiling
};
}
int main()
{
// Start OpenGL context and OS window using the GLFW helper library.
if (!glfwInit()) {
std::cout << "ERROR: could not start GLFW" << std::endl;
return -1;
}
// Request an OpenGL 4.5, core, context from GLFW.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create a window on the operating system, then tie the OpenGL context to it.
GLFWwindow* Window = glfwCreateWindow(800, 600, "windowTitle", NULL, NULL);
if (!Window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(Window);
glfwSetFramebufferSizeCallback(Window, framebuffer_size_callback);
// Start Glad, so we can call OpenGL functions.
if (gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) == 0) {
return -1;
}
glEnable(GL_DEPTH_TEST);
glCreateVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glCreateBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * RendererMaxVertexCount, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Color));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexCoord));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexIndex));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TilingFactor));
TextureShader = new Shader();
WhiteTexture = new Texture(1, 1);
uint32_t whiteTextureData = 0xffffffff;
WhiteTexture->setData(&whiteTextureData, sizeof(uint32_t));
TextureSlots[0] = WhiteTexture;
uint32_t* quadIndices = new uint32_t[RendererMaxIndices];
uint32_t offset = 0;
for (uint32_t i = 0; i < RendererMaxIndices; i += 6)
{
quadIndices[i + 0] = offset + 0;
quadIndices[i + 1] = offset + 2;
quadIndices[i + 2] = offset + 1;
quadIndices[i + 3] = offset + 1;
quadIndices[i + 4] = offset + 2;
quadIndices[i + 5] = offset + 3;
offset += 4;
}
glCreateBuffers(1, &IndexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, IndexBuffer);
glBufferData(GL_ARRAY_BUFFER, RendererMaxIndices * sizeof(uint32_t), quadIndices, GL_STATIC_DRAW);
delete[] quadIndices;
glClearColor( 0.0f, 0.0f, 1.0f, 1.0f);
while (!glfwWindowShouldClose(Window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
VertexCount = 0;
IndexCount = 0;
TextureSlotIndex = 1; // 0 = WhiteTexture
DrawQuad({ 0.0f, 0.0f, 0.0f}, { 1.0f, 1.0f }, { 1, 0, 0, 1 });
Flush();
glfwSwapBuffers(Window);
glfwPollEvents();
}
delete TextureShader;
delete WhiteTexture;
glfwTerminate();
return 0;
}
我尝试了各种修复方法:确保所有三角形的索引顺序正确,确保着色器不仅是在渲染一个透明纹理,确保我要渲染的顶点确实在相机的视野内,结果都无济于事。如果你恰好弄清楚我哪里做错了,请告诉我是怎么发现的。
解决方案
代码里有几个问题:
- 我从不增加IndexCount,因此当待绘制的索引数量为零时,绘制调用显然不会绘制任何东西。
- 在创建索引缓冲区时,我对glBindBuffer和 glBufferData传入的参数是GL_ARRAY_BUFFER,而不是正确的GL_ELEMENT_ARRAY_BUFFER。
- 最后,当我调用glm::ortho() 为场景创建投影矩阵时,我指定了一个800×600的窗口,将设备坐标从左下角的0,0映射到右上角的800,600。因此,当我在0,0处渲染一个大小为 (1,1) 的对象时,它渲染得太小,以致于在屏幕角落几乎看不到。
解决了所有这些问题后,我得到了期望的输出。
最终代码:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <string>
#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
#include <array>
//////////////////
// BEGIN SHADER //
//////////////////
class Shader
{
public:
Shader();
~Shader();
void use();
void setUniformMat4(const std::string name, glm::mat4 value);
private:
uint32_t m_rendererID;
};
Shader::Shader()
{
const char* vShaderCode = R"END(
#version 450 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
layout(location = 2) in vec2 a_TexCoord;
layout(location = 3) in float a_TexIndex;
layout(location = 4) in float a_TilingFactor;
uniform mat4 u_ViewProjection;
struct VertexOutput
{
vec4 Color;
vec2 TexCoord;
float TexIndex;
float TilingFactor;
};
layout (location = 0) out VertexOutput Output;
void main()
{
Output.Color = a_Color;
Output.TexCoord = a_TexCoord;
Output.TexIndex = a_TexIndex;
Output.TilingFactor = a_TilingFactor;
gl_Position = vec4(a_Position, 1.0);
}
)END";
const char* fShaderCode = R"END(
#version 450 core
layout(location = 0) out vec4 color;
struct VertexOutput
{
vec4 Color;
vec2 TexCoord;
float TexIndex;
float TilingFactor;
};
layout (location = 0) in VertexOutput Input;
layout (binding = 0) uniform sampler2D u_Textures[32];
void main()
{
vec4 texColor = Input.Color;
switch(int(Input.TexIndex))
{
case 0: texColor *= texture(u_Textures[ 0], Input.TexCoord * Input.TilingFactor); break;
case 1: texColor *= texture(u_Textures[ 1], Input.TexCoord * Input.TilingFactor); break;
case 2: texColor *= texture(u_Textures[ 2], Input.TexCoord * Input.TilingFactor); break;
case 3: texColor *= texture(u_Textures[ 3], Input.TexCoord * Input.TilingFactor); break;
case 4: texColor *= texture(u_Textures[ 4], Input.TexCoord * Input.TilingFactor); break;
case 5: texColor *= texture(u_Textures[ 5], Input.TexCoord * Input.TilingFactor); break;
case 6: texColor *= texture(u_Textures[ 6], Input.TexCoord * Input.TilingFactor); break;
case 7: texColor *= texture(u_Textures[ 7], Input.TexCoord * Input.TilingFactor); break;
case 8: texColor *= texture(u_Textures[ 8], Input.TexCoord * Input.TilingFactor); break;
case 9: texColor *= texture(u_Textures[ 9], Input.TexCoord * Input.TilingFactor); break;
case 10: texColor *= texture(u_Textures[10], Input.TexCoord * Input.TilingFactor); break;
case 11: texColor *= texture(u_Textures[11], Input.TexCoord * Input.TilingFactor); break;
case 12: texColor *= texture(u_Textures[12], Input.TexCoord * Input.TilingFactor); break;
case 13: texColor *= texture(u_Textures[13], Input.TexCoord * Input.TilingFactor); break;
case 14: texColor *= texture(u_Textures[14], Input.TexCoord * Input.TilingFactor); break;
case 15: texColor *= texture(u_Textures[15], Input.TexCoord * Input.TilingFactor); break;
case 16: texColor *= texture(u_Textures[16], Input.TexCoord * Input.TilingFactor); break;
case 17: texColor *= texture(u_Textures[17], Input.TexCoord * Input.TilingFactor); break;
case 18: texColor *= texture(u_Textures[18], Input.TexCoord * Input.TilingFactor); break;
case 19: texColor *= texture(u_Textures[19], Input.TexCoord * Input.TilingFactor); break;
case 20: texColor *= texture(u_Textures[20], Input.TexCoord * Input.TilingFactor); break;
case 21: texColor *= texture(u_Textures[21], Input.TexCoord * Input.TilingFactor); break;
case 22: texColor *= texture(u_Textures[22], Input.TexCoord * Input.TilingFactor); break;
case 23: texColor *= texture(u_Textures[23], Input.TexCoord * Input.TilingFactor); break;
case 24: texColor *= texture(u_Textures[24], Input.TexCoord * Input.TilingFactor); break;
case 25: texColor *= texture(u_Textures[25], Input.TexCoord * Input.TilingFactor); break;
case 26: texColor *= texture(u_Textures[26], Input.TexCoord * Input.TilingFactor); break;
case 27: texColor *= texture(u_Textures[27], Input.TexCoord * Input.TilingFactor); break;
case 28: texColor *= texture(u_Textures[28], Input.TexCoord * Input.TilingFactor); break;
case 29: texColor *= texture(u_Textures[29], Input.TexCoord * Input.TilingFactor); break;
case 30: texColor *= texture(u_Textures[30], Input.TexCoord * Input.TilingFactor); break;
case 31: texColor *= texture(u_Textures[31], Input.TexCoord * Input.TilingFactor); break;
}
color = texColor;
}
)END";
unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
m_rendererID = glCreateProgram();
glAttachShader(m_rendererID, vertex);
glAttachShader(m_rendererID, fragment);
glLinkProgram(m_rendererID);
glDeleteShader(vertex);
glDeleteShader(fragment);
}
Shader::~Shader()
{
glDeleteProgram(m_rendererID);
}
void Shader::use()
{
glUseProgram(m_rendererID);
}
void Shader::setUniformMat4(const std::string name, glm::mat4 value)
{
glUniformMatrix4fv(glGetUniformLocation(m_rendererID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}
///////////////////
// BEGIN TEXTURE //
///////////////////
class Texture
{
public:
Texture(uint32_t width, uint32_t height);
~Texture();
uint32_t getWidth() const { return m_width; }
uint32_t getHeight() const { return m_height; }
void setData(void* data, uint32_t size);
void bind(uint32_t slot = 0) const;
bool operator==(const Texture& other) const
{
return m_rendererID == ((Texture&)other).m_rendererID;
}
private:
std::string m_path;
uint32_t m_width, m_height;
uint32_t m_rendererID;
GLenum m_internalFormat, m_dataFormat;
};
Texture::Texture(uint32_t width, uint32_t height)
: m_width(width), m_height(height)
{
m_internalFormat = GL_RGBA8;
m_dataFormat = GL_RGBA;
glCreateTextures(GL_TEXTURE_2D, 1, &m_rendererID);
glTextureStorage2D(m_rendererID, 1, m_internalFormat, m_width, m_height);
glTextureParameteri(m_rendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(m_rendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_rendererID);
}
void Texture::setData(void* data, uint32_t size)
{
uint32_t bpp = m_dataFormat == GL_RGBA ? 4 : 3;
glTextureSubImage2D(m_rendererID, 0, 0, 0, m_width, m_height, m_dataFormat, GL_UNSIGNED_BYTE, data);
}
void Texture::bind(uint32_t slot) const
{
glBindTextureUnit(slot, m_rendererID);
}
//////////
// CODE //
//////////
const uint32_t RendererMaxQuads = 10000;
const uint32_t RendererMaxIndices = 6 * RendererMaxQuads;
const uint32_t RendererMaxVertexCount = 4 * RendererMaxQuads;
const uint32_t RendererMaxTextureSlots = 32;
struct Vertex {
glm::vec3 Position;
glm::vec4 Color;
glm::vec2 TexCoord;
float TexIndex;
float TilingFactor;
Vertex()
{
Position = { 0, 0, 0 };
Color = { 0,0,0,1 };
TexCoord = { 0, 0 };
TexIndex = 0;
TilingFactor = 1;
}
Vertex(glm::vec3 pos, glm::vec4 color, glm::vec2 texCoord, float texIndex, float tilingFactor)
{
Position = pos;
Color = color;
TexCoord = texCoord;
TexIndex = texIndex;
TilingFactor = tilingFactor;
}
};
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
Shader* TextureShader = nullptr;
Texture* WhiteTexture = nullptr;
std::array<Texture*, RendererMaxTextureSlots> TextureSlots;
std::array<Vertex, RendererMaxVertexCount> Verticies;
GLuint VAO = 0;
GLuint VBO = 0;
GLuint IndexBuffer = 0;
uint32_t VertexCount = 0;
uint32_t IndexCount = 0;
uint32_t TextureSlotIndex = 0;
void Flush()
{
if (VertexCount == 0)
{
// Nothing to draw
return;
}
TextureShader->use();
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, VertexCount * sizeof(Vertex), &Verticies);
// Bind textures
for (uint32_t i = 0; i < TextureSlotIndex; i++)
TextureSlots[i]->bind(i);
glDrawElements(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr);
}
void DrawQuad(glm::vec3 position, glm::vec2 size, glm::vec4 color)
{
if (VertexCount >= RendererMaxVertexCount - 4)
{
Flush();
VertexCount = 0;
IndexCount = 0;
TextureSlotIndex = 1; // 0 = WhiteTexture
}
// Add verticies
Verticies[VertexCount++] = {
position + glm::vec3(size.x, size.y, 0.0f), // Top Right
color,
{1, 1}, // Top Right
0, // White Texture
1 // No Tiling
};
Verticies[VertexCount++] = {
position + glm::vec3(-size.x, size.y, 0.0f), // Top Left
color,
{0, 1}, // Top Left
0, // White Texture
1 // No Tiling
};
Verticies[VertexCount++] = {
position + glm::vec3(size.x, -size.y, 0.0f), // Bottom Right
color,
{1, 0}, // Bottom Right
0, // White Texture
1 // No Tiling
};
Verticies[VertexCount++] = {
position + glm::vec3(-size.x, -size.y, 0.0f), // Bottom Left
color,
{0, 0}, // Bottom Left
0, // White Texture
1 // No Tiling
};
IndexCount += 6;
}
int main()
{
// Start OpenGL context and OS window using the GLFW helper library.
if (!glfwInit()) {
std::cout << "ERROR: could not start GLFW" << std::endl;
return -1;
}
// Request an OpenGL 4.5, core, context from GLFW.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create a window on the operating system, then tie the OpenGL context to it.
GLFWwindow* Window = glfwCreateWindow(800, 600, "windowTitle", NULL, NULL);
if (!Window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(Window);
glfwSetFramebufferSizeCallback(Window, framebuffer_size_callback);
// Start Glad, so we can call OpenGL functions.
if (gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) == 0) {
return -1;
}
glEnable(GL_DEPTH_TEST);
glCreateVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glCreateBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * RendererMaxVertexCount, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Color));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexCoord));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexIndex));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TilingFactor));
TextureShader = new Shader();
WhiteTexture = new Texture(1, 1);
uint32_t whiteTextureData = 0xffffffff;
WhiteTexture->setData(&whiteTextureData, sizeof(uint32_t));
TextureSlots[0] = WhiteTexture;
uint32_t* quadIndices = new uint32_t[RendererMaxIndices];
uint32_t offset = 0;
for (uint32_t i = 0; i < RendererMaxIndices; i += 6)
{
quadIndices[i + 0] = offset + 0;
quadIndices[i + 1] = offset + 2;
quadIndices[i + 2] = offset + 1;
quadIndices[i + 3] = offset + 1;
quadIndices[i + 4] = offset + 2;
quadIndices[i + 5] = offset + 3;
offset += 4;
}
glCreateBuffers(1, &IndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, RendererMaxIndices * sizeof(uint32_t), quadIndices, GL_STATIC_DRAW);
delete[] quadIndices;
glClearColor( 0.0f, 0.0f, 1.0f, 1.0f);
while (!glfwWindowShouldClose(Window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
VertexCount = 0;
IndexCount = 0;
TextureSlotIndex = 1; // 0 = WhiteTexture
DrawQuad({ 0, 0, 0.0f}, { 0.5f, 0.5f }, { 1, 0, 0, 1 });
Flush();
glfwSwapBuffers(Window);
glfwPollEvents();
}
delete TextureShader;
delete WhiteTexture;
glfwTerminate();
return 0;
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。