【C++游戏引擎开发】第9篇:数学计算库GLM(线性代数)、CGAL(几何计算)的安装与使用指南

写在前面

两天都没手搓实现可用的凸包生成算法相关的代码,自觉无法手搓相关数学库,遂改为使用成熟数学库。


一、GLM库安装与介绍

1.1 vcpkg安装GLM

跨平台C++包管理利器vcpkg完全指南

在PowerShell中执行命令:

vcpkg install glm# 集成到系统目录,只需要执行一次,以前执行过就无需重复执行
vcpkg integrate install

1.2 GLM库基础数学对象

类型描述示例
vec2/3/42/3/4维浮点向量vec3 position(1,2,3);
mat2/3/42x2、3x3、4x4浮点矩阵mat4 view = lookAt(…);
quat四元数(旋转表示)quat rotation = angleAxis(…);
dvec*/dmat*双精度向量/矩阵dmat4 highPrecisionMat;

1.3 GLM库使用示例代码(矩阵计算、四元数计算等)

// main.cpp
// main.cpp
#include <iostream>
#include <limits>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>  // 用于矩阵字符串输出
#include <glm/gtx/quaternion.hpp>// 打印GLM矩阵(带标签)
template<typename T>
void print_matrix(const std::string& name, const T& mat) {std::cout << name << ":\n" << glm::to_string(mat) << "\n\n";
}// 定义OBB结构体
struct OBB {glm::vec3 center;     // 包围盒中心glm::vec3 extents;    // 包围盒半长(x, y, z方向的半径)glm::mat3 rotation;   // 旋转矩阵(局部到世界坐标的变换)
};// 射线与OBB相交检测(返回相交距离,未相交返回-1)
float rayOBBIntersection(const glm::vec3& rayOrigin,const glm::vec3& rayDir,const OBB& obb,float maxDistance = std::numeric_limits<float>::max()
) {// 将射线转换到OBB局部空间glm::mat3 invRotation = glm::transpose(obb.rotation); // 旋转的逆矩阵glm::vec3 localOrigin = invRotation * (rayOrigin - obb.center);glm::vec3 localDir = invRotation * rayDir;// 射线与AABB相交检测(在局部空间)float tMin = 0.0f;float tMax = maxDistance;// 分别检查每个轴for (int i = 0; i < 3; ++i) {float axisMin = -obb.extents[i] - localOrigin[i];float axisMax = obb.extents[i] - localOrigin[i];if (std::abs(localDir[i]) < 1e-6) { // 射线与轴平行if (localOrigin[i] < -obb.extents[i] || localOrigin[i] > obb.extents[i])return -1.0f;}else {float invDir = 1.0f / localDir[i];float t1 = axisMin * invDir;float t2 = axisMax * invDir;if (t1 > t2) std::swap(t1, t2);tMin = std::max(tMin, t1);tMax = std::min(tMax, t2);if (tMin > tMax) return -1.0f;}}return tMin;
}// 在main函数中添加测试代码
void testRayOBB() {std::cout << "===== OBB射线检测测试 =====" << std::endl;// 创建一个旋转45度的OBBOBB obb;obb.center = glm::vec3(2.0f, 0.0f, 0.0f);obb.extents = glm::vec3(1.0f, 0.5f, 0.5f);obb.rotation = glm::mat3_cast(glm::angleAxis(glm::radians(45.0f), glm::vec3(0, 0, 1)));// 测试射线1:应相交glm::vec3 rayOrigin1(0.0f, 0.0f, 0.0f);glm::vec3 rayDir1 = glm::normalize(glm::vec3(1.0f, 0.0f, 0.0f));float t1 = rayOBBIntersection(rayOrigin1, rayDir1, obb);std::cout << "射线1结果: " << (t1 >= 0 ? "命中,距离=" + std::to_string(t1) : "未命中") << std::endl;// 测试射线2:应不相交glm::vec3 rayOrigin2(0.0f, 2.0f, 0.0f);glm::vec3 rayDir2 = glm::normalize(glm::vec3(1.0f, 0.0f, 0.0f));float t2 = rayOBBIntersection(rayOrigin2, rayDir2, obb);std::cout << "射线2结果: " << (t2 >= 0 ? "命中,距离=" + std::to_string(t2) : "未命中") << std::endl;// 测试射线3:从内部发射glm::vec3 rayOrigin3 = obb.center;glm::vec3 rayDir3 = glm::normalize(glm::vec3(1.0f, 0.0f, 0.0f));float t3 = rayOBBIntersection(rayOrigin3, rayDir3, obb);std::cout << "射线3结果: " << (t3 >= 0 ? "命中,距离=" + std::to_string(t3) : "未命中") << std::endl;std::cout << "\n";
}int main() {// ======================// 1. 矩阵基本操作// ======================// 创建两个4x4矩阵glm::mat4 A(1.0f);  // 单位矩阵glm::mat4 B = glm::translate(glm::mat4(1.0f), glm::vec3(2, 3, 4));  // 平移矩阵// 矩阵加法glm::mat4 C = A + B;print_matrix("Matrix A (Identity)", A);print_matrix("Matrix B (Translation)", B);print_matrix("Matrix C = A + B", C);// 矩阵减法glm::mat4 D = B - A;print_matrix("Matrix D = B - A", D);// 矩阵乘法(组合变换)glm::mat4 trans = glm::translate(glm::mat4(1.0f), glm::vec3(1, 0, 0));glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(2, 2, 2));glm::mat4 combined = trans * scale;  // 先缩放后平移print_matrix("Combined Matrix (Scale then Translate)", combined);// ======================// 2. 矩阵求逆// ======================glm::mat4 invB = glm::inverse(B);print_matrix("Inverse of Matrix B", invB);// 验证B * invB ≈ Identityglm::mat4 identityCheck = B * invB;print_matrix("B * invB (Should be Identity)", identityCheck);// ======================// 3. 四元数操作// ======================// 创建绕Y轴旋转45度的四元数glm::quat q1 = glm::angleAxis(glm::radians(45.0f), glm::vec3(0, 1, 0));// 创建绕X轴旋转30度的四元数glm::quat q2 = glm::angleAxis(glm::radians(30.0f), glm::vec3(1, 0, 0));// 四元数插值(球面线性插值)glm::quat slerped = glm::slerp(q1, q2, 0.5f);// 将四元数转换为旋转矩阵glm::mat4 rotMat = glm::mat4_cast(slerped);print_matrix("Rotation Matrix from Slerped Quaternion", rotMat);// 使用四元数旋转向量glm::vec3 originalVec(1, 0, 0);glm::vec3 rotatedVec = slerped * originalVec;std::cout << "Original Vector: (" << originalVec.x << ", " << originalVec.y << ", " << originalVec.z << ")\n";std::cout << "Rotated Vector: (" << rotatedVec.x << ", " << rotatedVec.y << ", " << rotatedVec.z << ")\n\n";testRayOBB();return 0;
}

二、CGAL库安装与使用

2.1 vcpkg安装CGAL库

在PowerShell中执行命令:

vcpkg install cgal

注:安装过程较长,很慢。

2.2 CGAL示例代码(凸包生成、三角剖分)

#include <iostream>
#include <vector>
#include <iterator>  // 添加iterator头文件
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_2.h>
#include <CGAL/convex_hull_3.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/point_generators_2.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Polyhedron_3.h>  // 添加Polyhedron_3头文件using namespace std;// 定义内核类型(快速浮点数计算)
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
typedef K::Point_3 Point_3;
typedef CGAL::Polyhedron_3<K> Polyhedron_3;  // 定义多面体类型//------- 二维凸包测试 -------
void test_2d_convex_hull() {cout << "===== 二维凸包测试 =====" << endl;// 生成100个随机二维点(坐标范围[0, 100))CGAL::Random_points_in_square_2<Point_2> gen(50.0);vector<Point_2> points;const int NUM_POINTS = 20;CGAL::cpp11::copy_n(gen, NUM_POINTS, back_inserter(points));// 计算凸包vector<Point_2> hull;CGAL::convex_hull_2(points.begin(), points.end(), back_inserter(hull));// 输出结果cout << "原始点集(" << points.size() << "):" << endl;for (const auto& p : points)cout << "(" << p.x() << ", " << p.y() << ") ";cout << "\n\n凸包顶点(" << hull.size() << "):" << endl;for (const auto& p : hull)cout << "(" << p.x() << ", " << p.y() << ") ";cout << "\n\n";
}//------- 三维凸包测试 -------
void test_3d_convex_hull() {cout << "===== 三维凸包测试 =====" << endl;// 生成20个随机三维点CGAL::Random_points_in_sphere_3<Point_3> gen(50.0);vector<Point_3> points;const int NUM_POINTS = 20;copy_n(gen, NUM_POINTS, back_inserter(points));  // 移除非必要的CGAL::cpp11::// 计算三维凸包Polyhedron_3 hull;CGAL::convex_hull_3(points.begin(), points.end(), hull);// 输出结果cout << "三维凸包面数: " << std::distance(hull.facets_begin(), hull.facets_end()) << endl;int faceCount = 0;for (auto face = hull.facets_begin(); face != hull.facets_end(); ++face, ++faceCount) {cout << "面 " << faceCount << ": ";auto he = face->halfedge();for (int i = 0; i < 3; ++i) {  // 假设所有面都是三角形const auto& p = he->vertex()->point();cout << "(" << p.x() << ", " << p.y() << ", " << p.z() << ") ";he = he->next();}cout << endl;}cout << "\n";
}
//------- 二维Delaunay三角剖分测试 -------
void test_2d_delaunay() {cout << "===== 二维Delaunay三角剖分测试 =====" << endl;// 生成100个随机二维点CGAL::Random_points_in_square_2<Point_2> gen(50.0);vector<Point_2> points;const int NUM_POINTS = 10;copy_n(gen, NUM_POINTS, back_inserter(points));  // 移除非必要的CGAL::cpp11::// 构建Delaunay三角网CGAL::Delaunay_triangulation_2<K> dt;dt.insert(points.begin(), points.end());// 输出统计信息cout << "顶点数: " << dt.number_of_vertices() << endl;cout << "面数: " << dt.number_of_faces() << endl;// 遍历所有边(正确方式)cout << "\n边列表:" << endl;for (auto edge = dt.finite_edges_begin(); edge != dt.finite_edges_end(); ++edge) {auto segment = dt.segment(*edge);  // 直接获取边对应的线段cout << "(" << segment.source().x() << ", " << segment.source().y() << ") - "<< "(" << segment.target().x() << ", " << segment.target().y() << ")\n";}cout << "\n";
}//------- 三维Delaunay三角剖分测试 -------
void test_3d_delaunay() {cout << "===== 三维Delaunay三角剖分测试 =====" << endl;// 生成10个随机三维点CGAL::Random_points_in_sphere_3<Point_3> gen(50.0);vector<Point_3> points;const int NUM_POINTS = 10;CGAL::cpp11::copy_n(gen, NUM_POINTS, back_inserter(points));// 构建三维Delaunay三角网CGAL::Delaunay_triangulation_3<K> dt;dt.insert(points.begin(), points.end());// 输出统计信息cout << "顶点数: " << dt.number_of_vertices() << endl;cout << "边数: " << dt.number_of_edges() << endl;cout << "面数: " << dt.number_of_facets() << endl;cout << "四面体数: " << dt.number_of_cells() << endl;// 遍历所有四面体cout << "\n四面体列表:" << endl;for (auto cell = dt.finite_cells_begin(); cell != dt.finite_cells_end(); ++cell) {const Point_3& p0 = cell->vertex(0)->point();const Point_3& p1 = cell->vertex(1)->point();const Point_3& p2 = cell->vertex(2)->point();const Point_3& p3 = cell->vertex(3)->point();cout << "四面体: \n";cout << " (" << p0.x() << ", " << p0.y() << ", " << p0.z() << ")\n"<< " (" << p1.x() << ", " << p1.y() << ", " << p1.z() << ")\n"<< " (" << p2.x() << ", " << p2.y() << ", " << p2.z() << ")\n"<< " (" << p3.x() << ", " << p3.y() << ", " << p3.z() << ")\n";}cout << "\n";
}int main() {// 运行各测试用例test_2d_convex_hull();test_3d_convex_hull();test_2d_delaunay();test_3d_delaunay();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76510.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python文件打包无法导入ultralytics模块

&#x1f4a5;打包的 .exe 闪退了&#xff1f;别慌&#xff01;教你逐步排查 PyInstaller 打包的所有错误&#xff01; &#x1f6e0; 运行 .exe 查看报错信息✅ 正确姿势&#xff1a; ⚠ importlib 动态导入导致打包失败❓什么是动态导入&#xff1f;✅ 解决方式&#xff1a; …

【React框架】什么是 Vite?如何使用vite自动生成react的目录?

什么是 Vite&#xff1f; Vite 是一个基于原生 ES Modules 开发的前端构建工具&#xff0c;由 Evan You&#xff08;Vue 的作者&#xff09;开发。它最大的特点包括&#xff1a; 极速冷启动&#xff1a;因为利用了浏览器原生的 ES Modules&#xff0c;所以在开发时无需等待整…

深入解读 React 纯组件(PureComponent)

什么是纯组件&#xff1f; React 的纯组件(PureComponent)是 React.Component 的一个变体&#xff0c;它通过浅比较(shallow comparison)props 和 state 来自动实现 shouldComponentUpdate() 方法&#xff0c;从而优化性能。 核心特点 1. 自动浅比较&#xff1a; PureCompon…

JavaScript数组方法:`some()`的全面解析与应用

文章目录 JavaScript数组方法&#xff1a;some()的全面解析与应用一、some()方法的基本概念语法参数说明返回值 二、some()方法的核心特点三、基础用法示例示例1&#xff1a;检查数组中是否有大于10的元素示例2&#xff1a;检查字符串数组中是否包含特定子串 四、实际应用场景1…

判断两个 IP 地址是否在同一子网 C

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> // 将点分十进制的 IP 地址转换为 32 位无符号整数 unsigned int ip_to_uint(const char *ip) { struct in_addr addr; if (inet_pton(AF_INET, ip, &am…

React 组件样式

在这里插入图片描述 分为行内和css文件控制 行内 通过CSS中类名文件控制

尚硅谷Java第 4、5 章IDEA,数组

第 4 章&#xff1a;IDEA的使用 第 5 章&#xff1a;数组 5.1 数组的概述 数组(Array)&#xff1a;就可以理解为多个数据的组合。 程序中的容器&#xff1a;数组、集合框架&#xff08;List、Set、Map&#xff09;。 数组中的概念&#xff1a; 数组名 下标&#xff08;或索…

SQL注入基本原理靶场实现

↵ 一、前言 SQL注入漏洞(SQL injection)是WEB层面高危的漏洞之一&#xff0c;也是常见的攻击方式。 二、本质 1、什么是SQL注入 SQL 注入是一种利用应用程序对用户输入数据过滤不严格&#xff0c;将恶意 SQL 代码插入到正常 SQL 语句中&#xff0c;从而操控数据库查询逻辑的…

图像预处理(OpenCV)

1 图像翻转(图像镜像旋转) 在OpenCV中&#xff0c;图片的镜像旋转是以图像的中心为原点进行镜像翻转的。 cv2.flip(img,flipcode) 参数 img: 要翻转的图像 flipcode: 指定翻转类型的标志 flipcode0: 垂直翻转&#xff0c;图片像素点沿x轴翻转 flipcode>0: 水平翻转&…

PCDN收益高低的关键因素

PCDN&#xff08;P2P内容分发网络&#xff09;收益好的三个主要关键因素是&#xff1a;硬件配置与性能、网络环境与质量、业务调度与策略。 1. 硬件配置与性能 设备稳定性与兼容性 PCDN节点需长时间稳定运行&#xff0c;硬件性能直接影响收益。例如&#xff0c;使用高性能CPU、…

『生成内容溯源系统』详解

生成内容溯源系统详解 1. 定义与核心目标 生成内容溯源系统&#xff08;Generative Content Provenance System&#xff09;是指能够追踪AI生成内容的来源、生成过程、版权归属及修改历史的技术体系。其核心目标是&#xff1a; 验证真实性&#xff1a;证明内容由特定AI模型生…

conda如何安装和运行jupyter

在Conda环境中安装和运行Jupyter Notebook是一项常见且实用的任务&#xff0c;特别是在数据科学和机器学习项目中。以下是使用Conda安装和运行Jupyter Notebook的步骤&#xff1a; 安装Jupyter Notebook 首先&#xff0c;确保你的Conda是最新的。打开终端或Anaconda Prompt&a…

QML之Flickable(滚动区域)

Flickable 是 QML 中用于创建可滚动区域的基础组件&#xff0c;它比 ScrollView 提供更底层的控制&#xff0c;适合需要自定义滚动行为的场景。 基本用法 qml import QtQuick 2.15Flickable {width: 200height: 200contentWidth: 400 // 内容总宽度contentHeight: 800 // 内…

【NumPy科学计算引擎:从基础操作到高性能实践】

目录 前言&#xff1a;技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析关键技术模块说明技术选型对比 二、实战演示环境配置核心代码实现运行结果验证 三、性能对比测试方法论量化数据对比结果分析 四、最佳实践推荐方案 ✅常见错误 ❌调试技巧 五、应用…

PandaGPT实战(1): 环境配置及效果演示

文章目录 1. 环境安装2. 数据准备2.1 模型权重获取2.2 训练数据准备3. 效果演示3.1 训练3.2 部署效果PandaGPT是首个无需显式监督即能跨六种模态执行指令微调任务的基础模型。它展现出多样化的多模态能力,包括复杂理解/推理、基于知识的描述以及多轮对话交互。 作为通用型指令…

spring security oauth2.0 使用GitHub

在 Spring Security 中集成 GitHub 的 OAuth 2.0 登录&#xff0c;可以实现用户通过 GitHub 账号快速认证。以下是完整的分步实现指南和代码示例&#xff1a; 一、前置准备 1. 在 GitHub 注册 OAuth 应用 访问 GitHub Settings → Developer settings → OAuth Apps点击 New …

QT聊天项目DAY01

1.新建初始项目 2.修改UI格式 运行效果 3.创建登录界面 设计登录界面UI 设计布局 调整布局间距 往水平布局中拖入标签和文本输入框 更换控件名称并固定高度 添加窗口部件 往现有的资源文件中导入图片 添加水平布局 4.设置登陆界面为主窗口的核心组件 #pragma once#include &l…

检测到目标URL存在http host头攻击漏洞

漏洞描述 修复措施 方法一&#xff1a; nginx 的 default_server 指令可以定义默认的 server 去处理一些没有匹配到 server_name 的请求&#xff0c;如果没有显式定义&#xff0c;则会选取第一个定义的 server 作为 default_server。 server { …

小甲鱼第004讲:变量和字符串(下)| 课后测试题及答案

问答题: 0. 请问下面代码有没有毛病&#xff0c;为什么? 请问下面代码为什么会出错&#xff0c;应该如何解决&#xff1f; 答:这是由于在字符串中&#xff0c;反斜杠()会与其随后的字符共同构成转义字符。 为了避免这种不测情况的发生&#xff0c;我们可以在字符串的引号前面…

Hyprnote开源程序是一款记录和转录您会议的 AI 记事本。 本地优先且可扩展 。

一、软件介绍 文末提供源码下载学习 Hyprnote开源程序是一款记录和转录您会议的 AI 记事本。 从您的原始会议记录中生成强大的摘要&#xff0c;本地优先且可扩展 。使用开源模型 &#xff08;Whisper & Llama&#xff09; 离线工作&#xff0c;高度可扩展 &#xff0c;由插…