- 已关闭。**此问题需要debugging details。当前不接受答案。
编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将有助于其他人回答问题。
1小时前关闭。
Improve this question
我正在学习OpenGL教程,但遇到了麻烦。我试图画两个三角形来组成一个矩形,当我在主函数中包含glVertexAttribPointer和glEnableVertexAttribArray时,效果很好,但一旦我试图将其抽象到VertexArray类中,屏幕上什么也画不出来。我怀疑这是因为所有点都在0处绘制,0,因为当我将绘制模式更改为点而不是三角形时,它会在0,0处绘制一个点。请注意,下面的代码中不包含此内容,它仍然设置为三角形。
主要方法
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "Renderer.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
static ShaderProgramSource ParseShader(const std::string& filePath)
{
//open file at filePath
std::ifstream stream(filePath);
enum class ShaderType
{
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
ShaderType type = ShaderType::NONE;
std::string line;
std::stringstream ss[2];
while (getline(stream, line))
{
//if #shader is found in line
if (line.find("#shader") != std::string::npos)
{
//set type to vertex or fragment depending on #shader line
if (line.find("vertex") != std::string::npos)
{
//set the mode to vertex
type = ShaderType::VERTEX;
}
else if (line.find("fragment") != std::string::npos)
{
//set the mode to fragment
type = ShaderType::FRAGMENT;
}
}
// add the line to a string at the index of the type
else
ss[(int)type % 2] << line << "\n";
}
return { ss[0].str(), ss[1].str() };
}
static unsigned int CompileShader(unsigned int type, const std::string& source)
{
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
//retrieves the result of glCompileShader
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
unsigned int program = glCreateProgram();
unsigned int vShader = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fShader = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vShader);
glAttachShader(program, fShader);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vShader);
glDeleteShader(fShader);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
if (glewInit() != GLEW_OK)
std::cout << "Error Initilizing GLEW" << std::endl;
{
float positions[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.5f, 0.5f,
-0.5f, 0.5f
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
VertexArray VAO;
VertexBufferLayout layout;
layout.Push<float>(2);
VertexBuffer VB(positions, 4 * 2 * sizeof(float));
VAO.AddBuffer(VB, layout);
IndexBuffer IB(indices, 6);
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
unsigned int shader = CreateShader(source.VertexSource, source.FragmentSource);
glUseProgram(shader);
//returning values from a shader
GLCall(int location = glGetUniformLocation(shader, "u_Color"));
ASSERT(location != -1);
GLCall(glUniform4f(location, 0.8f, 0.3f, 0.8f, 1.0f));
GLCall(glBindVertexArray(0));
GLCall(glUseProgram(0));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
float r = 0.0f;
float increment = 0.05f;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
GLCall(glClear(GL_COLOR_BUFFER_BIT));
GLCall(glUseProgram(shader));
GLCall(glUniform4f(location, r, 0.3f, 0.8f, 1.0f));
VAO.Bind();
GLCall(IB.Bind());
GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
if (r > 1.0f)
increment = -0.05f;
else if (r < 0.0f)
increment = 0.05;
r += increment;
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
}
glfwTerminate();
return 0;
}
顶点阵列
#include "VertexArray.h"
#include "Renderer.h"
VertexArray::VertexArray()
{
GLCall(glGenVertexArrays(1, &m_RendererID));
Bind();
}
VertexArray::~VertexArray()
{
GLCall(glDeleteVertexArrays(1, &m_RendererID));
}
void VertexArray::AddBuffer(VertexBuffer VB, VertexBufferLayout& layout)
{
Bind();
VB.Bind();
const auto& elements = layout.getElements();
unsigned int offset = 0;
for (unsigned int i = 0; i < elements.size(); i++)
{
const auto& element = elements[i];
GLCall(glEnableVertexAttribArray(i));
GLCall(glVertexAttribPointer(i, element.count, element.type, element.normalized, layout.GetStride(), (const void*)offset));
offset += element.count * VertexBufferElement::GetSizeofType(element.type);
}
VB.Unbind();
}
void VertexArray::Bind()
{
// Make the VAO current by binding it
glBindVertexArray(m_RendererID);
}
void VertexArray::Unbind()
{
glBindVertexArray(0);
}
顶点缓冲区
#include "VertexBuffer.h"
#include "Renderer.h"
VertexBuffer::VertexBuffer(const void* data, unsigned int size)
{
//Returns a vacant Buffer object which can after v THIS v line can be referenced to OpenGL by uint ID
glGenBuffers(1, &m_RendererID);
//Binds the buffer to GL_ARRAY_BUFFER, so GL knows which to modify when BufferData vv is called or when a buffer drawn
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
//Fills GL_ARRAY_BUFFER with data
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
VertexBuffer::~VertexBuffer()
{
GLCall(glDeleteBuffers(1, &m_RendererID));
}
void VertexBuffer::Bind() const
{
//Binds the buffer to GL_ARRAY_BUFFER, so GL knows which to modify when BufferData vv is called or when a buffer drawn
GLCall(glBindBuffer(GL_ARRAY_BUFFER, m_RendererID));
}
void VertexBuffer::Unbind() const
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
顶点缓冲区布局:
#pragma once
#include <vector>
#include <GL/glew.h>
#include "Renderer.h"
struct VertexBufferElement
{
unsigned int type;
unsigned int count;
unsigned char normalized;
static unsigned int GetSizeofType(unsigned int type)
{
switch (type)
{
case GL_FLOAT: return 4;
case GL_UNSIGNED_INT: return 4;
case GL_UNSIGNED_BYTE: return 1;
}
ASSERT(false)
return 0;
}
};
class VertexBufferLayout
{
private:
std::vector<VertexBufferElement> m_Elements;
unsigned int m_Stride;
public:
VertexBufferLayout()
:m_Stride(0) {}
template<typename T>
void Push(unsigned int count)
{
static_assert(false);
}
template<>
void Push<float>(unsigned int count)
{
VertexBufferElement vbe = { GL_FLOAT, count, GL_FALSE };
m_Elements.push_back(vbe);
m_Stride += VertexBufferElement::GetSizeofType(GL_FLOAT) * count;
}
template<>
void Push<unsigned int>(unsigned int count)
{
VertexBufferElement vbe = { GL_UNSIGNED_INT, count, GL_FALSE };
m_Elements.push_back(vbe);
m_Stride += VertexBufferElement::GetSizeofType(GL_UNSIGNED_INT) * count;
}
template<>
void Push<unsigned char>(unsigned int count)
{
VertexBufferElement vbe = { GL_UNSIGNED_BYTE, count, GL_TRUE };
m_Elements.push_back(vbe);
m_Stride += VertexBufferElement::GetSizeofType(GL_UNSIGNED_BYTE) * count;
}
inline const std::vector<VertexBufferElement> getElements() const { return m_Elements; }
inline unsigned int GetStride() const { return m_Stride; }
};
当前仅处理错误的渲染器
#include "Renderer.h"
#include <iostream>
void GLClearError()
{
while (glGetError() != GL_NO_ERROR)
{
}
}
bool GLLogCall(const char* function, const char* file, int line)
{
while (GLenum error = glGetError())
{
std::cout << "[OpenGL Error] (" << error << "):" << function << " " << file << ":" << line << std::endl;
return false;
}
return true;
}
索引缓冲区
#include "IndexBuffer.h"
#include "Renderer.h"
IndexBuffer::IndexBuffer(const unsigned int* data, unsigned int count)
: m_Count(count)
{
ASSERT(sizeof(unsigned int) == sizeof(GLuint));
GLCall(glGenBuffers(1, &m_RendererID));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID));
GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW));
}
IndexBuffer::~IndexBuffer()
{
GLCall(glDeleteBuffers(1, &m_RendererID));
}
void IndexBuffer::Bind() const
{
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID));
}
void IndexBuffer::Unbind() const
{
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
最后是着色器
#shader vertex
#version 330 core
layout(location = 0) in vec4 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}
#shader fragment
#version 330 core
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main()
{
color = u_Color;
}
如果来自VertexArray::AddBuffer的两行GLCall位于main方法中,并且通过调试我能够确认这两行的值相同,则矩形绘制正确。
1条答案
按热度按时间zzwlnbp81#
UPDATE:我需要将VB对象作为引用传入。糟糕。当我将VB对象传入AddBuffer时,我正在创建一个堆栈分配的VB副本。