3
社区成员
发帖
与我相关
我的任务
分享cpp文件CandyRenderEngine/Math/Transform.cpp
//===========================================================
// 文件: Transform.cpp
// 路径: CandyRenderEngine/Math/Transform.cpp
// 说明: 变换组件实现文件,实现平移、旋转、缩放的具体逻辑
// 依赖: Transform.h, GLM 数学库
//===========================================================
#include "pch.h"
#include "Transform.h"
#include <cmath>
Transform::Transform() {
Reset();
}
// ===== 平移 =====
void Transform::SetPosition(const glm::vec3& position) {
m_Position = position;
}
void Transform::SetPosition(float x, float y, float z) {
m_Position = glm::vec3(x, y, z);
}
void Transform::Translate(const glm::vec3& delta) {
m_Position += delta;
}
void Transform::Translate(float x, float y, float z) {
m_Position += glm::vec3(x, y, z);
}
// ===== 旋转 =====
void Transform::SetRotation(const glm::vec3& rotation) {
m_Rotation = rotation;
UpdateVectors();
}
void Transform::SetRotation(float pitch, float yaw, float roll) {
m_Rotation = glm::vec3(pitch, yaw, roll);
UpdateVectors();
}
void Transform::Rotate(const glm::vec3& delta) {
m_Rotation += delta;
UpdateVectors();
}
void Transform::Rotate(float pitch, float yaw, float roll) {
m_Rotation += glm::vec3(pitch, yaw, roll);
UpdateVectors();
}
// ===== 缩放 =====
void Transform::SetScale(const glm::vec3& scale) {
m_Scale = scale;
}
void Transform::SetScale(float uniform) {
m_Scale = glm::vec3(uniform);
}
void Transform::SetScale(float x, float y, float z) {
m_Scale = glm::vec3(x, y, z);
}
void Transform::Scale(const glm::vec3& delta) {
m_Scale += delta;
}
void Transform::Scale(float factor) {
m_Scale *= factor;
}
// ===== 获取变换矩阵 =====
glm::mat4 Transform::GetModelMatrix() const {
glm::mat4 model = glm::mat4(1.0f);
// 平移
model = glm::translate(model, m_Position);
// 旋转(按 Z, Y, X 顺序,避免万向锁)
model = glm::rotate(model, glm::radians(m_Rotation.z), glm::vec3(0, 0, 1));
model = glm::rotate(model, glm::radians(m_Rotation.y), glm::vec3(0, 1, 0));
model = glm::rotate(model, glm::radians(m_Rotation.x), glm::vec3(1, 0, 0));
// 缩放
model = glm::scale(model, m_Scale);
return model;
}
// ===== 更新方向向量 =====
void Transform::UpdateVectors() {
// 将欧拉角转换为弧度
float pitch = glm::radians(m_Rotation.x);
float yaw = glm::radians(m_Rotation.y);
float roll = glm::radians(m_Rotation.z);
// 计算前向向量
m_Forward.x = cos(yaw) * cos(pitch);
m_Forward.y = sin(pitch);
m_Forward.z = sin(yaw) * cos(pitch);
m_Forward = glm::normalize(m_Forward);
// 计算右向量
m_Right.x = cos(yaw);
m_Right.y = 0;
m_Right.z = sin(yaw);
m_Right = glm::normalize(m_Right);
// 计算上向量(前向与右向的叉积)
m_Up = glm::cross(m_Right, m_Forward);
m_Up = glm::normalize(m_Up);
}
// ===== 重置为单位变换 =====
void Transform::Reset() {
m_Position = glm::vec3(0.0f);
m_Rotation = glm::vec3(0.0f);
m_Scale = glm::vec3(1.0f);
UpdateVectors();
}
//===========================================================
// 文件: Texture.cpp
// 路径: CandyRenderEngine/Texture.cpp
// 说明: 纹理管理实现文件
//===========================================================
#include "pch.h"
#include "Texture.h"
// 包含 stb_image 头文件(实现放在单独的文件中)
#include "stb_image.h"
Texture::Texture()
: m_ID(0)
, m_Width(0)
, m_Height(0)
, m_Type("diffuse")
{
}
Texture::Texture(const std::string& path)
: m_ID(0)
, m_Width(0)
, m_Height(0)
, m_Path(path)
, m_Type("diffuse")
{
LoadFromFile(path);
}
Texture::Texture(const std::string& path, const std::string& type)
: m_ID(0)
, m_Width(0)
, m_Height(0)
, m_Path(path)
, m_Type(type)
{
LoadFromFile(path);
}
Texture::~Texture()
{
if (m_ID != 0)
{
glDeleteTextures(1, &m_ID);
}
}
bool Texture::LoadFromFile(const std::string& path)
{
if (m_ID != 0)
{
glDeleteTextures(1, &m_ID);
m_ID = 0;
}
int width, height, channels;
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0);
if (!data)
{
OutputDebugStringA(("Failed to load texture: " + path + "\n").c_str());
return false;
}
m_Width = width;
m_Height = height;
glGenTextures(1, &m_ID);
glBindTexture(GL_TEXTURE_2D, m_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLenum format = GL_RGB;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
else if (channels == 4)
format = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
OutputDebugStringA(("Loaded texture: " + path + "\n").c_str());
return true;
}
void Texture::Bind(unsigned int slot) const
{
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_ID);
}
void Texture::Unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
//===========================================================
// 文件: stb_image_impl.cpp
// 路径: CandyRenderEngine/stb_image_impl.cpp
// 说明: STB 图像库实现(只编译一次)
//===========================================================
#include "pch.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//===========================================================
// 文件: Shader.cpp
// 路径: CandyRenderEngine/Core/Shader.cpp
//===========================================================
#include "pch.h"
#include "Shader.h"
#include <fstream>
#include <sstream>
Shader::Shader() : m_ID(0) {}
Shader::~Shader() {
if (m_ID != 0) {
glDeleteProgram(m_ID);
}
}
bool Shader::LoadFromFile(const std::string& vertexPath, const std::string& fragmentPath) {
std::string vertexSource = ReadFile(vertexPath);
std::string fragmentSource = ReadFile(fragmentPath);
if (vertexSource.empty() || fragmentSource.empty()) {
return false;
}
return LoadFromSource(vertexSource, fragmentSource);
}
bool Shader::LoadFromSource(const std::string& vertexSource, const std::string& fragmentSource) {
if (m_ID != 0) {
glDeleteProgram(m_ID);
m_ID = 0;
m_UniformLocationCache.clear();
}
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) return false;
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShader == 0) {
glDeleteShader(vertexShader);
return false;
}
bool success = LinkProgram(vertexShader, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return success;
}
GLuint Shader::CompileShader(GLenum type, const std::string& source) {
GLuint shader = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
if (!CheckCompileErrors(shader, type == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT")) {
glDeleteShader(shader);
return 0;
}
return shader;
}
bool Shader::LinkProgram(GLuint vertexShader, GLuint fragmentShader) {
m_ID = glCreateProgram();
glAttachShader(m_ID, vertexShader);
glAttachShader(m_ID, fragmentShader);
glLinkProgram(m_ID);
if (!CheckLinkErrors(m_ID)) {
glDeleteProgram(m_ID);
m_ID = 0;
return false;
}
return true;
}
void Shader::Use() const {
if (m_ID != 0) {
glUseProgram(m_ID);
}
}
void Shader::Unuse() const {
glUseProgram(0);
}
void Shader::SetBool(const std::string& name, bool value) const {
SetInt(name, (int)value);
}
void Shader::SetInt(const std::string& name, int value) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniform1i(location, value);
}
void Shader::SetFloat(const std::string& name, float value) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniform1f(location, value);
}
void Shader::SetVec2(const std::string& name, const glm::vec2& value) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniform2fv(location, 1, glm::value_ptr(value));
}
void Shader::SetVec3(const std::string& name, const glm::vec3& value) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniform3fv(location, 1, glm::value_ptr(value));
}
void Shader::SetVec4(const std::string& name, const glm::vec4& value) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniform4fv(location, 1, glm::value_ptr(value));
}
void Shader::SetMat2(const std::string& name, const glm::mat2& mat) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniformMatrix2fv(location, 1, GL_FALSE, glm::value_ptr(mat));
}
void Shader::SetMat3(const std::string& name, const glm::mat3& mat) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(mat));
}
void Shader::SetMat4(const std::string& name, const glm::mat4& mat) const {
GLint location = GetUniformLocation(name);
if (location != -1) glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(mat));
}
GLint Shader::GetUniformLocation(const std::string& name) const {
if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end()) {
return m_UniformLocationCache[name];
}
GLint location = glGetUniformLocation(m_ID, name.c_str());
m_UniformLocationCache[name] = location;
if (location == -1) {
OutputDebugStringA(("Warning: Uniform '" + name + "' not found\n").c_str());
}
return location;
}
bool Shader::CheckCompileErrors(GLuint shader, const std::string& type) {
GLint success;
GLchar infoLog[1024];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::string msg = "Shader Compile Error (" + type + "):\n" + std::string(infoLog);
OutputDebugStringA(msg.c_str());
return false;
}
return true;
}
bool Shader::CheckLinkErrors(GLuint program) {
GLint success;
GLchar infoLog[1024];
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::string msg = "Program Link Error:\n" + std::string(infoLog);
OutputDebugStringA(msg.c_str());
return false;
}
return true;
}
std::string Shader::ReadFile(const std::string& filePath) {
std::ifstream file(filePath);
if (!file.is_open()) {
OutputDebugStringA(("Failed to open file: " + filePath + "\n").c_str());
return "";
}
std::stringstream buffer;
buffer << file.rdbuf();
return buffer.str();
}
//===========================================================
// 文件: Scene.cpp
// 路径: CandyRenderEngine/Scene.cpp
// 说明: 场景管理实现文件
//===========================================================
#include "pch.h"
#include "Scene.h"
#include "Model.h"
#include "Shader.h"
#include "Light.h"
#include "Camera.h"
Scene::Scene()
: m_Name("DefaultScene")
, m_CurrentTime(0.0f) {
}
Scene::Scene(const std::string& name)
: m_Name(name)
, m_CurrentTime(0.0f) {
}
Scene::~Scene() {
Clear();
}
void Scene::AddModel(std::shared_ptr<Model> model) {
if (model) {
m_Models.push_back(model);
}
}
void Scene::RemoveModel(Model* model) {
auto it = std::find_if(m_Models.begin(), m_Models.end(),
[model](const std::shared_ptr<Model>& ptr) { return ptr.get() == model; });
if (it != m_Models.end()) {
m_Models.erase(it);
}
}
void Scene::RemoveModel(size_t index) {
if (index < m_Models.size()) {
m_Models.erase(m_Models.begin() + index);
}
}
void Scene::ClearModels() {
m_Models.clear();
}
Model* Scene::GetModel(size_t index) const {
if (index < m_Models.size()) {
return m_Models[index].get();
}
return nullptr;
}
Model* Scene::FindModelByName(const std::string& name) const {
for (const auto& model : m_Models) {
if (model && model->GetName() == name) {
return model.get();
}
}
return nullptr;
}
void Scene::AddLight(std::shared_ptr<Light> light) {
if (light) {
m_Lights.push_back(light);
}
}
void Scene::RemoveLight(Light* light) {
auto it = std::find_if(m_Lights.begin(), m_Lights.end(),
[light](const std::shared_ptr<Light>& ptr) { return ptr.get() == light; });
if (it != m_Lights.end()) {
m_Lights.erase(it);
}
}
void Scene::ClearLights() {
m_Lights.clear();
}
Light* Scene::GetLight(size_t index) const {
if (index < m_Lights.size()) {
return m_Lights[index].get();
}
return nullptr;
}
void Scene::SetMainCamera(std::shared_ptr<Camera> camera) {
m_MainCamera = camera;
}
void Scene::Render(Shader& shader) const {
if (!m_MainCamera) return;
glm::mat4 view = m_MainCamera->GetViewMatrix();
glm::vec3 cameraPos = m_MainCamera->GetPosition();
shader.SetMat4("u_View", view);
shader.SetVec3("u_ViewPos", cameraPos);
shader.SetVec3("u_LightPos", glm::vec3(2.0f, 5.0f, 3.0f));
shader.SetVec3("u_LightColor", glm::vec3(1.0f, 1.0f, 1.0f));
for (const auto& model : m_Models) {
if (model) {
model->Draw(shader);
}
}
}
void Scene::Update(float deltaTime) {
m_CurrentTime += deltaTime;
}
void Scene::Clear() {
m_Models.clear();
m_Lights.clear();
m_MainCamera = nullptr;
m_CurrentTime = 0.0f;
}
//===========================================================
// 文件: Renderer.cpp
// 路径: CandyRenderEngine/Renderer.cpp
// 说明: 主渲染器实现
//===========================================================
#include "pch.h"
#include "Renderer.h"
#include "Camera.h"
#include "Transform.h"
#include <glad/glad.h>
#include <vector>
#pragma comment(lib, "opengl32.lib")
// 顶点着色器
static const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 ourColor;
uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;
void main() {
gl_Position = u_Projection * u_View * u_Model * vec4(aPos, 1.0);
ourColor = aColor;
}
)";
// 片段着色器
static const char* fragmentShaderSource = R"(
#version 330 core
in vec3 ourColor;
out vec4 FragColor;
void main() {
FragColor = vec4(ourColor, 1.0);
}
)";
// 网格顶点着色器
static const char* gridVertexSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 u_View;
uniform mat4 u_Projection;
void main() {
gl_Position = u_Projection * u_View * vec4(aPos, 1.0);
}
)";
// 网格片段着色器
static const char* gridFragmentSource = R"(
#version 330 core
out vec4 FragColor;
void main() {
FragColor = vec4(0.3, 0.3, 0.4, 1.0);
}
)";
static GLuint CompileShader(GLenum type, const char* source) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
OutputDebugStringA(("Shader compile error: " + std::string(infoLog) + "\n").c_str());
glDeleteShader(shader);
return 0;
}
return shader;
}
static GLuint LinkProgram(GLuint vs, GLuint fs) {
GLuint program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(program, 512, nullptr, infoLog);
OutputDebugStringA(("Program link error: " + std::string(infoLog) + "\n").c_str());
glDeleteProgram(program);
return 0;
}
return program;
}
Renderer::Renderer()
: hwnd(nullptr)
, hdc(nullptr)
, hglrc(nullptr)
, initialized(false)
, shaderProgram(0)
, gridProgram(0)
, VAO(0)
, VBO(0)
, EBO(0)
, gridVAO(0)
, gridVBO(0)
, m_Camera(nullptr)
, m_ModelTransform(nullptr)
, m_WireframeMode(false)
, m_ShowGrid(true) {
}
Renderer::~Renderer() {
Shutdown();
}
bool Renderer::Initialize(HWND parentHwnd, int width, int height) {
OutputDebugStringA("=== Renderer Initialize START ===\n");
hwnd = parentHwnd;
hdc = GetDC(hwnd);
if (!hdc) {
OutputDebugStringA("GetDC failed\n");
return false;
}
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), 1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, 32,
0,0,0,0,0,0,0,0,0,0,0,0,0,
24,8,0,PFD_MAIN_PLANE,0,0,0,0
};
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
if (!pixelFormat) {
OutputDebugStringA("ChoosePixelFormat failed\n");
return false;
}
if (!SetPixelFormat(hdc, pixelFormat, &pfd)) {
OutputDebugStringA("SetPixelFormat failed\n");
return false;
}
hglrc = wglCreateContext(hdc);
if (!hglrc) {
OutputDebugStringA("wglCreateContext failed\n");
return false;
}
if (!wglMakeCurrent(hdc, hglrc)) {
OutputDebugStringA("wglMakeCurrent failed\n");
return false;
}
if (!gladLoadGL()) {
OutputDebugStringA("gladLoadGL failed\n");
return false;
}
const char* version = (const char*)glGetString(GL_VERSION);
OutputDebugStringA(("OpenGL Version: " + std::string(version) + "\n").c_str());
// 编译着色器
GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShaderSource);
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
shaderProgram = LinkProgram(vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
vs = CompileShader(GL_VERTEX_SHADER, gridVertexSource);
fs = CompileShader(GL_FRAGMENT_SHADER, gridFragmentSource);
gridProgram = LinkProgram(vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
CreateCube();
CreateGrid();
// 创建相机和变换对象
m_Camera = new Camera();
m_ModelTransform = new Transform();
m_Camera->SetPosition(glm::vec3(3.0f, 3.0f, 5.0f));
m_Camera->SetTarget(glm::vec3(0.0f));
m_Camera->EnableOrbitMode(true);
m_Camera->SetZoom(45.0f);
m_ModelTransform->SetScale(1.0f);
m_ModelTransform->SetRotation(45.0f, 45.0f, 0.0f);
glViewport(0, 0, width, height);
glEnable(GL_DEPTH_TEST);
initialized = true;
OutputDebugStringA("=== Renderer Initialize SUCCESS ===\n");
return true;
}
void Renderer::CreateCube() {
float vertices[] = {
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 1.0f, 0.5f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f,
0.5f, 0.5f, -0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f,
};
unsigned int indices[] = {
0,1,2, 2,3,0, 1,5,6, 6,2,1,
5,4,7, 7,6,5, 4,0,3, 3,7,4,
3,2,6, 6,7,3, 4,5,1, 1,0,4
};
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);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
void Renderer::CreateGrid() {
std::vector<float> vertices;
int gridSize = 20;
float step = 0.5f;
float start = -gridSize * step / 2;
for (int i = 0; i <= gridSize; i++) {
float pos = start + i * step;
vertices.push_back(pos); vertices.push_back(0.0f); vertices.push_back(start);
vertices.push_back(pos); vertices.push_back(0.0f); vertices.push_back(-start);
vertices.push_back(start); vertices.push_back(0.0f); vertices.push_back(pos);
vertices.push_back(-start); vertices.push_back(0.0f); vertices.push_back(pos);
}
glGenVertexArrays(1, &gridVAO);
glGenBuffers(1, &gridVBO);
glBindVertexArray(gridVAO);
glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
void Renderer::RenderFrame() {
if (!initialized || !m_Camera || !m_ModelTransform) return;
glClearColor(0.15f, 0.15f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RECT rect;
GetClientRect(hwnd, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
if (width == 0) width = 1;
if (height == 0) height = 1;
float aspect = (float)width / (float)height;
glm::mat4 projection = m_Camera->GetProjectionMatrix(aspect);
glm::mat4 view = m_Camera->GetViewMatrix();
glm::mat4 model = m_ModelTransform->GetModelMatrix();
// 绘制网格
if (m_ShowGrid) {
glUseProgram(gridProgram);
glUniformMatrix4fv(glGetUniformLocation(gridProgram, "u_View"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(gridProgram, "u_Projection"), 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(gridVAO);
// 修复:计算正确的顶点数量
// 网格线数量 = (gridSize+1) * 4 条线,每条线2个顶点
int gridSize = 20;
int vertexCount = (gridSize + 1) * 4 * 2;
glDrawArrays(GL_LINES, 0, vertexCount);
glBindVertexArray(0);
}
// 绘制立方体
glUseProgram(shaderProgram);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_Model"), 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_View"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_Projection"), 1, GL_FALSE, glm::value_ptr(projection));
if (m_WireframeMode) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
if (m_WireframeMode) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
SwapBuffers(hdc);
}
void Renderer::ProcessMouseMovement(float xOffset, float yOffset) {
if (m_Camera) m_Camera->ProcessMouseMovement(xOffset, yOffset);
}
void Renderer::ProcessMouseScroll(float yOffset) {
if (m_Camera) m_Camera->ProcessMouseScroll(yOffset);
}
void Renderer::ProcessPan(float xOffset, float yOffset) {
if (m_Camera) m_Camera->ProcessPan(xOffset, yOffset);
}
void Renderer::ResetCamera() {
if (m_Camera) m_Camera->Reset();
}
void Renderer::FitView() {
if (m_Camera) {
m_Camera->SetTarget(glm::vec3(0.0f));
m_Camera->SetPosition(glm::vec3(3.0f, 3.0f, 5.0f));
m_Camera->SetZoom(45.0f);
}
}
void Renderer::SetModelRotation(float x, float y, float z) {
if (m_ModelTransform) m_ModelTransform->SetRotation(x, y, z);
}
void Renderer::SetModelScale(float scale) {
if (m_ModelTransform) m_ModelTransform->SetScale(scale);
}
void Renderer::SetModelPosition(float x, float y, float z) {
if (m_ModelTransform) m_ModelTransform->SetPosition(x, y, z);
}
void Renderer::SetWireframeMode(bool enabled) {
m_WireframeMode = enabled;
}
void Renderer::ShowGrid(bool show) {
m_ShowGrid = show;
}
void Renderer::GetCameraPosition(float& x, float& y, float& z) {
if (m_Camera) {
glm::vec3 pos = m_Camera->GetPosition();
x = pos.x;
y = pos.y;
z = pos.z;
}
else {
x = y = z = 0;
}
}
void Renderer::Resize(int width, int height) {
if (initialized) {
glViewport(0, 0, width, height);
}
}
void Renderer::Shutdown() {
if (initialized) {
if (EBO) glDeleteBuffers(1, &EBO);
if (VBO) glDeleteBuffers(1, &VBO);
if (VAO) glDeleteVertexArrays(1, &VAO);
if (gridVBO) glDeleteBuffers(1, &gridVBO);
if (gridVAO) glDeleteVertexArrays(1, &gridVAO);
if (shaderProgram) glDeleteProgram(shaderProgram);
if (gridProgram) glDeleteProgram(gridProgram);
delete m_Camera;
delete m_ModelTransform;
m_Camera = nullptr;
m_ModelTransform = nullptr;
if (hglrc) {
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(hglrc);
hglrc = nullptr;
}
if (hdc && hwnd) {
ReleaseDC(hwnd, hdc);
hdc = nullptr;
}
hwnd = nullptr;
initialized = false;
}
}
//===========================================================
// 文件: pch.cpp
// 路径: CandyRenderEngine/pch.cpp
// 说明: 预编译头对应的源文件,用于生成预编译头文件 (.pch)
// 依赖: pch.h
//===========================================================
#include "pch.h"
//===========================================================
// 文件: Model.cpp
// 路径: CandyRenderEngine/Model.cpp
// 说明: 模型管理实现文件
//===========================================================
#include "pch.h"
#include "Model.h"
#include "Shader.h"
#include <cmath>
#include <limits>
#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F
#endif
Model::Model()
: m_Name("Empty")
, m_Visible(true)
, m_MinBounds(0.0f)
, m_MaxBounds(0.0f) {
}
Model::Model(const std::string& path)
: m_Name(path)
, m_Visible(true)
, m_MinBounds(0.0f)
, m_MaxBounds(0.0f) {
LoadModel(path);
}
Model::~Model() {
ClearMeshes();
}
bool Model::LoadModel(const std::string& path) {
OutputDebugStringA(("Loading model: " + path + "\n").c_str());
return true;
}
void Model::Draw(Shader& shader) const {
if (!m_Visible) return;
shader.SetMat4("u_Model", m_Transform.GetModelMatrix());
for (const auto& mesh : m_Meshes) {
if (mesh) {
mesh->Draw(shader);
}
}
}
void Model::AddMesh(std::shared_ptr<Mesh> mesh) {
if (mesh) {
m_Meshes.push_back(mesh);
CalculateBoundingBox();
}
}
void Model::ClearMeshes() {
m_Meshes.clear();
}
Mesh* Model::GetMesh(size_t index) const {
if (index < m_Meshes.size()) {
return m_Meshes[index].get();
}
return nullptr;
}
void Model::SetPosition(const glm::vec3& position) {
m_Transform.SetPosition(position);
}
void Model::SetRotation(const glm::vec3& rotation) {
m_Transform.SetRotation(rotation);
}
void Model::SetScale(const glm::vec3& scale) {
m_Transform.SetScale(scale);
}
void Model::CalculateBoundingBox() {
if (m_Meshes.empty()) {
m_MinBounds = glm::vec3(0.0f);
m_MaxBounds = glm::vec3(0.0f);
return;
}
glm::vec3 minBounds(FLT_MAX);
glm::vec3 maxBounds(-FLT_MAX);
for (const auto& mesh : m_Meshes) {
if (!mesh) continue;
for (const auto& vertex : mesh->GetVertices()) {
glm::vec3 worldPos = m_Transform.GetModelMatrix() * glm::vec4(vertex.Position, 1.0f);
minBounds.x = (std::min)(minBounds.x, worldPos.x);
minBounds.y = (std::min)(minBounds.y, worldPos.y);
minBounds.z = (std::min)(minBounds.z, worldPos.z);
maxBounds.x = (std::max)(maxBounds.x, worldPos.x);
maxBounds.y = (std::max)(maxBounds.y, worldPos.y);
maxBounds.z = (std::max)(maxBounds.z, worldPos.z);
}
}
m_MinBounds = minBounds;
m_MaxBounds = maxBounds;
}
float Model::GetRadius() const {
glm::vec3 center = GetCenter();
float maxDist = 0.0f;
glm::vec3 corners[8] = {
m_MinBounds,
glm::vec3(m_MaxBounds.x, m_MinBounds.y, m_MinBounds.z),
glm::vec3(m_MinBounds.x, m_MaxBounds.y, m_MinBounds.z),
glm::vec3(m_MaxBounds.x, m_MaxBounds.y, m_MinBounds.z),
glm::vec3(m_MinBounds.x, m_MinBounds.y, m_MaxBounds.z),
glm::vec3(m_MaxBounds.x, m_MinBounds.y, m_MaxBounds.z),
glm::vec3(m_MinBounds.x, m_MaxBounds.y, m_MaxBounds.z),
m_MaxBounds
};
for (const auto& corner : corners) {
float dist = glm::distance(center, corner);
maxDist = (std::max)(maxDist, dist);
}
return maxDist;
}
//===========================================================
// 文件: Mesh.cpp
// 路径: CandyRenderEngine/Mesh.cpp
// 说明: 网格数据管理实现文件
//===========================================================
#include "pch.h"
#include "Mesh.h"
#include "Shader.h"
Mesh::Mesh()
: m_VAO(0), m_VBO(0), m_EBO(0), m_IsInitialized(false) {
}
Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices)
: m_Vertices(vertices)
, m_Indices(indices)
, m_VAO(0), m_VBO(0), m_EBO(0)
, m_IsInitialized(false) {
SetupMesh();
}
Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices,
const std::vector<std::shared_ptr<Texture>>& textures)
: m_Vertices(vertices)
, m_Indices(indices)
, m_Textures(textures)
, m_VAO(0), m_VBO(0), m_EBO(0)
, m_IsInitialized(false) {
SetupMesh();
}
Mesh::~Mesh() {
Clear();
}
void Mesh::SetupMesh() {
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
glGenBuffers(1, &m_EBO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), m_Vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_Indices.size() * sizeof(unsigned int), m_Indices.data(), GL_STATIC_DRAW);
// 位置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(0);
// 法线
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(1);
// 纹理坐标
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
glEnableVertexAttribArray(2);
// 切线
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
glEnableVertexAttribArray(3);
// 副切线
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));
glEnableVertexAttribArray(4);
glBindVertexArray(0);
m_IsInitialized = true;
}
void Mesh::Draw(Shader& shader) const {
if (!m_IsInitialized || m_Vertices.empty()) return;
unsigned int diffuseIdx = 0;
unsigned int specularIdx = 0;
unsigned int normalIdx = 0;
unsigned int heightIdx = 0;
for (size_t i = 0; i < m_Textures.size(); ++i) {
if (m_Textures[i]) {
m_Textures[i]->Bind((unsigned int)i);
std::string name = m_Textures[i]->GetType();
std::string uniformName;
if (name == "diffuse") {
uniformName = "material.diffuse" + std::to_string(diffuseIdx++);
}
else if (name == "specular") {
uniformName = "material.specular" + std::to_string(specularIdx++);
}
else if (name == "normal") {
uniformName = "material.normal" + std::to_string(normalIdx++);
}
else if (name == "height") {
uniformName = "material.height" + std::to_string(heightIdx++);
}
else {
uniformName = "material." + name;
}
shader.SetInt(uniformName, (int)i);
}
}
glBindVertexArray(m_VAO);
glDrawElements(GL_TRIANGLES, (GLsizei)m_Indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE0);
}
void Mesh::SetVertices(const std::vector<Vertex>& vertices) {
m_Vertices = vertices;
if (m_IsInitialized) {
SetupMesh();
}
}
void Mesh::SetIndices(const std::vector<unsigned int>& indices) {
m_Indices = indices;
if (m_IsInitialized) {
SetupMesh();
}
}
void Mesh::SetTextures(const std::vector<std::shared_ptr<Texture>>& textures) {
m_Textures = textures;
}
void Mesh::Clear() {
if (m_IsInitialized) {
if (m_VAO != 0) {
glDeleteVertexArrays(1, &m_VAO);
m_VAO = 0;
}
if (m_VBO != 0) {
glDeleteBuffers(1, &m_VBO);
m_VBO = 0;
}
if (m_EBO != 0) {
glDeleteBuffers(1, &m_EBO);
m_EBO = 0;
}
m_IsInitialized = false;
}
m_Vertices.clear();
m_Indices.clear();
m_Textures.clear();
}
//===========================================================
// 文件: Material.cpp
// 路径: CandyRenderEngine/Material.cpp
// 说明: 材质系统实现文件
//===========================================================
#include "pch.h"
#include "Material.h"
#include "Shader.h"
#include "Texture.h"
Material::Material()
: m_Name("DefaultMaterial") {
}
Material::Material(const MaterialProperties& properties)
: m_Properties(properties)
, m_Name("CustomMaterial") {
}
Material::~Material() {
ClearTextures();
}
void Material::SetProperties(const MaterialProperties& properties) {
m_Properties = properties;
}
void Material::SetTexture(const std::string& type, std::shared_ptr<Texture> texture) {
if (texture) {
m_Textures[type] = texture;
}
}
std::shared_ptr<Texture> Material::GetTexture(const std::string& type) const {
auto it = m_Textures.find(type);
if (it != m_Textures.end()) {
return it->second;
}
return nullptr;
}
void Material::ClearTextures() {
m_Textures.clear();
}
void Material::Apply(Shader& shader) const {
// 应用材质属性
shader.SetVec3("material.ambient", m_Properties.Ambient);
shader.SetVec3("material.diffuse", m_Properties.Diffuse);
shader.SetVec3("material.specular", m_Properties.Specular);
shader.SetFloat("material.shininess", m_Properties.Shininess);
shader.SetFloat("material.opacity", m_Properties.Opacity);
shader.SetFloat("material.metallic", m_Properties.Metallic);
shader.SetFloat("material.roughness", m_Properties.Roughness);
// 应用纹理
int textureSlot = 0;
for (const auto& pair : m_Textures) {
if (pair.second) {
pair.second->Bind(textureSlot);
shader.SetInt(("material." + pair.first).c_str(), textureSlot);
textureSlot++;
}
}
}
//===========================================================
// 文件: Light.cpp
// 路径: CandyRenderEngine/Light.cpp
// 说明: 光源管理实现文件
//===========================================================
#include "pch.h"
#include "Light.h"
Light::Light()
: m_Type(LightType::Point)
, m_Position(0.0f, 5.0f, 5.0f)
, m_Direction(0.0f, -1.0f, 0.0f)
, m_Color(1.0f, 1.0f, 1.0f)
, m_Intensity(1.0f)
, m_Range(10.0f)
, m_ConstantAttenuation(1.0f)
, m_LinearAttenuation(0.09f)
, m_QuadraticAttenuation(0.032f)
, m_InnerAngle(35.0f)
, m_OuterAngle(45.0f)
, m_Enabled(true) {
}
Light::Light(LightType type)
: m_Type(type)
, m_Position(0.0f, 5.0f, 5.0f)
, m_Direction(0.0f, -1.0f, 0.0f)
, m_Color(1.0f, 1.0f, 1.0f)
, m_Intensity(1.0f)
, m_Range(10.0f)
, m_ConstantAttenuation(1.0f)
, m_LinearAttenuation(0.09f)
, m_QuadraticAttenuation(0.032f)
, m_InnerAngle(35.0f)
, m_OuterAngle(45.0f)
, m_Enabled(true) {
// 根据类型设置默认方向
if (type == LightType::Directional) {
m_Direction = glm::vec3(0.0f, -1.0f, 0.0f);
}
}
void Light::SetAttenuation(float constant, float linear, float quadratic) {
m_ConstantAttenuation = constant;
m_LinearAttenuation = linear;
m_QuadraticAttenuation = quadratic;
}
void Light::GetAttenuation(float& constant, float& linear, float& quadratic) const {
constant = m_ConstantAttenuation;
linear = m_LinearAttenuation;
quadratic = m_QuadraticAttenuation;
}
void Light::SetSpotAngle(float innerAngle, float outerAngle) {
m_InnerAngle = innerAngle;
m_OuterAngle = outerAngle;
}
//===========================================================
// 文件: Frustum.cpp
// 路径: CandyRenderEngine/Frustum.cpp
// 说明: 视锥体实现文件
//===========================================================
#include "pch.h"
#include "Frustum.h"
#include <cmath>
Frustum::Frustum() {
for (int i = 0; i < 6; ++i) {
m_Planes[i] = glm::vec4(0.0f);
}
}
void Frustum::Update(const glm::mat4& viewProjection) {
// 提取视锥体平面
// 左平面
m_Planes[0].x = viewProjection[0][3] + viewProjection[0][0];
m_Planes[0].y = viewProjection[1][3] + viewProjection[1][0];
m_Planes[0].z = viewProjection[2][3] + viewProjection[2][0];
m_Planes[0].w = viewProjection[3][3] + viewProjection[3][0];
// 右平面
m_Planes[1].x = viewProjection[0][3] - viewProjection[0][0];
m_Planes[1].y = viewProjection[1][3] - viewProjection[1][0];
m_Planes[1].z = viewProjection[2][3] - viewProjection[2][0];
m_Planes[1].w = viewProjection[3][3] - viewProjection[3][0];
// 下平面
m_Planes[2].x = viewProjection[0][3] + viewProjection[0][1];
m_Planes[2].y = viewProjection[1][3] + viewProjection[1][1];
m_Planes[2].z = viewProjection[2][3] + viewProjection[2][1];
m_Planes[2].w = viewProjection[3][3] + viewProjection[3][1];
// 上平面
m_Planes[3].x = viewProjection[0][3] - viewProjection[0][1];
m_Planes[3].y = viewProjection[1][3] - viewProjection[1][1];
m_Planes[3].z = viewProjection[2][3] - viewProjection[2][1];
m_Planes[3].w = viewProjection[3][3] - viewProjection[3][1];
// 近平面
m_Planes[4].x = viewProjection[0][3] + viewProjection[0][2];
m_Planes[4].y = viewProjection[1][3] + viewProjection[1][2];
m_Planes[4].z = viewProjection[2][3] + viewProjection[2][2];
m_Planes[4].w = viewProjection[3][3] + viewProjection[3][2];
// 远平面
m_Planes[5].x = viewProjection[0][3] - viewProjection[0][2];
m_Planes[5].y = viewProjection[1][3] - viewProjection[1][2];
m_Planes[5].z = viewProjection[2][3] - viewProjection[2][2];
m_Planes[5].w = viewProjection[3][3] - viewProjection[3][2];
// 归一化所有平面
for (int i = 0; i < 6; ++i) {
float length = sqrt(m_Planes[i].x * m_Planes[i].x +
m_Planes[i].y * m_Planes[i].y +
m_Planes[i].z * m_Planes[i].z);
if (length > 0.0f) {
m_Planes[i] /= length;
}
}
}
bool Frustum::IsBoxVisible(const BoundingBox& box) const {
if (!box.IsValid()) return true;
glm::vec3 corners[8];
box.GetCorners(corners);
for (int i = 0; i < 6; ++i) {
const glm::vec4& plane = m_Planes[i];
bool allOutside = true;
for (int j = 0; j < 8; ++j) {
float distance = plane.x * corners[j].x + plane.y * corners[j].y +
plane.z * corners[j].z + plane.w;
if (distance >= 0) {
allOutside = false;
break;
}
}
if (allOutside) return false;
}
return true;
}
bool Frustum::IsSphereVisible(const glm::vec3& center, float radius) const {
for (int i = 0; i < 6; ++i) {
const glm::vec4& plane = m_Planes[i];
float distance = plane.x * center.x + plane.y * center.y +
plane.z * center.z + plane.w;
if (distance < -radius) {
return false;
}
}
return true;
}
bool Frustum::IsPointVisible(const glm::vec3& point) const {
for (int i = 0; i < 6; ++i) {
const glm::vec4& plane = m_Planes[i];
float distance = plane.x * point.x + plane.y * point.y +
plane.z * point.z + plane.w;
if (distance < 0) {
return false;
}
}
return true;
}
//===========================================================
// 文件: Export.cpp
// 路径: CandyRenderEngine/Export.cpp
// 说明: DLL 导出函数实现
//===========================================================
#include "pch.h"
#include "Export.h"
#include "Renderer.h"
static Renderer g_Renderer;
bool Initialize(HWND hwnd, int width, int height) {
return g_Renderer.Initialize(hwnd, width, height);
}
void Shutdown() {
g_Renderer.Shutdown();
}
void RenderFrame() {
g_Renderer.RenderFrame();
}
void Resize(int width, int height) {
g_Renderer.Resize(width, height);
}
void ProcessMouseMovement(float xOffset, float yOffset) {
g_Renderer.ProcessMouseMovement(xOffset, yOffset);
}
void ProcessMouseScroll(float yOffset) {
g_Renderer.ProcessMouseScroll(yOffset);
}
void ProcessPan(float xOffset, float yOffset) {
g_Renderer.ProcessPan(xOffset, yOffset);
}
void ResetCamera() {
g_Renderer.ResetCamera();
}
void FitView() {
g_Renderer.FitView();
}
void SetModelRotation(float x, float y, float z) {
g_Renderer.SetModelRotation(x, y, z);
}
void SetModelScale(float scale) {
g_Renderer.SetModelScale(scale);
}
void SetModelPosition(float x, float y, float z) {
g_Renderer.SetModelPosition(x, y, z);
}
void SetWireframeMode(bool enabled) {
g_Renderer.SetWireframeMode(enabled);
}
void ShowGrid(bool show) {
g_Renderer.ShowGrid(show);
}
void GetCameraPosition(float* x, float* y, float* z) {
g_Renderer.GetCameraPosition(*x, *y, *z);
}
bool GetWireframeMode() {
return g_Renderer.GetWireframeMode();
}
bool IsGridVisible() {
return g_Renderer.IsGridVisible();
}
//===========================================================
// 文件: dllmain.cpp
// 路径: CandyRenderEngine/dllmain.cpp
// 说明: DLL 入口点文件,处理 DLL 的加载/卸载事件
// 依赖: pch.h, windows.h
//===========================================================
#include "pch.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// DLL 被加载到进程地址空间时调用
break;
case DLL_THREAD_ATTACH:
// 进程中创建新线程时调用
break;
case DLL_THREAD_DETACH:
// 线程正常退出时调用
break;
case DLL_PROCESS_DETACH:
// DLL 从进程地址空间卸载时调用
break;
}
return TRUE;
}
//===========================================================
// 文件: Camera.cpp
// 路径: CandyRenderEngine/Core/Camera.cpp
// 说明: 相机系统实现文件,实现平移、旋转、缩放的具体逻辑
// 依赖: Camera.h, GLM 数学库
//===========================================================
#include "pch.h"
#include "Camera.h"
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
Camera::Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch)
: m_Position(position)
, m_WorldUp(up)
, m_Yaw(yaw)
, m_Pitch(pitch)
, m_Zoom(45.0f)
, m_MoveSpeed(5.0f)
, m_RotateSpeed(0.5f)
, m_ZoomSpeed(2.0f)
, m_Target(0.0f)
, m_Radius(5.0f)
, m_OrbitMode(false)
{
for (int i = 0; i < 6; i++) m_Keys[i] = false;
UpdateCameraVectors();
}
// ===== 获取视图矩阵 =====
glm::mat4 Camera::GetViewMatrix() const {
if (m_OrbitMode) {
// 轨道模式:相机围绕目标点旋转
return glm::lookAt(m_Position, m_Target, m_Up);
}
return glm::lookAt(m_Position, m_Position + m_Front, m_Up);
}
// ===== 获取投影矩阵 =====
glm::mat4 Camera::GetProjectionMatrix(float aspectRatio) const {
return glm::perspective(glm::radians(m_Zoom), aspectRatio, 0.1f, 1000.0f);
}
// ===== 键盘移动 =====
void Camera::ProcessKeyboard(CameraMovement direction, float deltaTime) {
float velocity = m_MoveSpeed * deltaTime;
if (m_OrbitMode) {
// 轨道模式下,移动目标点
switch (direction) {
case CameraMovement::FORWARD:
m_Target += m_Front * velocity;
break;
case CameraMovement::BACKWARD:
m_Target -= m_Front * velocity;
break;
case CameraMovement::LEFT:
m_Target -= m_Right * velocity;
break;
case CameraMovement::RIGHT:
m_Target += m_Right * velocity;
break;
case CameraMovement::UP:
m_Target += m_WorldUp * velocity;
break;
case CameraMovement::DOWN:
m_Target -= m_WorldUp * velocity;
break;
}
// 更新相机位置(保持距离)
m_Position = m_Target - m_Front * m_Radius;
}
else {
// 自由模式:移动相机位置
switch (direction) {
case CameraMovement::FORWARD:
m_Position += m_Front * velocity;
break;
case CameraMovement::BACKWARD:
m_Position -= m_Front * velocity;
break;
case CameraMovement::LEFT:
m_Position -= m_Right * velocity;
break;
case CameraMovement::RIGHT:
m_Position += m_Right * velocity;
break;
case CameraMovement::UP:
m_Position += m_WorldUp * velocity;
break;
case CameraMovement::DOWN:
m_Position -= m_WorldUp * velocity;
break;
}
}
}
// ===== 鼠标旋转 =====
void Camera::ProcessMouseMovement(float xOffset, float yOffset, bool constrainPitch) {
xOffset *= m_RotateSpeed;
yOffset *= m_RotateSpeed;
m_Yaw += xOffset;
m_Pitch += yOffset;
// 限制俯仰角,防止翻转
if (constrainPitch) {
if (m_Pitch > 89.0f) m_Pitch = 89.0f;
if (m_Pitch < -89.0f) m_Pitch = -89.0f;
}
// 更新方向向量
UpdateCameraVectors();
// 轨道模式下,更新相机位置
if (m_OrbitMode) {
m_Position = m_Target - m_Front * m_Radius;
}
}
// ===== 鼠标滚轮缩放 =====
void Camera::ProcessMouseScroll(float yOffset) {
m_Zoom -= yOffset * m_ZoomSpeed;
if (m_Zoom < 1.0f) m_Zoom = 1.0f;
if (m_Zoom > 89.0f) m_Zoom = 89.0f;
}
// ===== 平移动画/平移 =====
void Camera::ProcessPan(float xOffset, float yOffset) {
float panSpeed = 0.01f;
glm::vec3 right = glm::normalize(glm::cross(m_Front, m_WorldUp));
glm::vec3 up = glm::normalize(glm::cross(right, m_Front));
if (m_OrbitMode) {
m_Target += right * xOffset * panSpeed;
m_Target += up * yOffset * panSpeed;
m_Position = m_Target - m_Front * m_Radius;
}
else {
m_Position += right * xOffset * panSpeed;
m_Position += up * yOffset * panSpeed;
}
}
// ===== 旋转视图(触摸/手势)=====
void Camera::ProcessRotate(float angleDelta) {
// 简化实现,实际可根据需求扩展
m_Yaw += angleDelta;
UpdateCameraVectors();
if (m_OrbitMode) {
m_Position = m_Target - m_Front * m_Radius;
}
}
// ===== 双指缩放 =====
void Camera::ProcessPinch(float zoomDelta) {
float newZoom = m_Zoom - zoomDelta;
if (newZoom < 1.0f) newZoom = 1.0f;
if (newZoom > 89.0f) newZoom = 89.0f;
m_Zoom = newZoom;
}
// ===== 轨道旋转 =====
void Camera::OrbitRotate(float xOffset, float yOffset) {
if (!m_OrbitMode) return;
m_Yaw += xOffset * m_RotateSpeed;
m_Pitch += yOffset * m_RotateSpeed;
if (m_Pitch > 89.0f) m_Pitch = 89.0f;
if (m_Pitch < -89.0f) m_Pitch = -89.0f;
UpdateCameraVectors();
m_Position = m_Target - m_Front * m_Radius;
}
// ===== 轨道缩放 =====
void Camera::OrbitZoom(float zoomDelta) {
if (!m_OrbitMode) return;
m_Radius -= zoomDelta * m_ZoomSpeed;
if (m_Radius < 0.5f) m_Radius = 0.5f;
if (m_Radius > 100.0f) m_Radius = 100.0f;
m_Position = m_Target - m_Front * m_Radius;
}
// ===== 轨道平移 =====
void Camera::OrbitPan(float xOffset, float yOffset) {
if (!m_OrbitMode) return;
float panSpeed = 0.01f;
glm::vec3 right = glm::normalize(glm::cross(m_Front, m_WorldUp));
glm::vec3 up = glm::normalize(glm::cross(right, m_Front));
m_Target += right * xOffset * panSpeed;
m_Target += up * yOffset * panSpeed;
m_Position = m_Target - m_Front * m_Radius;
}
// ===== 设置目标点 =====
void Camera::SetTarget(const glm::vec3& target) {
m_Target = target;
if (m_OrbitMode) {
m_Radius = glm::distance(m_Position, target);
UpdateCameraVectors();
}
}
// ===== 重置相机 =====
void Camera::Reset() {
m_Position = glm::vec3(0.0f, 0.0f, 5.0f);
m_Target = glm::vec3(0.0f);
m_Radius = 5.0f;
m_Yaw = -90.0f;
m_Pitch = 0.0f;
m_Zoom = 45.0f;
UpdateCameraVectors();
if (m_OrbitMode) {
m_Position = m_Target - m_Front * m_Radius;
}
}
// ===== 设置相机位置 =====
void Camera::SetPosition(const glm::vec3& position) {
m_Position = position;
if (m_OrbitMode) {
m_Radius = glm::distance(position, m_Target);
UpdateCameraVectors();
}
}
// ===== 设置偏航角 =====
void Camera::SetYaw(float yaw) {
m_Yaw = yaw;
UpdateCameraVectors();
}
// ===== 设置俯仰角 =====
void Camera::SetPitch(float pitch) {
m_Pitch = pitch;
if (m_Pitch > 89.0f) m_Pitch = 89.0f;
if (m_Pitch < -89.0f) m_Pitch = -89.0f;
UpdateCameraVectors();
}
// ===== 设置缩放 =====
void Camera::SetZoom(float zoom) {
m_Zoom = zoom;
if (m_Zoom < 1.0f) m_Zoom = 1.0f;
if (m_Zoom > 89.0f) m_Zoom = 89.0f;
}
// ===== 设置移动速度 =====
void Camera::SetSpeed(float moveSpeed, float rotateSpeed, float zoomSpeed) {
m_MoveSpeed = moveSpeed;
m_RotateSpeed = rotateSpeed;
m_ZoomSpeed = zoomSpeed;
}
// ===== 更新方向向量 =====
void Camera::UpdateCameraVectors() {
// 计算新的前向向量
glm::vec3 front;
front.x = cos(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch));
front.y = sin(glm::radians(m_Pitch));
front.z = sin(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch));
m_Front = glm::normalize(front);
// 计算右向量和上向量
m_Right = glm::normalize(glm::cross(m_Front, m_WorldUp));
m_Up = glm::normalize(glm::cross(m_Right, m_Front));
}
//===========================================================
// 文件: BoundingBox.cpp
// 路径: CandyRenderEngine/BoundingBox.cpp
// 说明: 包围盒实现文件
//===========================================================
#include "pch.h"
#include "BoundingBox.h"
#include <algorithm>
#include <cmath>
#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F
#endif
BoundingBox::BoundingBox()
: m_Min(FLT_MAX, FLT_MAX, FLT_MAX)
, m_Max(-FLT_MAX, -FLT_MAX, -FLT_MAX) {
}
BoundingBox::BoundingBox(const glm::vec3& min, const glm::vec3& max)
: m_Min(min)
, m_Max(max) {
}
void BoundingBox::Merge(const BoundingBox& other) {
if (!other.IsValid()) return;
m_Min.x = (std::min)(m_Min.x, other.m_Min.x);
m_Min.y = (std::min)(m_Min.y, other.m_Min.y);
m_Min.z = (std::min)(m_Min.z, other.m_Min.z);
m_Max.x = (std::max)(m_Max.x, other.m_Max.x);
m_Max.y = (std::max)(m_Max.y, other.m_Max.y);
m_Max.z = (std::max)(m_Max.z, other.m_Max.z);
}
void BoundingBox::Merge(const glm::vec3& point) {
m_Min.x = (std::min)(m_Min.x, point.x);
m_Min.y = (std::min)(m_Min.y, point.y);
m_Min.z = (std::min)(m_Min.z, point.z);
m_Max.x = (std::max)(m_Max.x, point.x);
m_Max.y = (std::max)(m_Max.y, point.y);
m_Max.z = (std::max)(m_Max.z, point.z);
}
void BoundingBox::Reset() {
m_Min = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX);
m_Max = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
}
BoundingBox BoundingBox::Transform(const glm::mat4& matrix) const {
if (!IsValid()) return BoundingBox();
glm::vec3 corners[8];
GetCorners(corners);
BoundingBox result;
for (int i = 0; i < 8; ++i) {
glm::vec4 transformed = matrix * glm::vec4(corners[i], 1.0f);
result.Merge(glm::vec3(transformed.x, transformed.y, transformed.z));
}
return result;
}
bool BoundingBox::Intersects(const BoundingBox& other) const {
if (!IsValid() || !other.IsValid()) return false;
return (m_Min.x <= other.m_Max.x && m_Max.x >= other.m_Min.x) &&
(m_Min.y <= other.m_Max.y && m_Max.y >= other.m_Min.y) &&
(m_Min.z <= other.m_Max.z && m_Max.z >= other.m_Min.z);
}
bool BoundingBox::Contains(const glm::vec3& point) const {
if (!IsValid()) return false;
return (point.x >= m_Min.x && point.x <= m_Max.x) &&
(point.y >= m_Min.y && point.y <= m_Max.y) &&
(point.z >= m_Min.z && point.z <= m_Max.z);
}
bool BoundingBox::IsOnFrustum(const glm::vec4 planes[6]) const {
if (!IsValid()) return false;
glm::vec3 corners[8];
GetCorners(corners);
for (int i = 0; i < 6; ++i) {
const glm::vec4& plane = planes[i];
bool allOutside = true;
for (int j = 0; j < 8; ++j) {
float distance = plane.x * corners[j].x + plane.y * corners[j].y +
plane.z * corners[j].z + plane.w;
if (distance >= 0) {
allOutside = false;
break;
}
}
if (allOutside) return false;
}
return true;
}
float BoundingBox::GetRadius() const {
if (!IsValid()) return 0.0f;
return glm::distance(GetCenter(), m_Max);
}
float BoundingBox::GetVolume() const {
if (!IsValid()) return 0.0f;
glm::vec3 size = GetSize();
return size.x * size.y * size.z;
}
void BoundingBox::GetCorners(glm::vec3 corners[8]) const {
corners[0] = glm::vec3(m_Min.x, m_Min.y, m_Min.z);
corners[1] = glm::vec3(m_Max.x, m_Min.y, m_Min.z);
corners[2] = glm::vec3(m_Min.x, m_Max.y, m_Min.z);
corners[3] = glm::vec3(m_Max.x, m_Max.y, m_Min.z);
corners[4] = glm::vec3(m_Min.x, m_Min.y, m_Max.z);
corners[5] = glm::vec3(m_Max.x, m_Min.y, m_Max.z);
corners[6] = glm::vec3(m_Min.x, m_Max.y, m_Max.z);
corners[7] = glm::vec3(m_Max.x, m_Max.y, m_Max.z);
}