3D游戲編程大師技巧(2) 3D線框引擎

EngineMain_Tank.png
EngineMain_Box.png

目錄

學(xué)習(xí)了前七章的vs工程浑此, github地址: https://github.com/GeWenL/My3DGameEngine

  1. 本書坐標(biāo)是行矩陣還是列矩陣?
  2. Model變換 : 局部坐標(biāo)到世界坐標(biāo)
  3. View變換:世界坐標(biāo)到相機(jī)坐標(biāo)
  4. Projection變換 + 投影到Screen:相機(jī)坐標(biāo)到透視坐標(biāo)再到屏幕坐標(biāo)
  5. 渲染線框
  6. 背面剔除 與 物體剔除

一救恨、本書坐標(biāo)是行矩陣還是列矩陣?

unity使用的是列矩陣,本書中的坐標(biāo)是行矩陣還是列矩陣训堆?

為什么要關(guān)注這個(gè)問題颂暇?

頂點(diǎn)坐標(biāo)執(zhí)行變換的順序是縮放酗洒、旋轉(zhuǎn)、位移凛忿。
列矩陣:TRS * POS == (T(R(S * POS)))從右到左執(zhí)行
行矩陣:POS *SRT

Unity中旋轉(zhuǎn)矩陣的順序是:(基于self坐標(biāo)系)

  • 旋轉(zhuǎn)后不改變坐標(biāo)系(官方) zxy :(My * (Mx * (Mz * POS)))
  • 旋轉(zhuǎn)后改變坐標(biāo)系 yxz :(Mz * (Mx * (My * POS)))

從Mat_Mul_VECTOR4D_4X4函數(shù)中可以看出澈灼,用坐標(biāo)va的行乘以矩陣mb的列。是行矩陣[x,y,x,w]侄非。

void Mat_Mul_VECTOR4D_4X4(VECTOR4D_PTR  va, 
                          MATRIX4X4_PTR mb,
                          VECTOR4D_PTR  vprod)
{
// this function multiplies a VECTOR4D against a 
// 4x4 matrix - ma*mb and stores the result in mprod
// the function makes no assumptions

    for (int col=0; col < 4; col++)
        {
        // compute dot product from row of ma 
        // and column of mb
        float sum = 0; // used to hold result

        for (int row=0; row<4; row++)
             {
             // add in next product pair
             sum+=(va->M[row]*mb->M[row][col]);
             } // end for index

        // insert resulting col element
        vprod->M[col] = sum;

        } // end for col

} // end Mat_Mul_VECTOR4D_4X4

二蕉汪、Model變換

頂點(diǎn)坐標(biāo)執(zhí)行變換的順序是縮放、旋轉(zhuǎn)逞怨、位移者疤。

1. 示例版本demoII7_3.cpp的實(shí)現(xiàn)方式:
  1. 縮放:在load模型的時(shí)候就對(duì)局部坐標(biāo)進(jìn)行縮放,非矩陣叠赦。變換后存放在vlist_local局部信息中驹马。
    Load_OBJECT4DV1_PLG(&obj, "cube2.plg",&vscale, &vpos, &vrot);
// scale vertices
obj->vlist_local[vertex].x*=scale->x;
obj->vlist_local[vertex].y*=scale->y;
obj->vlist_local[vertex].z*=scale->z;
  1. 旋轉(zhuǎn):旋轉(zhuǎn)矩陣,變換后存放在vlist_local局部信息中除秀。

在示例中糯累,是遵循xyz的順序:

// generate rotation matrix around y axis
Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot);

// rotate the local coords of single polygon in renderlist
Transform_OBJECT4DV1(&obj, &mrot, TRANSFORM_LOCAL_ONLY,1);
  1. 位移:在load模型的時(shí)候就記錄局部坐標(biāo)系原點(diǎn)相對(duì)世界坐標(biāo)系的坐標(biāo)world_pos。非矩陣變換册踩。變換后存放在vlist_trans信息中泳姐。
Load_OBJECT4DV1_PLG(&obj, "cube2.plg",&vscale, &vpos, &vrot);
// set position of object 設(shè)置物體位置
obj->world_pos.x = pos->x;
obj->world_pos.y = pos->y;
obj->world_pos.z = pos->z;
obj->world_pos.w = pos->w;

// perform local/model to world transform
Model_To_World_OBJECT4DV1(&obj);
VECTOR4D_Add(&obj->vlist_local[vertex], &obj->world_pos, &obj->vlist_trans[vertex]);
2. 我使用縮放矩陣、旋轉(zhuǎn)矩陣暂吉、位移矩陣的版本:(注意順序:POS *SRT)
static MATRIX4X4 mRot; // general rotation matrix
static MATRIX4X4 mScale;
static MATRIX4X4 mTrans;
static MATRIX4X4 mTemp;
static MATRIX4X4 mSRT;
// generate rotation matrix around y axis
Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang--, z_ang, &mRot);
Build_Model_To_World_MATRIX4X4(&vpos, &mTrans);
Mat_Init_4X4(&mScale, vscale.x, 0, 0, 0,
    0, vscale.y, 0, 0,
    0, 0, vscale.z, 0,
    0, 0, 0, 1);
Mat_Mul_4X4(&mScale,&mRot, &mTemp);
Mat_Mul_4X4(&mTemp, &mTrans, &mSRT);
Transform_OBJECT4DV1(&obj, &mSRT, TRANSFORM_LOCAL_TO_TRANS, 1);

三胖秒、View變換

 // generate camera matrix
Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX);
Mat_Mul_4X4(&mt_inv, &mrot, &cam->mcam);

視圖變換只包含位移矩陣和旋轉(zhuǎn)矩陣,沒有縮放矩陣慕的。

World_To_Camera_OBJECT4DV1(&obj, &cam);

四阎肝、Projection變換 + 投影到Screen

1. 示例版本demoII7_3.cpp的實(shí)現(xiàn)方式:
// apply camera to perspective transformation
Camera_To_Perspective_OBJECT4DV1(&obj, &cam);

// apply screen transform
Perspective_To_Screen_OBJECT4DV1(&obj, &cam);

這兩次變換都不是基于矩陣變換。


Projection變換.png

投影到Screen.png
2. 我的矩陣版本:結(jié)合view矩陣肮街、Projection矩陣风题、Screen矩陣。
MATRIX4X4 mVP; // view矩陣 * Projection矩陣 * Screen矩陣
MATRIX4X4 mPer;
MATRIX4X4 mScr;
MATRIX4X4 mPerScr;// Projection矩陣 * Screen矩陣
Build_Camera_To_Perspective_MATRIX4X4(&cam, &mPer);
Build_Perspective_To_Screen_MATRIX4X4(&cam, &mScr);
Mat_Mul_4X4(&mPer, &mScr, &mPerScr);
Mat_Mul_4X4(&(&cam)->mcam, &mPerScr, &mVP);
Transform_OBJECT4DV1(&obj, &mVP, TRANSFORM_TRANS_ONLY, 1);
Convert_From_Homogeneous4D_OBJECT4DV1(&obj);

五嫉父、渲染線框

  1. Draw_OBJECT4DV1_Wire16(&obj, back_buffer, back_lpitch);// render the object
  2. Draw_Clip_Line16
  3. Draw_Line16
  4. UCHAR *back_buffer = NULL; // secondary back buffer

六沛硅、背面剔除 與 物體剔除

1. 背面剔除:在世界空間下處理
// remove backfaces
Remove_Backfaces_OBJECT4DV1(&obj, &cam);
  1. 計(jì)算三角形法線(通過叉乘):u = p0->p1, v=p0->p2, 法線n=uxv

     // we need to compute the normal of this polygon face, and recall
     // that the vertices are in cw order, u = p0->p1, v=p0->p2, n=uxv
     VECTOR4D u, v, n;
    
     // build u, v
     VECTOR4D_Build(&obj->vlist_trans[vindex_0], &obj->vlist_trans[vindex_1], &u);
     VECTOR4D_Build(&obj->vlist_trans[vindex_0], &obj->vlist_trans[vindex_2], &v);
    
     // compute cross product
     VECTOR4D_Cross(&u, &v, &n);
    
  2. 計(jì)算三角形法線和相機(jī)視線dot 點(diǎn)積

     // now create eye vector to viewpoint
     VECTOR4D view;
     VECTOR4D_Build(&obj->vlist_trans[vindex_0], &cam->pos, &view);
    
     // and finally, compute the dot product
     float dp = VECTOR4D_Dot(&n, &view);
    
  3. 點(diǎn)積<=0,表示>=90度,不可見绕辖,設(shè)置為隱藏

    • a·b>0 方向基本相同稽鞭,夾角在0°到90°之間
    • a·b=0 正交,相互垂直
    • a·b<0 方向基本相反引镊,夾角在90°到180°之間
    // if the sign is > 0 then visible, 0 = scathing, < 0 invisible
    if (dp <= 0.0)
        SET_BIT(curr_poly->state, POLY4DV1_STATE_BACKFACE);
2. 物體剔除:

使用物體的中心和最大半徑來創(chuàng)建包圍球,測(cè)試是否在左、右弟头、上吩抓、下、遠(yuǎn)赴恨、近六個(gè)裁切面內(nèi)疹娶,即是否在視椎體內(nèi)。


將物體從3D渲染管線中剔除.png

示例是在世界空間下檢測(cè)伦连;也可以在相機(jī)空間下處理雨饺。
因?yàn)槎家M(jìn)行M、V變換惑淳,只是前者用臨時(shí)變量存儲(chǔ)變換結(jié)果额港。

物體剔除.png
  1. 將球心變換為相機(jī)坐標(biāo) transform the center of the object's bounding sphere into camera space
POINT4D sphere_pos; // hold result of transforming center of bounding sphere

// transform point
Mat_Mul_VECTOR4D_4X4(&obj->world_pos, &cam->mcam, &sphere_pos);
  1. 遠(yuǎn)、近裁切面檢測(cè) cull only based on z clipping planes

     if (((sphere_pos.z - obj->max_radius) > cam->far_clip_z) ||
         ((sphere_pos.z + obj->max_radius) < cam->near_clip_z))
     {
         SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);
         return(1);
     }
    
  2. 左歧焦、右裁切面檢測(cè):test the the right and left clipping planes against the leftmost and rightmost points of the bounding sphere

     float z_test = (0.5)*cam->viewplane_width*sphere_pos.z / cam->view_dist;
    
     if (((sphere_pos.x - obj->max_radius) > z_test) || // right side
         ((sphere_pos.x + obj->max_radius) < -z_test))  // left side, note sign change
     {
         SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);
         return(1);
     }
    
  3. 上移斩、下裁切面檢測(cè):test the the top and bottom clipping planes against the bottommost and topmost points of the bounding sphere

    float z_test = (0.5)*cam->viewplane_height*sphere_pos.z / cam->view_dist;

    if (((sphere_pos.y - obj->max_radius) > z_test) || // top side
        ((sphere_pos.y + obj->max_radius) < -z_test))  // bottom side, note sign change
    {
        SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);
        return(1);
    }

相關(guān)鏈接:

  1. 3D游戲編程大師技巧(1) 源碼與配置項(xiàng)目 http://www.reibang.com/p/85d754620d8b
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绢馍,隨后出現(xiàn)的幾起案子向瓷,更是在濱河造成了極大的恐慌,老刑警劉巖舰涌,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猖任,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瓷耙,警方通過查閱死者的電腦和手機(jī)朱躺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哺徊,“玉大人室琢,你說我怎么就攤上這事÷渥罚” “怎么了盈滴?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長轿钠。 經(jīng)常有香客問我巢钓,道長,這世上最難降的妖魔是什么疗垛? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任症汹,我火速辦了婚禮,結(jié)果婚禮上贷腕,老公的妹妹穿的比我還像新娘背镇。我一直安慰自己咬展,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布瞒斩。 她就那樣靜靜地躺著破婆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胸囱。 梳的紋絲不亂的頭發(fā)上祷舀,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音烹笔,去河邊找鬼裳扯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谤职,可吹牛的內(nèi)容都是我干的饰豺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼柬帕,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼哟忍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陷寝,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤锅很,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后凤跑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爆安,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年仔引,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扔仓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咖耘,死狀恐怖翘簇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情儿倒,我是刑警寧澤版保,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站夫否,受9級(jí)特大地震影響彻犁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凰慈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一汞幢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧微谓,春花似錦森篷、人聲如沸输钩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽张足。三九已至,卻和暖如春坎藐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哼绑。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工岩馍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抖韩。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓蛀恩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親茂浮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子双谆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容