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