(轉)從零實現3D圖像引擎:(6)向量函數庫

1. 數學分析

1) 基本定義:

向量由多個分量組成,2D/3D向量表示一條有向線段。下面的ux,uy就是兩個分量。

向量u = <ux, uy>,如果從點P1(x1, y1)指向點P2(x2, y2),則:

U = p2 - p1 = (x2-x1, y2-y1) = <Ux, Uy>

向量被定義后,總是相對于原點的,所以可以用一個點來表示從原點指向該點的向量。

2) 向量的范數(norm)

范數就是向量長度,是從原點到終點的距離。用|u|表示,所以:

|U| = sqrt(Ux2 + Uy2)

|U| = sqrt(Ux2 + Uy2 + Uz2)

3) 單位向量與歸一化

有時候,我們只關心向量的方向而不關心其長度,所以可以對向量做歸一化,使其方向不變,而長度縮放為1,以方便計算。用n'表示。

歸一化公式:

n' = n / |n|

4) 標量與向量乘法

對于標量k,標量與向量相乘的公式為:
k * u = k * <ux, uy> = <k * ux, k * uy>

標量與向量乘法的幾何意義:縮放一個向量。也可以乘以-1來反轉向量。

5) 向量之間相加,將各分量相加即可。

u + v = <ux, uy> + <vx, vy> = <ux + vx, uy + vy>

向量相加的幾何意義:平移v的起點至u的終點,則結果為u的起點到平移后的v的終點的線段。如下圖:

2011042516034486.png

6) 向量相減,分量相減

u - v = <ux, uy> - <vx, vy> = <ux - vx, uy - vy>

幾何意義:減數向量的終點指向被減數向量的終點的線段,如下圖:

2011042516070240.png

7) 點積

由于兩個向量的分量直接相乘沒有什么實際的幾何意義,所以一般沒用。而點積就十分有用。定義如下:

u.v = ux*vx + uy*vy

點積運算是將兩個向量的分量分別相乘,然后再相加,所得的結果是一個標量。

點積的幾何意義體現在這個點積公式上:

u.v = |u| * |v| * cos(theta)

即:點積等于兩個向量的長度積,再乘以它們之間的夾角的余弦。于是便可以推得夾角的計算方法:

theta = arccos(u.v / (|u| * |v|))

這個公式是很多3D圖形學算法的基礎,并且如果u和v都是單位向量的話,則|u| = |v| = 1,那么:

theta = arccos(u.v)

下面有4個點積非常重要的定理:

1. 如果u與v垂直,則u.v = 0

2. 如果夾角為銳角,則u.v > 0

3. 如果夾角為鈍角,則u.v < 0

4. 如果u與v相等,則u.v = |u| = |v|

那么根據點積的這些性質,我們可以發現由點積帶來的一大用途——計算向量在給定方向上的投影向量。

先看下圖:

2011042516072987.png

其實思路很簡單,既然是求u在v分量上的投影向量,那么方向已經可以知道了,所以所求投影向量的單位向量就等于v的單位向量,所以已經可以求得了該投影向量的單位向量:p(單位) = v / |v|

現在就差長度了,通過上圖,可以知道|p| = |u| * cos(theta),綜合一下,就可以求得:

p = (v / |v|) * (|u| * cos(theta))

還記得點積公式嗎? u.v = |u| * |v| * cos(theta)

所以可以簡化上面咱們的推導,得:

p = (u.v * v) / (|v| * |v|)

另外,點積滿足以下乘法定律,很好證明,這里省略:

u.v = v.u

u.(v+w) = (u.v + u.w)

k*(u.v) = (k*u).v = u.(k*v)

8) 叉積

首先給出叉積的定義:

u × v = |u| * |v| * sin(theta) * n

其中n是垂直于u和v的單位法向量。

如何求n呢?我們需要建立一個矩陣:

|? i??? j??? k? |

| ux uy uz |

| vx vy vz? |

其中i,j,k分別是與X、Y、Z軸平行的單位向量。

n是三個標量乘以X、Y、Z軸單位向量的線性組合:

n = (uy*vz - vy*uz)*i - (ux*vz - vx*uz)*j + (ux*vy - vx*uy)*k

所以n = <uy*vz - vy*uz, -ux*vz + vx*uz, ux*vy - vx*uy>

這樣求得的n不一定是單位向量,所以需要進行歸一化再使用。

其實后面求n不叉積的定義更重要,因為如果要求角度,點積就可以直接計算出來了,所以一般用叉積都是來求法線向量的。

叉積的乘法定律:

u×v = -(v×u)

u×(v+w) = u×v + u×w

(u+v)×w = u×w + v×w

k*(u×v) = (k*u)×v = u×(k*v)

9) 位移向量

先看圖:

2011042516075377.png

p1是從原點到點P1的向量,Vd是從點P1到點P2的向量,v'是Vd的單位向量,p是從原點到P2的向量。

還記得向量加法么,我們引入一個參數t來表示所相加的比例,則:

p = p1 + t*v' 其中t的取值范圍是[0, |vd|]

或者

p = p1 + t*vd 其中t的取值范圍是[0, 1]

這個概念非常重要,因為在游戲中跟蹤直線、線段、曲線時,非常有用。

2. 代碼實現

void _CPPYIN_Math::VectorAdd(VECTOR2D_PTR va, VECTOR2D_PTR vb, VECTOR2D_PTR vsum)
{vsum->x = va->x + vb->x;vsum->y = va->y + vb->y;
}void _CPPYIN_Math::VectorAdd(VECTOR3D_PTR va, VECTOR3D_PTR vb, VECTOR3D_PTR vsum)
{vsum->x = va->x + vb->x;vsum->y = va->y + vb->y;vsum->z = va->z + vb->z;
}void _CPPYIN_Math::VectorAdd(VECTOR4D_PTR va, VECTOR4D_PTR vb, VECTOR4D_PTR vsum)
{vsum->x = va->x + vb->x;vsum->y = va->y + vb->y;vsum->z = va->z + vb->z;vsum->w = 1;
}void _CPPYIN_Math::VectorSub(VECTOR2D_PTR va, VECTOR2D_PTR vb, VECTOR2D_PTR vsum)
{vsum->x = va->x - vb->x;vsum->y = va->y - vb->y;
}void _CPPYIN_Math::VectorSub(VECTOR3D_PTR va, VECTOR3D_PTR vb, VECTOR3D_PTR vsum)
{vsum->x = va->x - vb->x;vsum->y = va->y - vb->y;vsum->z = va->z - vb->z;
}void _CPPYIN_Math::VectorSub(VECTOR4D_PTR va, VECTOR4D_PTR vb, VECTOR4D_PTR vsum)
{vsum->x = va->x - vb->x;vsum->y = va->y - vb->y;vsum->z = va->z - vb->z;vsum->w = 1;
}void _CPPYIN_Math::VectorScale(double k, VECTOR2D_PTR va, VECTOR2D_PTR vscaled)
{vscaled->x = k * va->x;vscaled->y = k * va->y;
}void _CPPYIN_Math::VectorScale(double k, VECTOR3D_PTR va, VECTOR3D_PTR vscaled)
{vscaled->x = k * va->x;vscaled->y = k * va->y;vscaled->z = k * va->z;
}void _CPPYIN_Math::VectorScale(double k, VECTOR4D_PTR va, VECTOR4D_PTR vscaled)
{vscaled->x = k * va->x;vscaled->y = k * va->y;vscaled->z = k * va->z;vscaled->w = 1;
}double _CPPYIN_Math::VectorDot(VECTOR2D_PTR va, VECTOR2D_PTR vb)
{return (va->x * vb->x) + (va->y * vb->y);
}double _CPPYIN_Math::VectorDot(VECTOR3D_PTR va, VECTOR3D_PTR vb)
{return (va->x * vb->x) + (va->y * vb->y) + (va->z * va->z);
}double _CPPYIN_Math::VectorDot(VECTOR4D_PTR va, VECTOR4D_PTR vb)
{return (va->x * vb->x) + (va->y * vb->y) + (va->z * va->z);
}void _CPPYIN_Math::VectorCross(VECTOR3D_PTR va, VECTOR3D_PTR vb, VECTOR3D_PTR vn)
{vn->x =  ((va->y * vb->z) - (va->z * vb->y));vn->y = -((va->x * vb->z) - (va->z * vb->x));vn->z =  ((va->x * vb->y) - (va->y * vb->x)); 
}void _CPPYIN_Math::VectorCross(VECTOR4D_PTR va, VECTOR4D_PTR vb, VECTOR4D_PTR vn)
{vn->x =  ((va->y * vb->z) - (va->z * vb->y));vn->y = -((va->x * vb->z) - (va->z * vb->x));vn->z =  ((va->x * vb->y) - (va->y * vb->x)); vn->w = 1;
}double _CPPYIN_Math::VectorLength(VECTOR2D_PTR va)
{return sqrt(va->x * va->x + va->y * va->y);
}double _CPPYIN_Math::VectorLength(VECTOR3D_PTR va)
{return sqrt(va->x * va->x + va->y * va->y + va->z * va->z);
}double _CPPYIN_Math::VectorLength(VECTOR4D_PTR va)
{return sqrt(va->x * va->x + va->y * va->y + va->z * va->z);
}void _CPPYIN_Math::VectorNormalize(VECTOR2D_PTR va, VECTOR2D_PTR vn)
{vn->x = 0;vn->y = 0;double length = VectorLength(va);if (length < EPSILON){return;}else{double lengthdao = 1 / length;vn->x = va->x * lengthdao;vn->y = va->y * lengthdao;}
}void _CPPYIN_Math::VectorNormalize(VECTOR3D_PTR va, VECTOR3D_PTR vn)
{vn->x = 0;vn->y = 0;vn->z = 0;double length = VectorLength(va);if (length < EPSILON){return;}else{double lengthdao = 1 / length;vn->x = va->x * lengthdao;vn->y = va->y * lengthdao;vn->z = va->z * lengthdao;}
}void _CPPYIN_Math::VectorNormalize(VECTOR4D_PTR va, VECTOR4D_PTR vn)
{vn->x = 0;vn->y = 0;vn->z = 0;vn->w = 0;double length = VectorLength(va);if (length < EPSILON){return;}else{double lengthdao = 1 / length;vn->x = va->x * lengthdao;vn->y = va->y * lengthdao;vn->z = va->z * lengthdao;vn->w = 1;}
}double _CPPYIN_Math::VectorCos(VECTOR2D_PTR va, VECTOR2D_PTR vb)
{return VectorDot(va, vb) / (VectorLength(va) * VectorLength(vb));
}double _CPPYIN_Math::VectorCos(VECTOR3D_PTR va, VECTOR3D_PTR vb)
{return VectorDot(va, vb) / (VectorLength(va) * VectorLength(vb));
}double _CPPYIN_Math::VectorCos(VECTOR4D_PTR va, VECTOR4D_PTR vb)
{return VectorDot(va, vb) / (VectorLength(va) * VectorLength(vb));
}

不用多說了,都是按照上面數學推導出來的公式直接實現。

3. 代碼下載

完整項目源代碼下載:>>點擊進入下載頁<<

之前的一直忘了改資源分默認是1,從這次開始我都改成0了。

4. 補充內容

1) 對于求向量范數的問題,其實這個實現方式效率不高,現在使用的勾股開方的形式實現,而其實可以使用泰勒級數來計算近似值,雖然有一點點誤差,但是運算速度大大提高。

2) 你可以發現我在做向量歸一化的時候,是先求了lengthdao = 1 / length,然后再去和三個分量做乘法,而不是讓他們分別去除以length。其實也是效率原因,計算機做除法的速度遠遠慢于做乘法,所以我們只做一次除法,而做三次乘法,這樣簡單的優化帶來的效果卻是非常明顯的。

轉自:http://blog.csdn.net/cppyin/archive/2011/02/07/6174087.aspx

轉載于:https://www.cnblogs.com/CoolJie/archive/2011/03/03/1970223.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275642.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275642.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275642.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

chrome黑暗模式_黑暗模式-并非時尚

chrome黑暗模式In this post I’ve shared my research and views on how the extremely popular “Dark Mode” has moved beyond it’s initial label of “The App Design Fad of 2019”.在這篇文章中&#xff0c;我分享了我的研究和看法&#xff0c;探討了非常受歡迎的“黑…

A.華華聽月月唱歌

鏈接&#xff1a;https://ac.nowcoder.com/acm/contest/392/A 題意&#xff1a; 月月唱歌超級好聽的說&#xff01;華華聽說月月在某個網站發布了自己唱的歌曲&#xff0c;于是把完整的歌曲下載到了U盤里。然而華華不小心把U盤摔了一下&#xff0c;里面的文件摔碎了。月月的歌曲…

花了一天精選了20多篇好文,只為與你分享

大家好&#xff0c;我是若川。很多小伙伴因工作繁忙而沒有很多自己的時間去學習新知識&#xff0c;更多的是通過一些碎片化的時間來閱讀一些他人的技術文章來提升自己的技術視野以及擴展自己的知識儲備。這次我精心整理了一批大佬們的優秀文章&#xff0c;感興趣的可以閱讀關注…

matlab判斷電話播鍵音,MATLAB電話撥號音的合成與識別

1.實驗目的1.本實驗內容基于對電話通信系統中撥號音合成與識別的仿真實現。主要涉及到電話撥號音合成的基本原理及識別的主要方法&#xff0c;利用 MATLAB 軟件以及 FFT 算法實現對電話通信系統中撥號音的合成與識別。并進一步利用 MATLAB 中的圖形用戶界面 GUI 制作簡單直觀的…

jquery插件之無縫循環新聞列表

一、效果圖&#xff1a; tips源碼下載&#xff1a;http://files.cnblogs.com/waitingbar/newslist.rar 二、jquery源碼: (function($){$.fn.extend({newsList:function(options){var defaults {actName:li, //顯示條數名&#xff1b;maxShowNum:6, //最多的顯示…

素描的幾大基礎知識點_2020年讓您感到驚奇的5大素描資源

素描的幾大基礎知識點Sketch is my favorite stand-alone software that I use every day. It is simple, stable, and fast. During my working process, I use other resources that allow me to create UX/UI design faster. These tools have a different direction, but s…

ESMap+Html5+SpringBoot+FastDFS實現導航導購App

github鏈接 項目實現的簡要概述 服務器部分 測試階段使用的是雙系統的開發模式&#xff0c;在Linux服務器上部署了輕量級分布式文件系統fastdfs&#xff0c;且整合了高性能的HTTP和反向代理服務器nginx&#xff1b;在本地的服務器上使用Spring Boot框架&#xff0c;使用其內置的…

你不知道的 Chrome DevTools 玩法

大家好&#xff0c;我是若川。今天再分享一篇 chrome devtools 的文章。之前分享過多篇。Chrome DevTools 全攻略&#xff01;助力高效開發 前端容易忽略的 debugger 調試技巧?筆者在前段時間的開發時&#xff0c;需要通過 Chrome DevTools來分析一個接口&#xff0c;調試中發…

matlab擬合四次函數表達式,用matlab編寫程序求以冪函數作基函數的3次、4次多項式的最小二乘曲線擬合,畫出數據散點圖及擬合曲線圖...

共回答了18個問題采納率&#xff1a;83.3%x[0.0 0.1 0.2 0.3 0.5 0.8 1.0]; %輸入數組>> y[1.0 0.41 0.50 0.61 0.91 2.02 2.46];>> f1inline(poly2sym(polyfit(x,y,3))); %polyfit擬合得到系數,poly2sym由系數得到多項式,inline轉換內聯函數>> f2inline(pol…

排版人員 快速排版_選擇排版前應了解的事項

排版人員 快速排版Design is everywhere, and with design comes text and the content that you’re trying to reach the user with. But before creating your design and choosing what font you want to use, there are some things you should know that will help you a…

matlab光順拐點,基于MATLAB的最大誤差雙圓弧逼近曲線的算法及實現.pdf

基于MATLAB的最大誤差雙圓弧逼近曲線的算法及實現.pdf第31卷第6期 基于MⅢB的最大誤差雙圓弧逼近曲線的算法及實現文章編號&#xff1a;1004—2539120町】06一唧一∞基于MAⅡ&#xff0e;AB的最大誤差雙圓弧逼近曲線的算法及實現淮海工學院機械工程系&#xff0c;扛蘇連云港笠a…

若川誠邀你加源碼共讀群,幫助更多人學會看源碼~

小提醒&#xff1a;若川視野公眾號面試、源碼等文章合集在菜單欄中間【源碼精選】按鈕&#xff0c;歡迎點擊閱讀&#xff0c;也可以星標我的公眾號&#xff0c;便于查找。回復pdf&#xff0c;可以獲取前端優質書籍。最近我創建了一個源碼共讀的前端交流群&#xff0c;希望嘗試幫…

體育木地板的施工

文章來源&#xff1a;http://www.bjfhrd.com 體育木地板上有許多暗門&#xff0c;以制造特殊效果&#xff0c;如火焰、煙霧&#xff0c;使房屋、樹木、山或人物在一瞬間出現或銷售。這種特殊的要求&#xff0c;對于專業體育木地板德施工就有了一定的要求。 專業體育木地板施工&…

imessage_重新設計iMessage以獲得更好的用戶體驗— UX案例研究

imessage體驗設計 (EXPERIENCE DESIGN) Communication is a vital part of our everyday lives. We almost don’t even have to think about it. With social media and our devices as prime tools, we’re constantly finding new ways to stay connected. Instant messagin…

mysql 生成時間軸,MYSQL 時間軸數據 獲取同一天數據的前3條

創建表數據CREATE TABLE praise_info (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ID,pic_id varchar(64) DEFAULT NULL COMMENT 圖片ID,created_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 創建時間,PRIMARY KEY (id),KEY pic_id (pic_id) USING BTREE) ENGINEInn…

【招聘】永輝招前端

大家好&#xff0c;我是若川。這應該招聘第六期。友情幫好友宣傳招聘。之前在跟各位讀者朋友分享下公眾號運營策略 文中提到 公眾號主旨是幫助5年內前端小伙伴提升&#xff0c;找到好工作&#xff0c;所以有招聘文。上海 高級前端 本科 25k-50k 16薪崗位職責&#xff1a;1、…

C語身教程第三章: C說話挨次籌算匹面(1)

&#xff23;說話挨次籌算本課先容&#xff23;說話挨次籌算的根基要領和根基的挨次語句。從挨次流程的角度來看&#xff0c;挨次可以分為三種根基構造&#xff0c; 即挨次構造、分支構造、循環構造。 這三種根基構造可以組玉成部的種種重年夜挨次。&#xff23;說話供給了多種…

插圖 引用 同一行兩個插圖_插圖的目的

插圖 引用 同一行兩個插圖If you’re a designer in tech you’ve likely come across them. Any search for UI or product design on Dribbble will yield at least a few. Amid the sea of pastel blues and pinks, accented neon purples and gamboge yellows, these facel…

php 轉碼iconv,PHP iconv()函數轉字符編碼的問題(轉)

在php函數庫有一個函數&#xff1a;iconv()&#xff0c;iconv函數庫能夠完成各種字符集間的轉換&#xff0c;是php編程中不可缺少的基礎函數庫。最近在做一個小偷程序&#xff0c;需要用到iconv函數把抓取來過的utf-8編碼的頁面轉成gb2312&#xff0c;發現只有用iconv函數把抓取…

VSCode 竟然可以無縫調試瀏覽器了!

大家好&#xff0c;我是若川。今天周末&#xff0c;分享一篇相對比較簡單的文章。學習源碼系列、面試、年度總結、JS基礎系列。2021-07-16 微軟發布了一篇博客專門介紹了這個功能&#xff0c;VSCode 牛逼&#xff01;在此之前&#xff0c;你想要在 vscode 內調試 chrome 或者 e…