續上篇「Part1」
掰了~BoundingBox,哈囉!BoundingSphere
除了BoundingBox之外,XNA還提供了BoundingSphere這個碰撞檢測的類別。再次提醒,BoundingSphere是一個不可見的類別,且有個叫做Intersects()的方法用來告訴你是否有和其他物件碰撞。
例如:
if (bulletBoundingSphere.Intersects(planeBoundingSphere)) { //plane's been hit. cue smoke, flames, snakes in a panic, singing nuns, whatever… } |
回想一下par1的部分…是否還記得這些??
這裡有些應該了解的:
|
一個球體不管怎麼轉,他還是一個球體。所以,旋轉的部分就可以甭管了~不再有AABB的複雜問題。但我們仍需更新BoundingSphere的座標,也需要隨著模型縮放。
到BoundingSphere的中心旅行
(意義不明)
比起BoundingBox,要準確的移動BoundingSphere更為簡單。BoundingSphere就只有一個用Vector3代表的中心點,以及一個半徑。當模型移動時,需要將中心點一到正確的地方。當然,如果模型有縮放仍然要跟著縮放。
說完這些,你一定很困惑「OK~那這些球體從哪邊來的?」
嗯~你可以輕易的創造它們,但沒那必要。XNA的Model類別會自動幫Model裡的每個ModelMesh產生一個BoundingSphere放在模型裡。
像是我的Spitfire模型就有幾個ModelMesh,像是機翼、機身、駕駛座艙、螺旋槳、尾翼等等…
這裡範例展示要如何取得Model的BoundingSphere…
//Load the model using my game's instance of a ContentManager.
Model myModel = MyGame.ContentManager.Load<Model>("ContentMeshesMyModel"); foreach (ModelMesh mesh in myModel.Meshes) |
※Heightlight版
當XNA的ContentManager讀取這個Model時,它會產生包覆每個組件的BoundingSphere。座標,mesh.BoundSphere.Center,他是相對於整個Nodel的中心點(0, 0, 0)。我相信有時候會參考像是「Object space」的座標。不要和「World space」混淆了,World space是描述這個物件在整個場景中的座標。
如你現在將BoundingSphere畫出來,應該會像是我的Spitfire模型一樣…
你可以看到飛機上幾個組件的球體:
- 亮綠色是機翼
- 橙色是尾翼
- etc…
這些「預設」的BoundingSphere可能非常符合你的模型。以這個Spitfire模型來看,很顯然的不適合。如果用part1題到的半徑檢測技術來看,我的飛機顯然變成一個更大的目標(對子彈來說)。
讓我們來修正他…
拆解與克服
當然,這些「預設」的BoundingSphere並不能真的切成數塊,但它們可以為我們在執行時提供一些資訊。所以,我們要使用這些資訊來產生數個新的BoundingSphere來更適用於我們的模型。
就像是…
我們會在Model讀取完之後,馬上產生新的BoundingSphere,並且儲存起來以供使用。這裡展示我如何處理他們。我之道還有很大的進步空間,歡迎指教。
接著來看看這些程式碼,它們可以在MyGame.cs裡面找到…
private void AnalyseModel() { // Take a copy of the Model's BoneTransforms (transforms to be applied to each part of the model) GetBoneTransforms(); // Build BoundingParts for Collision Detection private void GetBoneTransforms() |
※Heightlight版
你可以看到我在ContentManager讀取完Model之後馬上呼叫AnalyseModel()。
GetBoneTransforms()會複製一份Model的BoneTransform矩陣資料。簡而言之,這些BoneTransform是用來告 訴XNA要如何定位、旋轉和縮放模型裡的每個組件。如果忽略它,我們的飛機組件(像是機翼、機身、尾翼)可能就不會依照模型設計者所設計的展現。
是的,這一切聽起來令人興奮,所以來看看著個好東西。這些程式碼在MyGame.cs約頂部的地方,你可以看到以下有趣的程式碼…
//Blob mesh private string[] _modelBoundingPartNames = new string[] { "Fuselage", "Wing", "Tail" }; private Color[] _modelBoundingPartColours = new Color[] private Vector4[][] _modelBoundingPartSubdivisions = new Vector4[][] |
※Heightlight版
這些陣列將在範例裡面使用到,其中最需要注意的是_modelBoundingPartSubdivisions的這個陣列。
他是用來描述如何在Model剛讀取時,利用「預設」的BoundingSphere產生新的BoundingSphere。
接著來看如何利用Vector4的定義來產生機翼的5個BoundingSphere。Vector4的X、Y和Z分別代表在各軸的位移百分比,而W則是代表半徑的縮放百分比。
接下來看BuildBoundingParts()方法會做些甚麼事情!
/// <summary> /// Builds a collection of BoundingParts for each ModelMesh in the Model. /// Each BoundingPart will contain one or many BoundingSphere as defined in the _modelBoundingPartSubdivisions array. /// </summary> private void BuildBoundingParts() { _modelBoundingParts = new BoundingPartList(); BoundingPart boundingPart; int meshIndex = 0; //Create, Scale and Position new BoundingSphere's according to the defined subdivisions for this part of the model. //Determine the new BoundingSphere's Center by interpolating. pieces[pieceIndex] = new BoundingSphere(centre, radius); pieceIndex++; _modelBoundingParts.Add(boundingPart); |
※Heightlight版
我會在之後解釋BoundingPart類別。現在你只需要知道他是一個外覆類別(wrapper class),它擁有數個BoundingSphere物件。………..
它是這樣運作的…
我會走訪Model裡面的每個ModelMesh。
使用它的索引通過_modelBoundingPartSubdivisions陣列裡,對映的元素。
(這裡不確定怎麼翻…)
他會給我一個Vector4,利用XNA的MathHelper.Lerp() (線性內插)方法和Vector4的X、Y、Z和W,建構新BoundingSphere的中心點和半徑。
我愛Lerp。Lerp比起The Fonz酷多了!基本上它可以讓你要求「給我一個介於100 & 200之間70%的值」。
0% 是 100。
100% 是 200。
所以70%就是170。
在這裡,我使用XNA的「預設」BoundingSphere半徑做為範圍的規範。
例如,最小值為Center.X – Radius。最大值為Center.X + Radius。所以我將這些值對subdivision的X做Lerp。
這個BoundingPart類別可以取得適合的BoundingSphere,並且將它們加入主要的集合中。
OK!所以現在我有一個Winodws Live Writer的技術困難。我想教學太長了些,所以我先在這裡停下來,在Part3繼續…
天…
這篇真有夠長的
重點是我還因為不小心撞到滑鼠上的邊緣鍵(可以用來快速讓網頁切換上下頁)而導致我得整個重打…
那時候已經打到80%了說…
整個超無力…所以拖到現在才打完
先這樣啦~