【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.pswp.cn/pingmian/76510.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76510.shtml
英文地址,請注明出處:http://en.pswp.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;由插…