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