2013腾讯实时面试记录
原文鏈接:http://blog.csdn.net/left_la/article/details/8851759
始于2013.04.20南大筆試
結(jié)束于2013.04.24天豐一面
主要的幾個(gè)問題:
1、關(guān)于3D渲染管線
一個(gè)簡(jiǎn)單的例子,從游戲到多邊形繪制的圖形管線過程大致是這樣:
·?游戲決定在游戲中有哪些對(duì)象,?它們的模型,?使用的紋理,?他們可能在什么動(dòng)畫幀,以及它們?cè)谟螒蚴澜缋锏奈恢谩?游戲也決定照相機(jī)的位置和方向。
·?游戲把這些信息傳遞給渲染器。以模型為例?,渲染器首先要查看模型的大小?,照相機(jī)的位置,?然後決定模型在屏幕上是否全部可見,?或者在觀察者?(照相機(jī)視野)?的左邊,在觀察者的后面,或距離很遠(yuǎn)而不可見。它甚至?xí)褂靡恍┦澜鐪y(cè)定方式來計(jì)算出模型是否是可見的。?(參見下面這條)
·?世界可視化系統(tǒng)決定照相機(jī)在世界中的位置,并根據(jù)照相機(jī)視野決定世界的哪些區(qū)域?/?多邊形是可見的。有許多方法可以完成這個(gè)任務(wù),?包括把世界分割成許多區(qū)域的暴力方法,每個(gè)區(qū)域直接為"我能從區(qū)域?D?看見區(qū)域?AB & C",?到更精致的?BSP(二叉空間分割)世界。?所有通過這些剔除測(cè)試的多邊形被傳遞給多邊形渲染器進(jìn)行繪制。
·?對(duì)於每一個(gè)被傳遞給渲染器的多邊形,?渲染器依照局部數(shù)學(xué)?(?也就是模型動(dòng)畫)?和世界數(shù)學(xué)(相對(duì)于照相機(jī)的位置?)對(duì)多邊形進(jìn)行變換,并檢查決定多邊形是不是背對(duì)相機(jī)?(也就是遠(yuǎn)離照相機(jī))。背面的多邊形被丟棄。?非背面的多邊形由渲染器根據(jù)發(fā)現(xiàn)的附近燈光照亮。然后渲染器要看多邊形使用的紋理,并且確定?API/?圖形卡正在使用那種紋理作為它的渲染基礎(chǔ)。?在這里,多邊形被送到渲染?API,然后再送給顯卡。
Dave Salvator's 3D?管線一文中的圖表如下,可作為詳細(xì)參考:
硬件中的渲染管線也稱為渲染流水線,是顯示芯片內(nèi)部處理圖形信號(hào)相互獨(dú)立的的并行處理單元。一個(gè)流水線是一序列可以并行和按照固定順序進(jìn)行的階段。每個(gè)階段都從它的前一階段接收輸入,然后把輸出發(fā)給隨后的階段。就像一個(gè)在同一時(shí)間內(nèi),不同階段不同的汽車一起制造的裝配線,傳統(tǒng)的圖形硬件流水線以流水的方式處理大量的頂點(diǎn)、幾何圖元和片段。基本過程如下:
Local Space -->World Space -->View Space -->Backface Culling -->Lighting -->Clipping -->Projection -->Viewport Space -->Rasterization
Local Space(本地空間):本地空間以叫建模空間,這是我們定義物體三角形列的坐標(biāo)系。
World Space(世界空間):世界變換就是設(shè)置在世界中的各物體彼此的位置,大小和方向關(guān)系。
View Space(視圖空間):視圖空間變換就是世界坐標(biāo)系中的所有物體隨著攝像機(jī)的變換而做的相同的變換。
Backface Culling(背面揀選):背面揀選是指正面多邊形擋住了在它后面的背面多邊形,Direct3D將通過揀選(即刪除多余的處理過程)背面多邊形來提高效率的過程。
Lighting(光照):光源被定義在世界空間中,不是通過視圖空間變換到視圖空間中。
Clipping(裁剪):裁剪是揀選那些超出了可視體范圍的幾何圖形的過程。有三種情況完全包含,完全在外,部分在內(nèi)。
Projection(投影):從n維轉(zhuǎn)換成n-1維的過程。
Viewport Transform(視口變換):視口變換是將投影窗口變換為屏幕上一個(gè)矩形區(qū)域的可靠的變換。
Rasterization(光柵化):光柵化過程是計(jì)算需要顯示的每個(gè)三角形中每個(gè)點(diǎn)顏色值。
參考文章:
1.《游戲引擎剖析》第一部分
2.《3D管線教程 (一)》
2、紋理和材質(zhì)的概念與區(qū)別、如何綁定、如何渲染出來
? ? ? ? 紋理更偏向于“圖”,而材質(zhì)更偏向于“屬性”。
? ? ? ??打個(gè)比方說,對(duì)同一個(gè)立方體模型進(jìn)行處理:
? ? ? ??加材質(zhì)信息,可以認(rèn)為是為這個(gè)立方體加上屬性(這些屬性主要是指反射系數(shù)、折射系數(shù)等),比如木頭的屬性或大理石的屬性。
? ? ? ??紋理可以理解為是物體的外表圖案。在3D場(chǎng)景中,它極大的增加了物體的真實(shí)性。例如,我們可以在顯示屏上畫上一系列組合的矩形來表示一堵墻,但這樣的墻看起來光禿禿的,顏色也不真實(shí)。如果我們?cè)僭谏厦婕由弦恍﹦澓?#xff0c;磨損,苔跡,還有標(biāo)語,使它看起來更象一堵真實(shí)的墻,這就是紋理。
在D3D中,物體的這些外表圖案是存儲(chǔ)在一些二維的圖片中的,紋理也即是指這些二維的圖片,它一般采用bmp或 ppm的圖片格式。紋理上的每一個(gè)像素稱為紋理像素(Texel).
? ? ? ??材質(zhì)是指構(gòu)成現(xiàn)實(shí)中物體的材料,它使一個(gè)物體看上去更象金屬做的,陶瓷做的,還是塑料的。
在現(xiàn)實(shí)生活中,當(dāng)我們看一個(gè)鉛球,憑眼睛的觀察,手的觸摸,還有保存在我們頭腦里的一些生活的常識(shí),我們很容易判別該球是金屬做的,同樣看到一只足球,我們也很容易知道他是橡膠做的。
這樣就會(huì)產(chǎn)生一個(gè)問題,對(duì)顯示屏中虛擬的物體,光憑眼睛我們?cè)鯓颖鎰e它使金屬的,還是塑料的呢?或者說,在電腦上我們?cè)鯓颖硎疽粋€(gè)物體材質(zhì)屬性呢?? 在微軟Direct3D中, 是用物體對(duì)光的反射屬性來表達(dá)一個(gè)物體的材質(zhì)的,很顯然,金屬的物體和塑料的物體對(duì)光的反射會(huì)有不同的反射效果。這樣做雖然有時(shí)會(huì)產(chǎn)生失真,但對(duì)于屏幕渲染來說也是足夠了。
? ? ? ??材質(zhì)可以看成是材料和質(zhì)感的結(jié)合。在渲染程式中,它是表面各可視屬性的結(jié)合,這些可視屬性是指表面的色彩、紋理、光滑度、透明度、反射率、折射率、發(fā)光度等。
? ? ? ??從另一個(gè)角度來看,加了紋理的模型是靜態(tài)的和表面的,不會(huì)因?yàn)橥饨绛h(huán)境變化而變化(比如光照)。但是加了材質(zhì)的模型是動(dòng)態(tài)的和本質(zhì)的,當(dāng)外界環(huán)境變化的時(shí)候能做出相應(yīng)的變化,所以更真實(shí)。
最簡(jiǎn)單的例子就是,我們可以做出有木頭光澤的大理石模型,有大理石光澤的木頭模型,有木頭光澤的木頭模型,有大理石光澤的大理石模型。在上面的描述中,有“什么光澤”的“什么”,這是材質(zhì)信息;“什么模型”的“什么”,這是紋理信息。
6、關(guān)于RTTI
? ? ? ??Runtime Type identificaion(運(yùn)行時(shí)類型識(shí)別,RTTI),程序能夠使用基類的指針或引用來檢索這些指針或引用所指對(duì)象的實(shí)際派生類型。
? ? ? ??通過下面兩個(gè)操作符提供RTTI
? ? ? ??(1)typeid操作符,返回指針或引用所指對(duì)象的實(shí)際類型。
? ? ? ??typeid表達(dá)式如下:
? ? ? ??typeid(e)
? ? ? ??這里e是任意表達(dá)式或者是類型名。
? ? ? ??如果操作數(shù)不是類類型或者是沒有虛函數(shù)的類,則typeid操作符指出操作數(shù)的靜態(tài)類型;如果操作數(shù)是定義了至少一個(gè)虛函數(shù)的類類型,則在運(yùn)行時(shí)計(jì)算類型。即:只有當(dāng)typeid的操作數(shù)是帶虛函數(shù)的類類型的對(duì)象的時(shí)候,才返回動(dòng)態(tài)類型信息。
? ? ? ??講到運(yùn)行時(shí)識(shí)別,這就想到了虛函數(shù),虛函數(shù)的動(dòng)態(tài)調(diào)用時(shí)通過虛函數(shù)表vrbl來實(shí)現(xiàn)的,那么typeid是如何實(shí)現(xiàn)的呢?
? ? ? ??要想讓任何一個(gè)內(nèi)含虛函數(shù)的對(duì)象都有能力取得其專屬信息的能力,于是乎,可以同樣依靠虛函數(shù)表vrbl來實(shí)現(xiàn),將RTTI信息的地址放到虛函數(shù)表中第一個(gè)虛函數(shù)的前面,這個(gè)RTTI信息為Derive::`RTTI Complete Object Locator。示意圖如下:
? ? ? ??(2)dynamic cast操作符,將基類類型的指針或引用安全得轉(zhuǎn)換為派生類類型的指針或引用,基于RTTI數(shù)據(jù)信息,在執(zhí)行時(shí)先驗(yàn)證被請(qǐng)求的轉(zhuǎn)換是否有效,只有有效,操作符才能實(shí)際進(jìn)行轉(zhuǎn)換。
參考文章:
1.《如何在運(yùn)行時(shí)確定對(duì)象類型(RTTI)》
2.《淺議 Dynamic_cast 和 RTTI》
7、編程實(shí)現(xiàn)統(tǒng)計(jì)整形數(shù)組中各個(gè)數(shù)字出現(xiàn)的次數(shù)
? ? ? ??7.1 使用計(jì)數(shù)排序的方法,先找出這堆整形數(shù)組中的數(shù)字大小范圍,然后新建一個(gè)同等大小的數(shù)組來存放每個(gè)數(shù)字對(duì)應(yīng)的次數(shù),遍歷一遍原數(shù)組來統(tǒng)計(jì)次數(shù),遍歷一遍新數(shù)組來輸出統(tǒng)計(jì)。此方法適用于數(shù)字范圍小,但個(gè)數(shù)多的情況,不然空間復(fù)雜度和時(shí)間復(fù)雜度會(huì)過多消耗。實(shí)現(xiàn)過程如下:
[cpp] view plaincopy// 1.0 使用計(jì)數(shù)排序 void fun(int a[], int n) { int i; int max = -10000000; int min = 10000000; // 查找數(shù)列最大最小值 for (i=0; i<n-1; i=i+2) { if (a[i]>a[i+1]) { if (a[i]>max) max = a[i]; if (a[i+1]<min) min = a[i+1]; } else { if (a[i+1]>max) max = a[i+1]; if (a[i]<min) min = a[i]; } } if (i == n-1) { if (a[i]>max) max = a[i]; else if(a[i]<min) min = a[i]; } // 先計(jì)數(shù)后輸出 int lenb = max-min+1; int *b = new int[lenb]; memset(b, 0, lenb*sizeof(int)); for (i=0; i<n; i++) b[a[i]-min]++; for (i=0; i<lenb; i++) { if (b[i]!=0) cout<<i+min<<":"<<b[i]<<endl; } delete []b; }
? ? 7.2 使用STL中的map來進(jìn)行數(shù)據(jù)的存放和查找計(jì)數(shù),數(shù)字為鍵值,次數(shù)為對(duì)應(yīng)數(shù)據(jù),map利用樹結(jié)構(gòu)來動(dòng)態(tài)管理插入和查找,效率較高
[cpp] view plaincopy
// 2.0 利用map void fun2(int a[], int n) { map<int, int> b; for (int i=0; i<n; i++) b[a[i]]++; for (map<int,int>::iterator iter = b.begin(); iter!=b.end(); iter++) cout<<iter->first<<":"<<iter->second<<endl; }
? ? ? ??7.3?先將原數(shù)據(jù)進(jìn)行快排,然后遍歷一遍統(tǒng)計(jì)個(gè)數(shù),但若不備份會(huì)破壞原數(shù)據(jù)
[cpp] view plaincopy
int compare (const void * a, const void * b) { return ( *(int*)a - *(int*)b ); } void fun3(int a[], int n) { qsort(a, n, sizeof(int), compare); int temp = a[0]; int count = 1; for (int i=1; i<n; i++) { if (temp == a[i]) count ++; else { cout<<temp<<":"<<count<<endl; temp = a[i]; count = 1; } } cout<<temp<<":"<<count<<endl; }
總結(jié)
以上是生活随笔為你收集整理的2013腾讯实时面试记录的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 专业程序员必知必会技巧:驯服复杂代码
- 下一篇: MFC——ComBox用法大全