再寫一篇遊戲程式基礎知識介紹。
為什麼玩遊戲除了CPU以外還需要一個顯示晶片?大家常說的Direct3D和OpenGL是做什麼用的?本篇就來為大家解說。
前一篇「
【程式】遊戲程式基本架構」裡提到,遊戲程式是一個迴圈不斷執行「取得輸入、計算邏輯、繪製畫面」,其中「繪製畫面」的計算量特別大。
實際算算看有多少工作量
假設有個畫面大小1024×768,類似AVG的對話系統,每畫上一張圖要更新多少像素。
重疊時為了做到半透明效果,每個像素都要把RGBA分量分開,做這樣的計算。
Cr = ArAa + Sr(1-Aa)
Cg = AgAa + Sg(1-Aa)
Cb = AbAa + Sb(1-Aa)
有3D畫面的話,計算更加複雜。
要用3D幾何學計算頂點在畫面上的位置,假如整個場景有20000個頂點,就要計算20000次。
且每個像素要根據3D空間裡的位置計算亮度,做出光照的效果,如果畫面是1024×768,要算786432次。
很複雜吧,由此可看出繪製畫面的計算有多繁重
—GPU的發明—即使CPU日新月異,遊戲對畫面的要求也越來越高,只靠CPU無法負荷了。
於是……
有廠商發明新的硬體:顯卡少女……不,是圖形處理器,又稱為顯示晶片、Graphics Processing Unit、GPU。
除了CPU以外,把GPU和一塊專用的記憶體裝上去。
把繪圖要用的資料事先傳到顯示記憶體。
CPU可以做多樣的工作,而GPU做成專門做圖形相關計算,犧牲泛用性達到高速,加上GPU讀取顯示記憶體很迅速,如此就可以快速繪製畫面。
市面上賣的顯示卡,是將顯示晶片和輔助零件:記憶體、散熱器、輸入輸出介面、……整合在一塊電路板上,做成插到電腦上就可以使用的狀態。顯卡包裝上標示「NVIDIA GeForce GTX 960」或「AMD Radeon RX 460」之類的是其核心GPU,核心晶片是顯卡性能的關鍵,所以遊戲的系統需求標示都有顯示晶片這一項,玩遊戲時要注意遊戲可以在哪些晶片執行。
—獨立顯卡與集成顯卡—上圖有分離記憶體的是獨立顯卡,還有一種做法是CPU和GPU共用主記憶體,稱為集成顯卡(內顯)。
由於存取記憶體跟CPU佔用同一條通道,效能會比同時期的獨顯差,但比較節省成本和電力。
至於集成顯卡實際放在哪裡,以前是主機板上除了CPU以外還要配置一個晶片,稱為晶片組,例如筆者以前有一臺筆電是Intel 915GM晶片組,是Pentium M CPU + GMA 900 GPU。
現在大多跟CPU做在同一塊晶片裡,不用額外的晶片了,如Intel HD Graphics、AMD APU、多數電玩主機、以及智慧型手機。
(手機對省電和省空間很要求,必須使用內顯)
(電玩主機把整臺機器都用來玩遊戲,不像PC要同時做很多工作,能用比PC低的配備跑相同的程式;而且製造成本要低,否則我們無法用10000元以內買到一臺主機,所以也使用內顯)
獨顯和內顯的定義是「是否有專用的顯示記憶體」,獨顯不一定真的有一張獨立的「卡」,筆電的獨顯通常也銲在主機板上。
—何謂Direct3D與OpenGL?—寫程式時,下指令給顯卡少女叫她們工作的方法,不外乎呼叫函式填入參數。
生產GPU的廠商很多,PC有N牌、A牌、I牌,智慧型手機還有ARM、PowerVR等等更加多樣,假如每家廠商各自開規格呢?
例如把貼圖從主記憶體傳到顯示記憶體:
通用規格在科技業裡一向很重要,於是各大廠商因應需求討論,制定出通用規格。Direct3D與OpenGL就是用來控制GPU的通用規格,即電子妖精和顯卡少女溝通的語言。
有了通用規格以後,晶片廠商生產顯示晶片,以及程式人員寫程式就方便多了。
不管對方是哪家廠商做的,只要呼叫glTexImage2D(),顯卡少女就知道是要傳送貼圖資料。
(詳細來講,各家晶片內部的電路畢竟還是不一樣,底層指令也不同,所以使用者還要安裝廠商提供的驅動程式(driver),呼叫glTexImage2D()時,驅動程式會產生晶片固有的指令給晶片執行)
(早期還有其他規格存在,如顯卡還沒有3D計算能力時的DirectDraw、曾與OpenGL競爭的Glide,現在已不再使用)
眾所周知,Direct3D是微軟開發的,只能在微軟的作業系統使用(Windows Desktop、Windows App、XBox系列),OpenGL與後述旳OpenGL ES則沒有限制哪個作業系統能使用它,所以其他作業系統大多用OpenGL。
遊戲機可能有自己的API,但現今各家主機GPU能做的事很相似,各家API大多能找到對應的功能。
—何謂shader?—或許有人聽過shader這個詞,這又是什麼東西?
一開始控制GPU像是選擇題和填充題,只能在預先設計好的表格裡填參數。這稱為fixed-function pipeline,可翻譯為「固定流程管線」。
(為了便於說明,上面列的設定值比起實際有省略)
隨著3D軟體對畫面的需求增加,GPU必須加入越來越多功能,設定值也愈趨複雜,不斷地增加選項會讓API混亂難以使用。
於是有了另一個發明:shader,兩大陣營分別在D3D 8.0和OpenGL 2.0加入這個功能。
這是讓一部分步驟可以用程式語言寫指令,再把指令給GPU執行,變成像問答題和作文了,靈活度比以往高了很多。這稱為programmable pipeline,可翻譯為「可程式管線」。
有的文章把shader翻譯成著色器,這名稱其實不準確,它的功用不只著色,凡是寫給GPU執行的程式都稱為shader。但中文好像也想不到比較名副其實的名稱,所以平常都用英文shader稱呼。
以下先知道有這些東西存在就好了,詳細可以等真正開始寫shader再學:
最早出現的是vertex shader和pixel shader,把3D繪圖其中兩個步驟變成能寫程式控制,後來又增加了geometry、tessellation和compute三種。
至於寫shader用的程式語言,Direct3D制定的語言稱為HLSL,OpenGL的是GLSL,寫法跟給CPU執行的程式語言(C、C#、Python等)很不一樣。
有些繪圖引擎有自訂的shader語言,像Unity的就是Cg (一個由NVIDIA開發的語言) 加一些客製化而來,引擎內部會把它轉換成D3D和OpenGL看得懂的型式。
—Direct3D與OpenGL的世代演進—隨著科技演進GPU的功能越來越多,Direct3D與OpenGL也配合新功能推出新版本,常有新功能可以做到≧舊功能,舊功能就不需要的情況。例如有了shader之後打光計算改由shader控制,OpenGL裡glLightfv()、glMaterialfv()之類設定打光的函式就不需要了。
但科技業另一個令人頭痛的問題是向後相容,有些舊程式已經找不到作者或公司改寫成新規格了,但還是有需要使用,要讓這些程式在新硬體也能執行,所以也不能把舊的函式直接移除。
假如把從古到今的功能完全保留在規格書中,這樣規格書裡有一大半是「不建議使用 (deprecated)」、「有替代方法」的,有好幾種方法不知道要用哪一個,會讓人混亂。
因應這個需求,D3D和OpenGL分別做了兩次廢除舊規格的改版:
Direct3D在第10版做了破釜沈舟的改版,使用方法跟D3D9以前完全不一樣,且廢除固定流程管線,使用它一定要學習HLSL,所以D3D10剛出來的時候有很多人說用不慣新的東西。
現在的Windows裡同時裝有D3D10和D3D9的DLL,程式初始化時可以選擇要用哪一個,D3D10是只用新功能,D3D9是可以相容舊功能。
之後的D3D11跟D3D10大同小異。
OpenGL則在3.2版引入了core profile和compatibility profile兩個模式,程式初始化時可以選擇要用哪一個。core是只用新功能,一樣是廢除固定流程管線,必須使用GLSL,用compatibility則是相容舊功能。
OpenGL有個為了手持裝置特製的版本OpenGL ES,也大致是刪除一些可廢除的舊功能,讓規格簡化。
(以前想用用看OpenGL 3.3,花了點時間研究才知道必須建立core profile才能使用,初始化的方法跟以往不同:
【程式】新開發機的相容性問題(上))
第二次是Direct3D 12,把10的規格又大改了一次。OpenGL團隊則是開發一個新標準:Vulkan。由於筆者手上有些開發機不支援新標準,目前沒打算使用,對這兩者不是很熟。
學習已經沒有人在用的東西用處不大,不如把時間拿去學習有用的東西,所以假如以後我要寫D3D和OpenGL教學,會從D3D11和OpenGL 3.3教起,不會再用舊版。
—DirectX—順便提一下DirectX,講到遊戲程式通常都會提到它,這是Windows內建的多媒體函式庫,包含很多部分。
除了用來控制GPU的Direct3D,簡介一下筆者知道的部分。
個人認為目前有使用價值的:
Direct2D |
跟Direct3D名稱很像,但並不是用來控制GPU,而是用CPU做2D繪圖,前身是GDI和GDI+。 |
DirectWrite |
繪製點陣或向量字型,必須跟Direct2D同時使用。 |
XAudio2 |
用來播放聲音,可以模擬3D場景中,聲音在不同位置發出的效果。 |
DirectSound |
用來播放聲音。照理說可以用XAudio2取代,但Windows 7並沒有內建XAudio2,必須另外裝個runtine才能用,所以我的自製遊戲還是用DirectSound。 |
DirectCompute |
利用GPU的高速運算能力,做圖形以外的數值計算。算是Direct3D的一部分,使用方法是先建立一個D3D device物件,然後寫shader給GPU執行。 |
個人認為不需要用,或已經被其他東西取代的:
DirectDraw |
顯示晶片還沒有3D加速的時代,用來控制顯示晶片的,被Direct3D取代。 |
DirectInput |
讀取鍵盤、滑鼠、手把輸入。Windows API可做到相同的事。 |
XInput |
用在Xbox 360手把或其他廠商做的相容手把(在3C賣場可以看到不少)。應該是為了方便遊戲作者把遊戲從Xbox 360移植到PC上而做的。 |
DirectPlay |
用在網路通訊。用socket也可以做到網路連線。 |
DirectShow |
聲音或影片解碼。被Media Foundation取代。 |
這次有事耽擱,隔了久一點才發新東西。
雜談:現在有D3D和OpenGL這樣的通用規格,不論PC、遊戲機、手機,控制顯示晶片的方法很一致。查了一些早期遊戲機的資料,即使還沒有3D的時代也有個輔助晶片處理繪圖,那個時代不同主機的CPU和GPU規格差很多,要移植遊戲到不同平臺應該很辛苦吧。
也看過一個Sega Saturn模擬器作者說SS的系統跟PC差很多,有很多獨自功能在現在的D3D、OpenGL無法重現出來,因此SS模擬器很難以開發。
關於插圖:
這幾位是同人場上另一個作品《顯卡少女》的角色,本篇跟顯示卡有關係便讓她們客串一下,從目前有的7個角色裡挑幾個來用。(有跟作者知會過會拿他的角色來用)
作者:哭哭喵的小屋《顯卡少女》介紹不過他目前設計的角色都是同一世代的晶片,沒有設計同一家廠商的新舊版,也沒有內顯和智慧型手機晶片的角色,所以插圖有一部分不符合實際情況。
左邊那位「前一個版本」是我自己想的,試著把原來的角色減少一些裝飾。