文章目录
在OpenGL提供的基础上,可以对其进行更高级的抽象来方便使用
VertexBuffer(顶点缓冲区):
- m_RenderID是使用OpenGL的API所分配返回的ID。
- 构造函数传入需要填入的数据和数据大小,数据大小为字节大小。内部会自动创建绑定缓冲区,并填充数据。当离开对象作用域时,会自动调用析构函数,释放缓冲区内存。
- Bind和UnBind函数会调用API函数,使用生成的id来绑定指定的缓冲区
//VertexBuffer.h
class VertexBuffer
{
private:
unsigned int m_RenderID;
public:
VertexBuffer(const void* data, unsigned int size);
~VertexBuffer();
void Bind() const;
void Unbind() const;
};
//VertexBuffer.cpp
#include "VertexBuffer.h"
#include "Renderer.h"
VertexBuffer::VertexBuffer(const void* data, unsigned int size)
{
GLCall(glGenBuffers(1, &m_RenderID));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, m_RenderID));
GLCall(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
Bind();
}
VertexBuffer::~VertexBuffer()
{
GLCall(glDeleteBuffers(1, &m_RenderID));
}
void VertexBuffer::Bind() const
{
GLCall(glBindBuffer(GL_ARRAY_BUFFER, m_RenderID));
}
void VertexBuffer::Unbind() const
{
GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
VertexBufferLayout(顶点缓冲区布局):
VertexBufferElement:
- type:使用如GL_FLOAT,GL_UNSIGNED_INT来为其赋值
- count:内部元素个数
- normalized:指定定点数据值应归一化或直接转换为定点值
- GetSizeOfType:根据type返回单个元素的字节大小
m_Elements:存储顺序紧密排布的元素布局
m_Stride:Layout(所有元素加起来)的长度
Push:泛型函数,向m_Elements推入一个对象,向m_Stride累加大小
//VertexBufferLayout.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;
}
VertexBufferElement(unsigned int type, unsigned int count, unsigned char normalized)
: type(type), count(count), normalized(normalized) {}
};
class VertexBufferLayout
{
private:
std::vector<VertexBufferElement> m_Elements;
unsigned int m_Stride;
public:
VertexBufferLayout();
template<typename T>
void Push(unsigned count)
{
static_assert(false);
}
template<>
void Push<float>(unsigned int count)
{
m_Elements.push_back({ GL_FLOAT, count, GL_FALSE });
m_Stride += count * VertexBufferElement::GetSizeOfType(GL_FLOAT);
}
template<>
void Push<unsigned int>(unsigned int count)
{
m_Elements.push_back({ GL_UNSIGNED_INT, count, GL_FALSE });
m_Stride += count * VertexBufferElement::GetSizeOfType(GL_UNSIGNED_INT);
}
template<>
void Push<unsigned char>(unsigned int count)
{
m_Elements.push_back({ GL_UNSIGNED_BYTE, count, GL_TRUE });
m_Stride += count * VertexBufferElement::GetSizeOfType(GL_UNSIGNED_BYTE);
}
inline const std::vector<VertexBufferElement> GetElements() const { return m_Elements; }
inline unsigned int GetStride() const { return m_Stride; }
};
//VertexBufferLayout.cpp
VertexBufferLayout::VertexBufferLayout()
{
m_Stride = 0;
}
Vertex Array Object(顶点数组对象):
AddBuffer:传入缓存区和缓存区布局,根据缓存布局对象内部存储的数据,调用glEnableVertexAttribArray和glVertexAttribPointer来进行实际的布局指定
构造函数:调用glGenVertexArrays生成VAO
Bind,UnBind:调用glBindVertexArray和记录的m_RendererID进行绑定
//VertexArray.h
class VertexBuffer;
class VertexBufferLayout;
class VertexArray
{
private:
unsigned int m_RendererID;
public:
VertexArray();
~VertexArray();
void AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout);
void Bind() const;
void Unbind() const;
};
//VertexArray.cpp
#include <GL/glew.h>
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "VertexBufferLayout.h"
#include "Renderer.h"
VertexArray::VertexArray()
{
GLCall(glGenVertexArrays(1, &m_RendererID));
}
VertexArray::~VertexArray()
{
GLCall(glDeleteVertexArrays(1, &m_RendererID));
}
void VertexArray::AddBuffer(const VertexBuffer& vb, const 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);
}
}
void VertexArray::Bind() const
{
GLCall(glBindVertexArray(m_RendererID));
}
void VertexArray::Unbind() const
{
GLCall(glBindVertexArray(0));
}
IndexBuffer(索引缓冲区):
构造函数传入数据和元素个数,内部生成绑定缓冲区,填充数据
Bind,UnBind函数内部绑定缓存的指定缓存区
//IndexBuffer.h
class IndexBuffer
{
private:
unsigned int m_RenderID;
unsigned int m_Count;
public:
IndexBuffer(const void* data, unsigned int count);
~IndexBuffer();
void Bind() const;
void Unbind() const;
inline unsigned int GetCount() const { return m_Count; }
};
//IndexBuffer.cpp
#include "IndexBuffer.h"
#include "Renderer.h"
IndexBuffer::IndexBuffer(const void* data, unsigned int count)
: m_Count(count)
{
ASSERT(sizeof(unsigned int) == sizeof(GLuint))
GLCall(glGenBuffers(1, &m_RenderID));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RenderID));
GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW));
}
IndexBuffer::~IndexBuffer()
{
GLCall(glDeleteBuffers(1, &m_RenderID));
}
void IndexBuffer::Bind() const
{
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RenderID));
}
void IndexBuffer::Unbind() const
{
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
Shader(着色器):
构造函数传入文件路径,在ParseShader中按自定义规则读取源GLSL代码,在CreateShader中创建并编译顶点和片元着色器
Bind和UnBind函数中调用glUseProgram使用指定的着色器
SetUniform设置着色器变量值,GetUniformLocation获取着色器变量位置,并有缓存机制
//Shader.h
#pragma once
#include <string>
#include <unordered_map>
#include <GL/glew.h>
#include <glm/glm.hpp>
using std::string;
using uint = unsigned int;
using ShaderProgramSource = std::pair<string, string>;
using hash = std::unordered_map<string, int>;
class Shader
{
private:
string m_FilePath;
uint m_RendererID;
hash m_UniformLocationCache;
public:
Shader(const string& filePath);
~Shader();
void Bind() const;
void Unbind() const;
void SetUniform1i(const string& name, int value);
void SetUniform1f(const string& name, float value);
void SetUniform4f(const string& name, float v0, float v1, float v2, float v3);
void SetUniformMat4f(const string& name, const GLfloat* matrixPtr);
private:
ShaderProgramSource ParseShader(const string& filePath);
uint CompileShader(uint type, const std::string& source);
uint CreateShader(const std::string& vertexShader, const std::string& fragmentShader);
int GetUniformLocation(const string& name);
};
//Shader.cpp
#include "Shader.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include "Renderer.h"
using std::ifstream;
using std::cout;
using std::endl;
Shader::Shader(const string& filePath)
: m_FilePath(filePath), m_RendererID(0)
{
auto shaderSource = ParseShader(filePath);
m_RendererID = CreateShader(shaderSource.first, shaderSource.second);
}
Shader::~Shader()
{
GLCall(glDeleteProgram(m_RendererID));
}
void Shader::Bind() const
{
GLCall(glUseProgram(m_RendererID));
}
void Shader::Unbind() const
{
GLCall(glUseProgram(0));
}
void Shader::SetUniform1i(const string& name, int value)
{
GLCall(glUniform1i(GetUniformLocation(name), value));
}
void Shader::SetUniform1f(const string& name, float value)
{
GLCall(glUniform1f(GetUniformLocation(name), value));
}
void Shader::SetUniform4f(const string& name, float v0, float v1, float v2, float v3)
{
GLCall(glUniform4f(GetUniformLocation(name), v0, v1, v2, v3));
}
void Shader::SetUniformMat4f(const string& name, const GLfloat* matrixPtr)
{
GLCall(glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, matrixPtr));
}
int Shader::GetUniformLocation(const string& name)
{
if (m_UniformLocationCache.contains(name))
return m_UniformLocationCache[name];
GLCall(int location = glGetUniformLocation(m_RendererID, name.c_str()));
if (location == -1)
cout << "Warning: uniform ' " << name << " ' doesn't exist!" << endl;
m_UniformLocationCache[name] = location;
return location;
}
ShaderProgramSource Shader::ParseShader(const string& filePath)
{
ifstream stream(filePath);
enum class ShaderType
{
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
string line;
std::stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line))
{
if (line.find("#shader") != string::npos)
{
if (line.find("vertex") != string::npos)
type = ShaderType::VERTEX;
else if (line.find("fragment") != string::npos)
type = ShaderType::FRAGMENT;
}
else if (type != ShaderType::NONE)
{
ss[(int)type] << line << "\n";
}
}
return { ss[0].str(), ss[1].str() };
}
uint Shader::CompileShader(uint type, const std::string& source)
{
uint id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
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);
cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertext" : "fragment") << " shader!" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
uint Shader::CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
uint program = glCreateProgram();
uint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
uint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
//已经使用了的着色器可以清理,节省一点空间但不再能调试了
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
Renderer(渲染器):
Renderer负责在渲染循环中调用,使用固定的渲染顺序,简化外部使用
外部负责传入vao,ibo或顶点数量,shader来绘制
//Renderer.h
#pragma once
#include <GL/glew.h>
class VertexArray;
class IndexBuffer;
class Shader;
//错误处理
#define ASSERT(x) if (!(x)) __debugbreak();
#define GLCall(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__));
void GLClearError();
bool GLLogCall(const char* function, const char* file, int line);
class Renderer
{
public:
void Draw(const VertexArray& vao, const unsigned int vertexCount, const Shader& shader) const;
void Draw(const VertexArray& vao, const IndexBuffer& ibo, const Shader& shader) const;
void Clear();
};
//Renderer.cpp
#include "Renderer.h"
#include <iostream>
#include "VertexArray.h"
#include "IndexBuffer.h"
#include "Shader.h"
using std::cout;
using std::endl;
void GLClearError()
{
while (glGetError() != GL_NO_ERROR);
}
bool GLLogCall(const char* function, const char* file, int line)
{
while (GLenum error = glGetError())
{
cout << "[OpenGL Error] ( " << error << " ) :\n" << function <<
"" << file << " : " << line << endl;
return false;
}
return true;
}
void Renderer::Draw(const VertexArray& vao, const unsigned int vertexCount, const Shader& shader) const
{
shader.Bind();
vao.Bind();
GLCall(glDrawArrays(GL_TRIANGLES, 0, vertexCount))
}
void Renderer::Draw(const VertexArray& vao, const IndexBuffer& ibo, const Shader& shader) const
{
shader.Bind();
vao.Bind();
ibo.Bind();
GLCall(glDrawElements(GL_TRIANGLES, ibo.GetCount(), GL_UNSIGNED_INT, nullptr));
}
void Renderer::Clear()
{
//清理颜色和深度的缓冲区
GLCall(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
}
Texture(纹理):
构造函数传入纹理路径,使用自定义的库读取纹理像素。创建绑定纹理对象,设定默认参数,将纹理填入该纹理对象(通过glBindTexture和m_RendererID指定)中
Bind中使用glActiveTexture选择要开启的纹理槽位,glBindTexture将本纹理绑定到该槽位上
//Texture.h
#pragma once
#include <string>
using uint = unsigned int;
using uchar = unsigned char;
using std::string;
class Texture
{
private:
uint m_RendererID;
string m_FilePath;
uchar* m_LocalBuffer;
int m_Width, m_Height, m_BPP;
public:
Texture(const string& filePath);
~Texture();
void Bind(uint slot = 0) const;
void Unbind();
inline int GetWidth() const { return m_Width; }
inline int GetHeight() const { return m_Height; }
};
//Texture.cpp
#include "Texture.h"
#include "Renderer.h"
#include "stb_image/stb_image.h"
Texture::Texture(const string& filePath)
: m_RendererID(0), m_FilePath(filePath), m_LocalBuffer(nullptr), m_Width(0), m_Height(0), m_BPP(0)
{
stbi_set_flip_vertically_on_load(1);
m_LocalBuffer = stbi_load(filePath.c_str(), &m_Width, &m_Height, &m_BPP, 4);
GLCall(glGenTextures(1, &m_RendererID));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
//这四个默认参数不填入,直接给你个黑纹理
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer));
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
if (m_LocalBuffer)
stbi_image_free(m_LocalBuffer);
}
Texture::~Texture()
{
GLCall(glDeleteTextures(1, &m_RendererID));
}
void Texture::Bind(uint slot) const
{
GLCall(glActiveTexture(GL_TEXTURE0 + slot));
GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
}
void Texture::Unbind()
{
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
}
Camera(摄像机):
外部调用Process函数来更新变量,并通过GetViewMatrix获取观察矩阵
#pragma once
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using glm::vec3;
using glm::radians;
using glm::cross;
using glm::normalize;
enum ECameraMoveDirection
{
FORWARD, BACKWARD, LEFT, RIGHT
};
// Default camera values
const GLfloat DEF_YAW = -90.0f;
const GLfloat DEF_PITCH = 0.0f;
const GLfloat DEF_SPEED = 3.0f;
const GLfloat DEF_SENSITIVTY = 0.25f;
const GLfloat DEF_ZOOM = 45.0f;
class Camera
{
public:
// Camera Attributes
vec3 Position;
vec3 WorldUp;
vec3 Front;
vec3 Right;
vec3 Up;
// Eular Angles
GLfloat Yaw;
GLfloat Pitch;
// Camera options
GLfloat MovementSpeed;
GLfloat MouseSensitivity;
GLfloat Zoom;
Camera(vec3 position = vec3(0, 0, 0), vec3 up = vec3(0, 1, 0), GLfloat yaw = DEF_YAW, GLfloat pitch = DEF_PITCH) :
Front(vec3(0, 0, -1)), MovementSpeed(DEF_SPEED), MouseSensitivity(DEF_SENSITIVTY), Zoom(DEF_ZOOM),
Position(position), WorldUp(up), Yaw(yaw), Pitch(pitch)
{
UpdateCameraVectors();
}
Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) :
Front(vec3(0, 0, -1)), MovementSpeed(DEF_SPEED), MouseSensitivity(DEF_SENSITIVTY), Zoom(DEF_ZOOM),
Position(posX, posY, posZ), WorldUp(upX, upY, upZ), Yaw(yaw), Pitch(pitch)
{
UpdateCameraVectors();
}
glm::mat4 GetViewMatrix()
{
return glm::lookAt(this->Position, this->Position + this->Front, this->Up);
}
void ProcessKeyboard(ECameraMoveDirection direction, GLfloat deltaTime)
{
GLfloat velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == RIGHT)
Position += Right * velocity;
if (direction == LEFT)
Position -= Right * velocity;
}
void ProcessMouseMovement(GLfloat offsetX, GLfloat offsetY, GLboolean constrainPitch = true)
{
offsetX *= MouseSensitivity;
offsetY *= MouseSensitivity;
Yaw += offsetX;
Pitch += offsetY;
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
UpdateCameraVectors();
}
void ProcessMouseScroll(GLfloat offsetY)
{
if (Zoom >= 1 && Zoom <= 45)
Zoom -= offsetY;
if (Zoom <= 1)
Zoom = 1;
if (Zoom >= 45)
Zoom = 45;
}
private:
void UpdateCameraVectors()
{
vec3 front;
front.x = cos(radians(Yaw)) * cos(radians(Pitch));
front.y = sin(radians(Pitch));
front.z = sin(radians(Yaw)) * cos(radians(Pitch));
Front = normalize(front);
Right = normalize(cross(Front, WorldUp));
Up = normalize(cross(Right, Front));
}
};
示例代码(仅核心部分):
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "Renderer.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "VertexArray.h"
#include "VertexBufferLayout.h"
#include "Shader.h"
#include "Texture.h"
#include "Camera.h"
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "learn1.hpp"
using std::cout;
using namespace glm;
//摄像机变量
Camera camera;
bool keys[1024];
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;
float deltaTime;
//提前声明
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void DoMovement();
void Learn2(GLFWwindow* window, float targetFrameTime)
{
deltaTime = targetFrameTime;
//开启深度测试
glEnable(GL_DEPTH_TEST);
//定义顶点和索引数据
GLfloat vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
// World space positions of our cubes
glm::vec3 cubePositions[] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
//创建顶点数组对象
VertexArray vao;
//创建顶点缓存和布局,并链接到顶点数组上
VertexBuffer vbo(vertices, sizeof(vertices));
VertexBufferLayout layout;
layout.Push<float>(3);
layout.Push<float>(2);
//缓存和布局绑定到vao上
vao.AddBuffer(vbo, layout);
//创建shader并设置参数
Shader shader("res/shaders/Learn2.shader");
shader.Bind();
//创建纹理并启用
Texture texture("res/textures/awesomeface.png");
texture.Bind();
shader.SetUniform1i("u_Texture", 0);
//创建渲染器
Renderer renderer;
//摄像机按键绑定
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
//在渲染循环中绘制指定的顶点数组对象,索引缓存,着色器
while (!glfwWindowShouldClose(window))
{
CheckFrameTimeOut(targetFrameTime);
DoMovement();
renderer.Clear();
glm::mat4 view(1), proj(1);
//投影矩阵(透视参数)
view = camera.GetViewMatrix();
shader.SetUniformMat4f("view", glm::value_ptr(view));
proj = glm::perspective<GLfloat>(45, 640 / 480, .1f, 100.f);
shader.SetUniformMat4f("projection", glm::value_ptr(proj));
//模型矩阵(模型位置)
for (GLuint i = 0; i < 10; i++)
{
glm::mat4 model(1);
model = glm::translate(model, cubePositions[i]);
GLfloat angle = 20.0f * i;
model = glm::rotate(model, angle + ((GLfloat)glfwGetTime() * (i % 2 ? 1 : -1)), glm::vec3(1.0f, 0.3f, 0.5f));
shader.SetUniformMat4f("model", glm::value_ptr(model));
renderer.Draw(vao, 36, shader);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
}
// Moves/alters the camera positions based on user input
void DoMovement()
{
if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime);
if (keys[GLFW_KEY_S])
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (keys[GLFW_KEY_A])
camera.ProcessKeyboard(LEFT, deltaTime);
if (keys[GLFW_KEY_D])
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 0 && key < 1024)
{
if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;
}
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
GLfloat xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to left
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(yoffset);
}


656

被折叠的 条评论
为什么被折叠?



