網(wǎng)上有很多關(guān)于pos機如何選擇sn,向量數學(xué)在游戲中如何使用的知識,也有很多人為大家解答關(guān)于pos機如何選擇sn的問(wèn)題,今天pos機之家(m.xjcwpx.cn)為大家整理了關(guān)于這方面的知識,讓我們一起來(lái)看下吧!
本文目錄一覽:
pos機如何選擇sn
對于一個(gè)初學(xué)者來(lái)說(shuō),三維空間的幾何似乎有點(diǎn)讓人望而生畏。在紙上可以畫(huà)出來(lái)的二維空間幾何就已經(jīng)足夠難以理解了,但是現在我們竟然要使用和掌握三維空間的幾何?
好消息是在圖形學(xué)中直接使用三角形是非常罕見(jiàn)的并且有很多方法可以用來(lái)避免這么做。我們有其他更好理解和使用的工具來(lái)代替。你可能在下圖中已經(jīng)認出我們的老朋友-向量(vector)。
這篇文章將向你介紹三維空間的向量,并將用幾個(gè)實(shí)際使用方面的例子來(lái)帶你熟悉三維空間的向量。雖然這些例子的內容是側重三維空間的,但是里面說(shuō)明的大部分內容和原理也同樣適用于二維空間。
這篇文章會(huì )假設讀者具有代碼和幾何方面的知識,以及具有編程方面的經(jīng)驗和對面向對象編程(OOP)的基本了解。
游戲中的向量數學(xué)
概念
在數學(xué)中,一個(gè)向量是指一個(gè)既有方向(direction)又有大小(magnitue)的結構。在游戲開(kāi)發(fā)中它經(jīng)常用來(lái)描述位置的變化,并且可以與其他向量相加或者相減來(lái)得到新的位置變化(一個(gè)向量代表一個(gè)位置的變化,兩個(gè)這樣的向量相加得到的是這兩段位置變化的總效果)。通常情況下,你會(huì )發(fā)現向量是數學(xué)庫或者物理庫的一部分。
它們通常包含一個(gè)或多個(gè)組件,比如x、y和z。向量可以是一維向量(只包含x分量)、二維向量(包含x、y分量)、三維向量(包含x、y、z分量)甚至是四維向量(一般是x、y、z、w分量)。四維向量可以用來(lái)描述其他一些東西,比如一個(gè)帶額外alpha值的顏色。
對于初學(xué)者來(lái)說(shuō)最困難的事情之一就是他們在剛接觸向量的時(shí)候如何去理解看上去就是空間的一個(gè)點(diǎn)的東西為什么可以用來(lái)描述一個(gè)方向。
讓我們用二維向量(3,3)來(lái)舉例說(shuō)明這個(gè)事情。要理解為什么向量能夠代表一個(gè)方向你只需要看下面這張圖。我們都知道需要兩個(gè)點(diǎn)才能形成一條線(xiàn)。所以第二個(gè)點(diǎn)在哪里呢?缺失的那個(gè)點(diǎn)就是位于(0,0)的原點(diǎn)(origin)。我們畫(huà)一條從原點(diǎn)(0,0)到(3,3)的線(xiàn)段,我們就得到下圖這么一個(gè)效果:
正如你在上圖中看到的那樣,原點(diǎn)作為第二個(gè)點(diǎn)引入以后就與第一個(gè)點(diǎn)一起賦予了我們的向量一個(gè)方向。但是你也會(huì )看到,第一個(gè)點(diǎn)(3,3)可以被移動(dòng)(或者說(shuō)位移)來(lái)接近或者遠離原點(diǎn)。
第一個(gè)點(diǎn)到原點(diǎn)的距離就被稱(chēng)為大小,可以用二次方程a^2 + b^2 = c^2計算得到。在我們舉得例子中,就是3^2 + 3^2 =c^2, c = sqrt(18) ~= 4.24。如果我們把向量的每個(gè)分量除以4.24那么我們就把向量放縮成了大小正好為1(也就是到原點(diǎn)的距離為1)的向量。在接下來(lái)的例子中我們將看到為什么這個(gè)被稱(chēng)為向量歸一化的過(guò)程非常有用,向量的歸一化保留了向量的方向,但是提供了通過(guò)對數字(也就是標量)值進(jìn)行乘法來(lái)放縮大小的能力。
在接下來(lái)的例子中,我將假設你的數學(xué)庫用Vector2 代指二維向量,用Vector3代指三維向量。它們在不同的庫和編程語(yǔ)言中有各種不同的名字,舉個(gè)例子來(lái)說(shuō),vector、vector3、 Vector3f、 vec3、 point、 point3f等等都是向量的名字。你的數學(xué)庫中關(guān)于向量部分肯定有很多文檔和例子。
注意:向量類(lèi)型在編程語(yǔ)言的世界里面通常有兩種含義,既可以用來(lái)指傳統的數學(xué)/物理場(chǎng)景中的向量,也可以用來(lái)表示自行控制的n維單位。這里僅僅是做一個(gè)小提醒。
像其他變量一樣,你代碼中的向量到底代表著(zhù)什么含義完全取決于你的控制:它可以是一個(gè)位置、方向或者速度。下面是游戲中常見(jiàn)的一些向量用法
位置 - 向量代表著(zhù)真實(shí)位置與你的世界坐標原點(diǎn)(0, 0, 0)的一個(gè)偏移量。
方向 - 向量看起來(lái)非常像是一個(gè)箭頭指著(zhù)某個(gè)方向。它確實(shí)是可以這么用。舉個(gè)例子來(lái)說(shuō),如果你有一個(gè)指向南的向量,那么你可以把這個(gè)向量賦予你的所有單位作為它們的新方向,那么它們都將面向南。
方向向量的一個(gè)特例是長(cháng)度為1的向量。它也被稱(chēng)為歸一化的向量或者簡(jiǎn)稱(chēng)為標準向量。
一個(gè)速度(velocity )向量可以描述一個(gè)運動(dòng)。在這種情況下,它描述的是特定時(shí)間內的位置的變化。
記住最基本的內容-向量加法和減法
向量加法是用來(lái)累加兩個(gè)向量所描述的不同,并寫(xiě)入最后的向量中。
比如說(shuō),一個(gè)物體移動(dòng)了A向量這么大的位移,然后又移動(dòng)了B向量這么大的位移,那么結果就仿佛是它一共移動(dòng)了C向量這么大的位移(其中C = A + B)。
對于向量減法來(lái)說(shuō),就相當于把第二個(gè)向量反轉,然后把反轉的向量加到第一個(gè)向量身上。
注意:坐標系解向量加減法:在直角坐標系里面,定義原點(diǎn)為向量的起點(diǎn).兩個(gè)向量和與差的坐標分別等于這兩個(gè)向量相應坐標的和與差若向量的表示為(x,y)形式,A(X1,Y1) B(X2,Y2),則A+B=(X1+X2,Y1+Y2),A-B=(X1-X2,Y1-Y2)
簡(jiǎn)單地講:向量的加減就是向量對應分量的加減。類(lèi)似于物理的正交分解。
例子: 物體之間的距離
如果在這個(gè)例子中,向量代表的分別是物體A和B的位置,那么 B – A將是代表著(zhù)A和B物體位置差的向量。 B – A所得到的結果將表示A位置移動(dòng)到B位置所需的方向和距離。
舉個(gè)例子來(lái)說(shuō),要得到人到樹(shù)的距離向量你必須用樹(shù)的位置減去人的位置,如下圖所示:
我用了偽代碼(pseudo-code )來(lái)保持代碼的簡(jiǎn)潔方便閱讀。在括號內的三個(gè)數字(x,y,z)代表著(zhù)一個(gè)向量。:
注意:偽代碼是一種算法描述語(yǔ)言。使用偽碼的目的是使被描述的算法可以容易地以任何一種編程語(yǔ)言(Pascal,C,Java等)實(shí)現。因此,偽代碼必須結構清晰、代碼簡(jiǎn)單、可讀性好,并且類(lèi)似自然語(yǔ)言。介于自然語(yǔ)言與編程語(yǔ)言之間。以編程語(yǔ)言的書(shū)寫(xiě)形式指明算法職能。使用偽代碼, 不用拘泥于具體實(shí)現。相比程序語(yǔ)言(例如Java,C++,C, Dephi 等等)它更類(lèi)似自然語(yǔ)言:
tree_position = (10, 10, 0)
my_position = (3, 3, 0)
# distance anddirection you would need to move
# to getexactly where the tree is
vector_to_tree = tree_position - my_position
例子: 速度
除了位置向量以外,對象可能還有一個(gè)向量用來(lái)表示速度。
舉個(gè)例子來(lái)說(shuō),大炮炮彈的速度向量描述的是它下一秒將要移動(dòng)的距離。
當第一次被發(fā)射的時(shí)候,大炮炮彈可能具有如下這些屬性:
position = (0, 10, 10) # position: 10units in Y and Z direction
velocity = (500, 0, 0) # initialmovement is 500 units in X direction over the next second
每秒鐘要基于速度向量來(lái)更新一次炮彈的位置:
position += velocity # add velocityto position and update position
概念: 仿真
等等!我們不希望每一秒才更新一次物體。事實(shí)上,我們希望盡可能的頻繁更新物體的信息。
但是我們不能指望兩次更新之間的時(shí)間總是固定的。所以我們使用了delta時(shí)間,這是上一次更新到這一次更新的時(shí)間差。
因為delta時(shí)間代表的是逝去時(shí)間的一個(gè)時(shí)間差。所以我們可以用它來(lái)得到這次更新到上一次更新之間的這段時(shí)間內物體的移動(dòng)速度所導致的位置差。
position += velocity * delta
這是一個(gè)非?;镜姆抡?。為了實(shí)現一個(gè)仿真,我們在自己的世界里面建模了我們的對象該具有怎樣的行為(比如說(shuō)大炮炮彈永遠具有不變的速度)。然后我們加載最初的游戲狀態(tài)(大炮炮彈開(kāi)始的時(shí)候具有初始位置和速度)。
最后一塊拼圖是要把所有的東西融合在一起,這就是update循環(huán),它會(huì )定期執行,我們用delta時(shí)間(也就是時(shí)間間隔)來(lái)記錄上一次更新到這次更新的時(shí)間間隔。在每次update調用的時(shí)候,它會(huì )根據我們預先定義好的規則(比如說(shuō)用炮彈的速度來(lái)更新炮彈的位置)來(lái)對每個(gè)仿真物體進(jìn)行更新。
例子:重力、空氣阻力和風(fēng)
我們的炮彈移動(dòng)是很無(wú)聊的:它永遠是向一個(gè)方向移動(dòng)并且移動(dòng)的速度永遠是不變的。我們需要它對周?chē)氖澜缱龀龇磻?。舉個(gè)例子來(lái)說(shuō),我們希望重力能讓炮彈下落,希望空氣阻力會(huì )讓炮彈的速度變慢,至于風(fēng)呢,僅僅是加進(jìn)來(lái)為了好玩。
在一個(gè)游戲中重力實(shí)際上意味著(zhù)什么呢?嗯,它會(huì )產(chǎn)生一個(gè)副作用,在物體向下的方向增加物體的速度。因為在我們的例子中Y軸是向上的,所以我們的重力向量將是下面這樣的:
# increasevelocity of every object -2 down per second
gravity_vector = (0, -2, 0)
所以,在每次進(jìn)行update調用之前,我們可以修改速度變量,如下面代碼所示:
velocity += gravity_vector * delta # applygravity effect
position += velocity * delta # updateposition
讓我們假設空氣很厚,所以空氣會(huì )每半秒就降低一次炮彈的速度。
velocity += gravity_vector * delta # applygravity effect
velocity *= 0.5 * delta # apply 0.5slowdown per second
position += velocity * delta # updateposition
速度會(huì )受到空氣阻力的影響因為炮彈總是在空氣中行進(jìn)??諝鈺?huì )阻擋它的前進(jìn)進(jìn)而減少它的動(dòng)能。所以我們需要調整下炮彈在空氣中前進(jìn)的速度。
但是,還有一個(gè)恒定的力會(huì )改變炮彈的運動(dòng),就像風(fēng)一樣。
# modifykinetic energy / velocity
# add all forces
final_change_per_second = velocity + wind_force_per_second
# updateposition
position += final_change_per_second * delta
這個(gè)例子的著(zhù)眼點(diǎn)在于說(shuō)明用簡(jiǎn)單的向量數學(xué)構建如此復雜的一個(gè)行為是多么的容易。
概念: 方向
通常情況下,你不會(huì )需要從A到B的距離,而是需要從A指向B的方向。向量A到向量B的距離當然可以用來(lái)表示方向,但是如果你需要從A向B移動(dòng)“很小一點(diǎn)點(diǎn)”,但是要精確的按照你希望的速度該怎樣做呢?
在這種情況下向量長(cháng)度應該無(wú)關(guān)緊要的,如果我們把方向向量的長(cháng)度縮減為1,就可以用于這個(gè)目的以及其他一些情況。我們把這個(gè)縮減稱(chēng)為歸一化(normalization ),得到的向量稱(chēng)為標準向量(normalvector)。
所以,一個(gè)標準向量它的長(cháng)度應該總是1,否則它就不是一個(gè)標準向量。。
一個(gè)標準向量代表的是一個(gè)角度,而沒(méi)有實(shí)際位置移動(dòng)相關(guān)的其他任何信息。如果我們用一個(gè)標量數字乘以一個(gè)標準向量,我們就得到了一個(gè)方向向量,同時(shí)它的長(cháng)度就是標量數字的大小。
在你的數學(xué)庫里面應該有一個(gè)normalize函數,來(lái)從任意的向量中得到一個(gè)標準向量。
所以如果要朝B精確的移動(dòng)3個(gè)單位長(cháng)度,代碼如下:
final_change = (B - A).normalize * 3
概念:平面
一個(gè)標準向量也可以用來(lái)描述一個(gè)平面所朝向的方向。你可以把平面想象成從一個(gè)特定點(diǎn)P出發(fā)的無(wú)限大的片,對這個(gè)片的旋轉可以通過(guò)法向量N來(lái)精確描述出來(lái)。
要旋轉這個(gè)片/平面,你應該改變它的法向量。
注意:法向量是空間解析幾何的一個(gè)概念,垂直于平面的直線(xiàn)所表示的向量為該平面的法向量。由于空間內有無(wú)數個(gè)直線(xiàn)垂直于已知平面,因此一個(gè)平面都存在無(wú)數個(gè)法向量(包括兩個(gè)單位法向量)。如果一個(gè)非零向量n與平面a垂直,則稱(chēng)向量n為平面a的法向量。垂直于平面的直線(xiàn)所表示的向量為該平面的法向量。每一個(gè)平面存在無(wú)數個(gè)法向量。
概念: 點(diǎn)積(Dot Product)
點(diǎn)積是對兩個(gè)向量進(jìn)行操作然后返回一個(gè)數字。你可以把返回的這個(gè)數字看作是兩個(gè)向量比較的一個(gè)方法。
注意:在數學(xué)中,點(diǎn)積(dot product; scalar product,也稱(chēng)為數量積)是接受在實(shí)數R上的兩個(gè)向量并返回一個(gè)實(shí)數值標量的二元運算。它是歐幾里得空間的標準內積。
通常寫(xiě)為:
result = A dot B
兩個(gè)法向量之間的這種比較是特別有用的,因為這個(gè)數字會(huì )代表著(zhù)他們在旋轉上的不同。
如果點(diǎn)積返回的結果為1,說(shuō)明這兩個(gè)法向量指向同一個(gè)方向。
如果點(diǎn)積返回的結果為0,說(shuō)明這兩個(gè)法向量互相垂直。
如果點(diǎn)積返回的結果為-1,說(shuō)明這兩個(gè)法向量指向完全相反的方向。
下面這張圖說(shuō)明的是點(diǎn)積返回的結果與兩個(gè)向量之間夾角的關(guān)系:
請注意上圖中從1到0以及從0到-1的變化不是線(xiàn)性的,而是遵循余弦曲線(xiàn)進(jìn)行變化的。所以,要從點(diǎn)積的結果中得到一個(gè)角度,你需要對返回的結果調用反余弦,如下面代碼所示:
angle = acos(A dot B)
例子: 光照
試想一下我們正在寫(xiě)一個(gè)光照著(zhù)色器并且我們需要計算一個(gè)特定表面點(diǎn)的像素明亮度。我們有如下這些信息:
一個(gè)法向量用來(lái)表示這個(gè)點(diǎn)上的表面的方向
光源的位置
這個(gè)表面點(diǎn)的位置
我們可以得到計算特定點(diǎn)到光源的距離向量:
distance_vec = light_pos - point_pos
以及把這個(gè)特定點(diǎn)上的光照方向變?yōu)橐粋€(gè)標準向量:
light_direction = distance_vec.normalize
然后基于我們已有的關(guān)于角度和點(diǎn)積(dot product)之間關(guān)系的知識,我們可以使用表面法向量和光照方向之間的點(diǎn)積來(lái)計算這個(gè)點(diǎn)的明亮度。在最簡(jiǎn)單的情況下,它就完全等于點(diǎn)積得到的結果!
brightness = surface_normaldot light_direction
不管你是否相信,這就是一個(gè)簡(jiǎn)單的光照著(zhù)色器的基本框架。OpenGL中的實(shí)際片段著(zhù)色器代碼就是這樣的(如果你沒(méi)有著(zhù)色器的相關(guān)知識也不用擔心,這只是一個(gè)用來(lái)說(shuō)明點(diǎn)積實(shí)際應用的例子,我們不會(huì )在著(zhù)色器方面展開(kāi)太多):
注意:Shader(著(zhù)色器)是用來(lái)實(shí)現圖像渲染的用來(lái)替代固定渲染管線(xiàn)的可編輯程序。Shader分為Vertex Shader(頂點(diǎn)著(zhù)色器)和Pixel Shader(像素著(zhù)色器兩種((注:兩種著(zhù)色器在不同的實(shí)現中略有不同)。其中Vertex Shader主要負責頂點(diǎn)的幾何關(guān)系等的運算,Pixel Shader主要負責片源顏色等的計算。
著(zhù)色器替代了傳統的固定渲染管線(xiàn),可以實(shí)現3D圖形學(xué)計算中的相關(guān)計算,由于其可編輯性,可以實(shí)現各種各樣的圖像效果而不用受顯卡的固定渲染管線(xiàn)限制。這極大的提高了圖像的畫(huà)質(zhì)。
varying vec3surface_normal;
varying vec3vertex_to_light_vector;
void main(void)
{
vec4diffuse_color = vec3(1.0, 1.0, 1.0); // the color of surface - white
float diffuse_term = dot(surface_normal, normalize(vertex_to_light_vector));
gl_FragColor = diffuse_color * diffuse_term;
}
注意dot函數和normalize函數的使用用法是與前一個(gè)例子唯一有區別的地方。
例子:點(diǎn)到一個(gè)平面的距離
如果要得到某個(gè)點(diǎn)到一個(gè)平面的最短距離,首先計算出這個(gè)點(diǎn)到平面上任意一點(diǎn)的距離向量,不要對這個(gè)向量進(jìn)行歸一化,然后將其與平面的法向量相乘,得到的就是這個(gè)點(diǎn)到這個(gè)平面的最短距離。
distance_to_a_plane = (point - plane_point) dotplane_normal;
例子:這個(gè)點(diǎn)是否在這個(gè)平面上?
利用上一個(gè)例子的內容,計算這個(gè)點(diǎn)到這個(gè)平面的最短距離,如果等于0,那么這個(gè)點(diǎn)就在這個(gè)平面上。
例子:一個(gè)向量是否與一個(gè)平面平行?
如果這個(gè)向量與平面的法向量垂直的話(huà),那么這個(gè)向量就是與這個(gè)平面平行的。
我們已經(jīng)知道,如果兩個(gè)向量的點(diǎn)積等于0的時(shí)候這兩個(gè)向量是垂直的。
所以當向量與平面法向量的點(diǎn)積等于0的時(shí)候,那么這個(gè)向量就是與這個(gè)平面平行的。
例子:線(xiàn)段是否與一個(gè)平面相交
讓我們假設下,線(xiàn)段從P1點(diǎn)開(kāi)始到P2點(diǎn)結束。在平面上的一個(gè)特定點(diǎn)是SP而平面的法向量是SN。
如果我們假想一個(gè)平面穿過(guò)線(xiàn)段的第一個(gè)點(diǎn)P1,那么要解決這個(gè)問(wèn)題就可以轉換為計算哪個(gè)點(diǎn)(P2還是SP)既更接近P1又與SN更加平行。這個(gè)值可以通過(guò)點(diǎn)積計算得到,如下所示:
dot1 = SN dot (SP - P1)
dot2 = SN dot (P2 - P1)
你可以計算它與平面相交的”程度“,也就是將這兩個(gè)值相比較(相除)。
u = (SN dot (SP - P1)) / (SN dot (P2 - P1))
如果 u == 0,那么線(xiàn)段是與平面平行的。
如果 u <= 1 并且 u > 0, 那么線(xiàn)段與平面相交。
如果u > 1,那么線(xiàn)段與平面不相交。
可以將線(xiàn)段的向量與u相乘得到精確的相交點(diǎn):
intersectionpoint = (P2 - P1) * u
概念: 向量積(Cross Product)
向量積也是對兩個(gè)向量的一個(gè)操作。結果是一個(gè)新的向量,它與前兩個(gè)向量垂直,并且它長(cháng)度是前兩個(gè)向量長(cháng)度的均值。
注意:向量積,數學(xué)中又稱(chēng)外積、叉積,物理中稱(chēng)矢積、叉乘,是一種在向量空間中向量的二元運算。與點(diǎn)積不同,它的運算結果是一個(gè)向量而不是一個(gè)標量。并且兩個(gè)向量的叉積與這兩個(gè)向量的和垂直。
兩個(gè)向量a和b的叉積寫(xiě)作a×b(有時(shí)也被寫(xiě)成a∧b,避免和字母x混淆)。
向量積可以被定義為:|向量a×向量b|=|a||b|sinθ在這里θ表示兩向量之間的夾角(共起點(diǎn)的前提下)(0° ≤ θ ≤ 180°),它位于這兩個(gè)矢量所定義的平面上。
需要注意的是對于向量積操作來(lái)說(shuō),參數的順序是有影響的,如果調換了參數的順序,生成的結果向量長(cháng)度不變,但是方向將會(huì )完全相反。
例子: 碰撞
假設物體以某個(gè)角度往墻那里移動(dòng)。但是墻是無(wú)摩擦的,所以物體應該沿著(zhù)墻的表面移動(dòng)而不是停下來(lái)。在這種情況下,如何計算物體的新位置?
首先,我們用一個(gè)向量來(lái)表示如果沒(méi)有墻的情況下物體應該移動(dòng)的距離。我們將稱(chēng)它為“變化向量“。然后,我們將假設物體觸碰到了墻。并且我們還需要墻表面的法向量。
我們將使用向量積來(lái)得到一個(gè)新的向量,它與”變化向量“和平面法向量相垂直:
temp_vector = change crossplane_normal
然后,最后的方向是與新的向量以及之前的平面法向量相垂直的:
new_direction = temp_vectorcross plane_normal
所以,就如下面代碼這樣得到最后的結果:
new_direction = (change crossplane_normal) cross plane_normal
現在該怎么辦?
通過(guò)這篇文章,我希望能彌補向量數學(xué)的理論和在游戲開(kāi)發(fā)中實(shí)際應用之間的鴻溝。但是,這也意味著(zhù)我在講解的過(guò)程中跳過(guò)了大量的東西。
但是我希望在閱讀完這篇文章以后,你對向量數學(xué)的整體框架更加清楚一點(diǎn)。文中對向量數學(xué)的遍歷可以視為游戲開(kāi)發(fā)中使用向量數學(xué)的一個(gè)概述。
以上就是關(guān)于pos機如何選擇sn,向量數學(xué)在游戲中如何使用的知識,后面我們會(huì )繼續為大家整理關(guān)于pos機如何選擇sn的知識,希望能夠幫助到大家!
