大多遊戲程式設計師和圖形程式都知道渲染流水線這個概念,它的本質是將3d的場景對映到顯示屏上的一系列操作。它主要分3個階段:應用程式階段,幾何階段,光柵化階段。將攝像機位置,光照,模型的圖元輸入到幾何階段便是應用程式階段。進行多邊形和頂點操作把3d資料對映到2d的階段便是幾何階段。給定進過變換和投影之後的頂點,顏色,紋理座標,給每個畫素正確配色,這個階段叫光柵化階段。具體的流水線概念,這篇文章不做詳細介紹,這篇文章主要講解幾何階段中的包圍體測試。
幾何階段簡介
幾何階段分幾個階段,流水線上按順序為頂點資料等執行以下操作
模型檢視變換:模型空間變換到觀察空間
頂點著色:光照處理
投影:將模型變換到乙個單位立方體內
裁剪:裁剪不顯示的部分
螢幕對映:對映到螢幕座標系
而物體剔除和背面消隱是處於模型檢視變換的可選操作。
在模型檢視變換階段時需要將物體座標系的點先轉換到世界座標系,然後再由世界座標系轉換到檢視座標系(相機座標系)
然而執行世界座標到相機座標前,需要進行幾個測試。來判斷物體對相機是否可見,避免場景過大時造成大量多餘的計算,然後準確無誤地渲染物體。而這些測試被稱為隱藏面消除。
執行的測試有2種,一種是背面消隱,一種是包圍體測試。
背面消隱的原理可以看這篇部落格,我這篇就主要講很少被提及的包圍體測試的原理
原理很簡單:就是用乙個球體把物體包起來,然後判斷球體是否在視景體外,是則丟棄這個物體。『
現在我們假設有乙個物體,包含一組頂點,要找到離中心遠最遠的頂點,最遠頂點到中心點的距離便是球體的半徑,**實現如下
class gameobject
/// /// 計算半徑
///
private void calculatemaxradius()
max_radius = (float)system.math.sqrt(max_radius);}}
為了便於理解,我用畫圖工具畫了個視景體的圖。視景體就是塗畫的淺藍色部門區域。
不過為了計算,程式裡的視景體是個由遠裁剪面,*裁剪面,y = ymax(視景體內點y座標的最大值),y = ymin,x = xmax,x = xmin六個面構成的長方體,我們只需要判斷球體是否在長方體內即可。也就是判斷球體的6個臨界頂點是否在視景體內即可。
遠*裁剪面
首先我們判斷球體是否在遠*裁剪面間
只需要判斷球體z座標最大的點的z座標值是否在比*裁面的z值小,球體z座標最小的點的z座標值是否比遠裁面的z值大即可。**實現如下
//遠*裁剪面裁剪
if (spherecenterpos.z - go.max_radius> camera.zf||
spherecenterpos.z + go.max_radius < camera.zn)
左右裁剪面和上下裁剪面
接下來是對左右裁剪面和上下裁剪面的判斷,不過由於需要計算xmin,ymin,xmax,ymax,我們需要先獲得攝像頭的焦距
焦距就是位於視景體內的黃線長度,也就是視景體的z深度
焦距的計算和攝像頭資料結構定義**如下
class camera
} }
通過**我們可以看到,焦距的計算,只是簡單的三角函式的變換,不做詳細介紹,不理解可以結合下圖來理解
完整**
/// /// 物體剔除-包圍球測試
///
private bool cullobject(gameobject go,vector3 spherecenterpos)
float focallength = camera.focallength;//獲得焦距
//左右裁剪面剔除
float z_test = 0.5f * camera.aspect * camera.screenheight *
spherecenterpos.z / focallength;
if (spherecenterpos.x - go.max_radius > z_test ||
spherecenterpos.x + go.max_radius < -z_test)
//上下裁剪面剔除
z_test = 0.5f * camera.screenheight *
spherecenterpos.z / focallength;
if (spherecenterpos.y - go.max_radius > z_test ||
spherecenterpos.y + go.max_radius < -z_test)
return go.mesh.cullflag = false;
}
程式中的視景體實際上並沒有成功代表整個視景體,包圍球也不一定很好地代表整個物體。而且存在物體部分位於視景體的情況,包圍體測試不一定管用。但這不代表包圍體測試沒有意義,至少在遊戲中,能有效避免對不可見的大型區域進行處理。 正則不怎麼會用
一 基本正則 1.乙個點 匹配除換行符之外的任意乙個字元,例如r.t能匹配rat ret,但是不能匹配root 2.符號 用於匹配前乙個字元0次或任意多次,比如ab 可以a ab abb等。比如 代表任意長度的不包含換行的字元 grep r t etc passwd 沒有rt rrt rrrt,只能...
例項3 邏輯操作,很少用卻很有用
所謂邏輯,即與 或關係,含有與 或關係運算子的表示式稱為邏輯表示式,在pascal語言中,與用and代替,或用or代替。編寫程式時,基本是處理這樣幾類問題 表示式 判斷 分支選擇。判斷有簡單判斷與複雜判斷,在複雜判斷中,少不了用到各種邏輯關係。比如有這樣乙個判斷 篩選出年裡在18 20歲 長頭髮 身...
BOM一些不怎麼重要的方法
console.log window.innerwidth 獲取可視視窗的寬度 console.log window.innerheight 獲取可視視窗的高度 location.href location.reload 重新整理頁面 window.history.forward 頁面前進一次 wi...