顯示具有 OPENGL 標籤的文章。 顯示所有文章
顯示具有 OPENGL 標籤的文章。 顯示所有文章

2013年6月26日 星期三

Mobile GPU大廠

 
目前移动市场的GPU主要有四大厂商系列:

1)Imagination Technologies的PowerVR SGX系列

    
代表型号:PowerVR SGX 535、PowerVR SGX 540、PowerVR SGX 543MP、PowerVR SGX 554MP等
代表作  :Apple iPhone全系
、iPad全系,三星I9000、P3100等

2)Qualcomm(高通)的Adreno系列

    
代表型号:Adreno 200、Adreno 205、Adreno 220、Adreno 320等
代表作  :HTC G10、G14,小米1、2等

3)ARM的Mali系列

    
代表型号:Mali-400、Mali-T604等
代表作  :三星Galaxy SII、Galaxy SIII、Galaxy Note1、Galaxy Note2(亚版)等

4)nVIDIA(英伟达)的Tegra系列

    
代表型号:nVIDIA Tegra2、nVIDIA Tegra3等
代表作  :Google Nexus 7,HTC One X等



5)性能出众的“小众”产品——Vivante的GCxx
与PowerVR、Mali、Adreno等明星相比,Vivante公司的GC系列GPU核心就不太为人熟知了,就连市场份额比它少的Tegra系列都 比Vivante知名。去年让Vivante露一大脸的是华为旗下的海思K3V2,这颗号称“世界最快四核”的移动处理器在华为去年的Ascend D1四核、荣耀2四核以及今年初的Ascend D2、6.1寸超大屏的Mate上全面应用,其16核GPU实际上就源于Vivante的GC系列GPU。
.
华为的K3V2处理器使用的就是Vivante的GC4000核心
Vivante其实还是挺有资本的,创立于2004年,创始人好像还是个华裔,他们专注于移动GPU市场,2010年的时候就有超过40家授权单位,主要 客户有Marvell、飞思卡尔等,很多人不知道的是国内的瑞芯微电子的RK2918以及自主知识产权的国产明星“龙芯-2H”使用的也是Vivante 的GPU核心。 Vivante给人的感觉就是“小众”,好听点的说法是“Vivante虽然小众,但是性能出众”,难听点的说法是“Vivante的GPU性能出众,但 是市场小众”。只不过从市场统计上看,Vivante的GC系列在移动GPU的份额上仅次于PowerVR、Adreno以及Mali之后,2012年上 半年的全球份额是9.8%,比Tegra的2.5%份额要高得多。 说起来Tegra才是小众,他们是大众产品呢,只不过Vivante在消费级的智能手机和平板领域确实露面太少,给人的印象是“小众”。
主力产品:GC400、GC800、GC4000




大部份資料都在參考網站中,懶得轉貼了。

參考網站
http://m.mydrivers.com/newsview.aspx?id=266555&cid=1&p=4

http://m.mydrivers.com/newsview.aspx?id=266555&cid=1&p=5

http://m.mydrivers.com/newsview.aspx?id=266555&cid=1&p=6

http://m.mydrivers.com/newsview.aspx?id=266555&cid=1&p=7

http://m.mydrivers.com/newsview.aspx?id=266555&cid=1&p=8

http://www.cnblogs.com/luming1979/archive/2013/02/04/2891421.html

 

OpenGL基本瞭解(二十)(Texture compression)




貼圖是在 3D 場景中,增加真實性的一個重要的工具。就像一般的影像一樣,貼圖的大小愈大,它的圖像就愈精細。事實上,貼圖往往需要比一般的影像更大。因為,在 3D 場景中,觀察者可能會很靠近貼圖,使得貼圖需要放大很多倍,而造成模糊的現象。所以,一般來說,如果可能的話,貼圖愈大就愈好。

不過,貼圖是非常佔用記憶體空間的。現在的貼圖都是以不壓縮的形式存放在顯示記憶體中,而目前常用的貼圖格式是 16 bits、24 bits 和 32 bits。下表列出一些貼圖大小所佔用的空間:

貼圖大小16 bits16 bits mipmap24 bits24 bits mipmap32 bits32 bits mipmap
64x648 KB10.6 KB12 KB16 KB16 KB21 KB
256x256128 KB170 KB192 KB256 KB256 KB340 KB
1024x10242 MB2.6 MB3 MB4 MB4 MB5.3 MB



常用的圖像文件格式有BMP,TGA,JPG,GIF,PNG等;
不過象JPG這種常見圖像壓縮格式對於多數應用的內存佔用和顯示總線帶寬佔用並沒有直接的好處,因為還得解壓縮成原始像素再傳給顯卡,而且還有加載時的解碼計算負擔。這是因為顯卡的紋理解碼硬件不理解JPG格式。所以,在沒有顯卡硬件支持的情況下,用壓縮格式保存紋理沒什麼意義,特別是對於手持移動設備來說,解碼象JPG這種複雜格式是很浪費電的。考慮到現代遊戲對紋理圖片的嚴重依賴,及相應的對視頻總線的巨大壓力,硬件實時解壓縮獲得了廣泛的支持,不過這個還沒有一種格式獲得多個廠家的支持。在OpenGL ES裡已經為此定義了一個標準接口glCompressedTexImage2D(..., format, ..., data),不過紋理數據的格式則沒有標準,要參考廠商的SDK或文檔獲得format值。這也就意味著,使用了壓縮紋理之後就不能跨平台了。



常用的紋理格式有R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等。
   
文件格式是圖像為了存儲信息而使用的對信息的特殊編碼方式,它存儲在磁盤中,或者內存中,但是並不能被GPU所識別,因為以向量計算見長的GPU對於這些複雜的計算無能為力。這些文件格式當被遊戲讀入後,還是需要經過CPU解壓成R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等像素格式,再傳送到GPU端進行使用。
    
 

紋理格式是能被GPU所識別的像素格式,能被快速尋址並採樣。舉個例子,DDS文件是遊戲開發中常用的文件格式,它內部可以包含A4R4G4B4的紋理格式,也可以包含A8R8G8B8的紋理格式,甚至可以包含DXT1的紋理格式。在這裡DDS文件有點容器的意味。
    
 

OpenGL ES 2.0支持以上提到的R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,A8R8G8B8等紋理格式,其中 R5G6B5,A4R4G4B4,A1R5G5B5每個像素佔用2個字節(BYTE),R8G8B8每個像素佔用3個字節,A8R8G8B8每個像素佔用4個字節。

RGB565 ....這類的顏色資料,可參考http://en.wikipedia.org/wiki/High_color

   
對於一張512*512的紋理的話,R5G6B5格式的文件需要佔用512KB的容量,A8R8G8B8格式的文件需要佔用1MB的容量;如果是1024*1024的紋理,則各需要2M和4M的容量,這對於動輒需要幾十、幾百張甚至更多紋理的遊戲,上G容量的遊戲在移動平台上是不容易被接受的(當然,還是有1、2G的大作的,裡麵包含了幾千張的紋理) 。
現在一般的顯示卡上通常裝有 32MB 的顯示記憶體。如果每個貼圖都要 2MB 的話,即使不計 frame buffer 所佔用的空間,也只能使用 16 張貼圖。這顯然是不可接受的。所以,現在的遊戲通常無法使用很大的貼圖。

然而,在儲存一般的影像的時候,通常會使用某些壓縮方式。現在常見的 JPEG 壓縮,可以達到 1:6 甚至 1:12 的壓縮比。如果把類似的壓縮方式應用在貼圖上,不就可以大量減少貼圖所用的空間了嗎?

不幸的是,一般的影像壓縮方式,是沒有辦法用在貼圖上面的。因為,顯示晶片在存取貼圖時,是一種「隨機存取」的動作。也就是說,顯示晶片通常會需要以任意 的順序存取貼圖裡的資料。一般的壓縮方式如 JPEG,都利用了 variable length 的 coding,簡單的說,它們必需以一定的順序才能解開。因此,不能用這種方式來壓縮貼圖。

一種壓縮方式,是改變顏色空間。例如,3dfx 的 YAB 格式,就是一種不同的顏色空間。利用 YAB,每個像點只需要 8 bits,就可以達到接近 16 bits 的效果。不過,無論如何,這樣都使顏色的數目減少。因此,整個貼圖的色彩變化就受到了限制。

另一種方式,就是用傳統的「調色盤」結構。利用一個 256 種顏色的調色盤,就可以把貼圖以 8 bits 的方式儲存。不過,雖然它的色彩空間較大(可以是 24 bits 或 32 bits),但是總顏色數目還是不能超過 256 種。所以,它的應用範圍仍然有限。

現在常用的貼圖壓縮方式,則是利用以區塊為基礎的方式。通常的做法是,把貼圖切割成許多小區塊,再對各個區塊進行壓縮。例如,S3TC 就是把貼圖切成 4x4 的小區塊。利用這種做法,就可以對區塊進行某種處理(通常就是 vector quantization 或是其變形),顯示晶片也可以區塊為單位,進行隨機的存取動作。因此,這是適合用在貼圖的方式。

不過,區塊的大小會影響到壓縮的效果。一般來說,區塊愈大,就能有愈高的壓縮比。不過,愈大的區塊也會使額外的負擔增加。因為顯示晶片只能以區塊為單位來讀取貼圖資料,如果區塊愈大,則每個區塊中就可能會有愈多的資料是不需要的。所以,也不能任意把區塊的大小加大。


在Beers,Agrawala和Chaddha於1996發表的一篇影響深遠的論文基於已壓縮紋理的渲染 [1]中,他們列舉四項紋理壓縮的特點,使其不同於其他圖像壓縮技術。
  • 解壓速度:由於最好能直接從已壓縮的紋理直接渲染,為了儘可能地不影響性能,解壓縮要儘可能快。
  • 隨機訪問:由於幾乎不可能預測紋素被訪問的順序,任何紋理壓縮演算法必須允許對其中紋素的隨機訪問。所以幾乎所有的紋理壓縮演算法都以塊為單位壓縮和存儲紋素,當某一紋素被訪問時,只有同一塊中若干紋素被讀取和解壓縮。這項需求也排除了很多壓縮率較高的圖像壓縮方式,例如JPEG和行程長度編碼。
  • 壓縮率和圖像質量:由於人眼的不精確性,相比於其他應用領域,圖像渲染更適宜使用有損數據壓縮。
  • 編碼速度:紋理壓縮對壓縮速度要求不高,因為絕大多數情況下,紋理只需要進行一次壓縮。
由於其數據訪問模式是事先知道的,紋理壓縮常作為整個繪圖管線的一部分,在繪製時對動態地已壓縮數據進行解壓縮。而反過來繪製管線也可以通過紋理壓縮技術來降低對於頻寬和存儲的需求。在紋理貼圖中,已壓縮紋理和沒有經過壓縮的紋理使用起來基本沒有區別,都可以被用來存儲顏色數據或其他數據,例如凹凸貼圖或法線貼圖,也都可以和Mipmapping或各向異性過濾等共同使用。


主流紋理壓縮標準:ETC、PVRTC、S3TC首先說OpenGL ES標準中的,2.0版規範中將ETC(Ericsson Texture Compression)作為基本的紋理壓縮標準,這是大部分移動GPU都會支持的紋理標準。 OpenGL ES 3.0中還引入了ETC2、EAC紋理壓縮格式,二者基本一致,只不過EAC主要用於1-2通道數據的情況。目前ECT2還在改進中,除了高通的Adreno 320之外還沒有移動GPU支持,Tgera 4也不行。

此外,OpenGL ES 3.0中還有一種可選紋理壓縮格式——ASTC(Adaptive Scalable Texture Compression,自適應擴展紋理壓縮),這是ARM提出的,去年被Khronos組織認可,納入到標準中來,不過並不是強制性的,目前也只有Mali-T600系列支持。Imagination旗下的PowerVR GPU支持的是PVRTC(PowerVR texture compression)和ETC,高通的Adreno 2xx系列支持ETC之外還有3Dc和ATITC。後兩者都是原來的ATI開發的,Adreno 320除了前面三種標準之外還支持ETC2紋理壓縮。ARM的Mali-300/400系列支持ETC,Mali-T600還多了ASTC紋理支持。NVIDIA的Tegra系列更有趣。之前的說法稱Tegra支持自己的紋理格式,實際上除了通用的ETC之外,Tegra支持的紋理叫做S3TC(S3 Texture Compression),也被稱為DXT​​n或者DXTC。 S3TC是S3公司在1999年引入的,後來被DX 6.0和OpenGL 1.3吸收為官方標準,DXTC相當於Windows版的名字,S3TC是OpenGL中的名字。說到S3TC,之前蘋果和HTC大打專利戰的時候就涉及到了這個標準。 S3已經歸為VIA威盛旗下,HTC和威盛又有同一個老闆——王雪紅。為了支援HTC打專利戰,威盛去年就把S3部門出售給了HTC,算是左手倒右手吧。S3TC是DX顯卡都支持的標準,NVIDIA也在Tegra中支持了這個標準,S3TC根據不同算法又分為DXT1-DXT5這五個級別,Terga支持的實際上是DXT1、DXT3和DXT5。Vivante的GC系列也支持ETC和S3TC,跟NVIDIA的Tegra路線相同。以前都說Vivante支持的是NVIDIA Tegra的紋理數據,實際上二者是選擇了共同的路線而已,DXT也不是NVIDIA的專利。


基於OpenGL ES的壓縮紋理有常見的如下幾種實現:1. ETC1(Ericcson texture compression)  //共同支援度最高2. PVRTC(PowerVR texture compression)3. ATITC(ATI texture compression)對於使用NVIDIA Tegra2芯片的手機如Motorola XOOM,ATRIX和DRIOID BIONIC則支持如下的紋理壓縮4. S3TC(S3 texture compression)


ETC是最通用的紋理壓縮格式,不過ETC並不招廠商待見,因為ETC紋理壓縮不支持Alpha通道,只能用於壓縮不透明的材質,不過ETC也有自己的優點,幾乎所有的安卓設備都可以支持ETC壓縮的GPU加速。S3TC無論壓縮速度還是壓縮比都不錯,也支持GPU加速,而且是桌面顯卡通用的壓縮格式,看起來是最完美的選擇,可惜的是移動市場跟PC不一樣,大家各自為王,NVIDIA現在還沒強大到讓其他GPU廠商低頭採用S3TC標準的程度,因為S3TC說到底還是一種私有的標準,有專利上的麻煩。ETC2壓縮標準補全了ETC1不支持Alpha通道的缺陷,支持更高質量的RGBA(RGB+Alpha)壓縮,而ARM提出的ASTC標准在壓縮速度和質量上比S3TC要好,但是這兩種壓縮格式都是新出的,支持的廠商實在太少了。
 

 
ETC1:
ETC1格式是OpenGL ES圖形標準的一部分,並且被所有的Andr​​oid設備所支持。擴展名為: GL_OES_compressed_ETC1_RGB8_texture,不支持透明通道,所以僅能用於不透明紋理。當加載壓縮紋理時,<internal format>參數支持如下格式:
    
GL_ETC1_RGB8_OES(RGB,每個像素0.5個字節)



PVRTC:
被 用在Motorola的一些机器上,比如DROID系列。GPU为Imagination Technologies的PowerVR SGX 530。OpenGL ES的扩展名为: GL_IMG_texture_compression_pvrtc,支持预处理压缩。当加载压缩纹理时,<internal format>参数支持如下几种格式:
COMPRESSED_RGB_PVRTC_4BPPV1_IMG (RGB 4 bit per pixel)
COMPRESSED_RGB_PVRTC_2BPPV1_IMG (RGB 2 bit per pixel)
COMPRESSED_RGBA_PVRTC_4BPPV1_IMG (RGB 4 bit per pixel with alpha channel)
COMPRESSED_RGBA_PVRTC_2BPPV1_IMG (RGB 2 bit per pixel with alpha channel)

ATITC:
当前使用该种纹理压缩的机器有Nexus One。支持的OpenGL ES扩展名为: GL_ATI_texture_compression_atitc。当加载压缩纹理时,<internal format>参数支持如下类型的纹理:
ATC_RGB_AMD (RGB textures)
ATC_RGBA_EXPLICIT_ALPHA_AMD (RGB textures using explicit alpha encoding)
ATC_RGBA_INTERPOLATED_ALPHA_AMD (RGBA textures using interpolated alpha encoding)

S3TC
也 被称为DXTC,在PC上广泛被使用,但是在移动设备上还是属于新鲜事物。在使用NVIDA芯片的手机上被使用。OpenGL ES扩展名为: GL_EXT_texture_compression_dxt1和GL_EXT_texture_compression_s3tc。当加载压缩纹理 时,<internal format>的参数有如下几种格式:
GL_COMPRESSED_RGB_S3TC_DXT1 (RGB data is compressed, alpha is always 1.0)
GL_COMPRESSED_RGBA_S3TC_DXT1 (RGB data is compressed, alpha is either 1.0 or 0.0)
GL_COMPRESSED_RGBA_S3TC_DXT3 (RGB data is compressed, alpha is stored as 4 bits)
GL_COMPRESSED_RGBA_S3TC_DXT5 (RGB data is compressed, alpha is a weighted average of 8-bit values)

在程序在开始检测这些可用的扩展很重要。对于ETC1压缩来说,使用ETC1Util.isETC1Supported()即可。可以使用android.openGL.getString(GL10.GL_EXTENSIONS)解析字符串获取更多的可用扩展。
 



以下是其它較常見的壓縮模式的細節介紹



VQTC (Vector Quantization Texture Compression)


首先,我們會介紹一種簡單的貼圖壓縮方式:VQTC。

VQTC 是由 NEC/Videologic 的 PowerVR 系列所使用的一種貼圖壓縮方式,但是因為 PowerVR 系列一直沒有得到很大的成功,所以 VQTC 一直未受到重視。而現在 Videologic 最新的 Kyro 顯示晶片也不再支援 VQTC。不過,因為 VQTC 相當簡單,所以還是簡單做個介紹。

VQTC 是使用 vector quantization 的方式,所以叫 VQTC。它的原理是:把貼圖切成許多相同大小的區塊(例如 2x2 或 4x4),對這些區塊做 vector quantization。例如,可以從這些區塊中,找出 4096 個最具代表性的區塊。這樣一來,每個區塊就只需要存放 index,也就是 12 bits 的空間。

顯示晶片在讀取貼圖資料時,要先將整個向量(即 4096 個區塊)讀入顯示晶片中的一個向量表。這個動作對每個貼圖只需要做一次。在讀取各個 texel 時,則是先判斷出所需的 texel 所在的區塊(以 2x2 的區塊來說,就是把位置座標分別除以二),讀取 index,再從向量表中查出區塊的內容。基本上,這些動作都非常簡單
。

在壓縮比方面,以上面的例子來說,如果使用 256x256 32bpp 的貼圖,並使用 2x2 的區塊,那麼貼圖就有 128x128 = 16384 個區塊。找出 4096 個最具代表性的區塊後,整個貼圖需要的空間就是 4096 個區塊再加上 16384 個 index 的空間,即 4096x16 + 16384x1.5 = 88 KB。和原來未壓縮所需要的 256KB 相比,它的壓縮比約為 1:2.9。

如果是更大的貼圖,則可以使用更大的區塊(例如 4x4),不過,這樣會使品質變差。但是,經由選擇不同的區塊大小,和區塊的數目,就可以調整出品質和壓縮比的平衡點。這是 VQTC 的優點之一。

不過,VQTC 並非沒有缺點的。事實上,VQTC 最大的缺點,就是「不能做部分更新」 。簡單的說,如果想要更新一個 VQTC 貼圖中的一小部分,幾乎可以說是不可能的,除非將貼圖重新壓縮,或是犧牲一些品質,使用原有的向量來壓縮。當然,對大部分的情形來說,這並不是個嚴重的問題;因為需要做部分更新的情形,通常是相當少見的。

另外,VQTC 也不太適合處理有「透明度」(即 alpha channel)的貼圖。一般來說,如果貼圖中有 alpha channel,會對 VQTC 的品質造成影響。

VQTC 現在已經不常用了(也許只在 Dreamcast 遊戲機中還被使用)。目前最流行的貼圖壓縮,則是由 S3 所開發的 S3TC。我們會在下一篇文章中介紹這個方法。



S3TC (S3 graphics Texture Compression)



這篇文章將會簡單介紹有名的 S3TC 貼圖壓縮方式。

S3TC 是由 S3 公司所發展出來的,最早用在它的 Savage 系列顯示晶片中。雖然 Savage 顯示晶片並不算成功,但是 S3TC 卻因為微軟公司將其加入 DirectX 而變得相當成功。微軟向 S3 授權 S3TC 技術後,其它公司若在 DirectX 中支援 S3TC(在 DirectX 中稱為 DXTC),則不需另外再付給 S3 費用,因此得到了相當程度的支援。

S3TC 包括五種貼圖壓縮格式,在 DirectX 中,分別稱為 DXT1 ~ DXT5。這些不同的貼圖壓縮格式,其實就是為了透明度(即 alpha channel)所設計的。

DXT1 是 S3TC 中,最基本的壓縮格式。它是用來處理「沒有 alpha channel」或是「alpha channel 為 1 bit」的貼圖。其它的壓縮方式都是只是 DXT1 的變化而已。

DXT1 所用的方法,和 VQTC 類似,也是將貼圖切成許多小區塊,然後再利用 vector quantization 的方式來壓縮。不過,和 VQTC 不同的是,DXT1 的區塊總是 4x4 的大小,而且它將 vector quantization 用在區塊內,而不是像 VQTC 對所有的區塊做 vector quantization。

對每個 4x4 的區塊,儲存了兩個 16 bits 的顏色,顏色的格式是 5-6-5 的 RGB。從這兩個顏色,可以用線性內插的方式,得到另外兩個顏色。簡單的說,如果這兩個顏色分別是 RGB0 和 RGB1,那 RGB2 和 RGB3 可以由下面的式子求出:

RGB2 = (2 * RGB0 + 1 * RGB3) / 3
RGB3 = (1 * RGB0 + 2 * RGB3) / 2


這樣就得到了四個顏色。區塊中的每個 texel 則是以一個 2 bits 的 index 表示。如果 index = 0,則表示這個 texel 的顏色是 RGB0;index = 1 則是 RGB1;index = 2 則是 RGB2;index = 3 則是 RGB3。以這樣的方式儲存,每個區塊只需要 16x2 + 2x4x4 = 64 bits。因此,在壓縮 16 bits 的貼圖時,壓縮比是 1:4。

DXT1 同時也可以處理「具有 1 bit alpha channel」的貼圖。一般來說,在貼圖中使用 1 bit 的 alpha channel,就是用來註明「透明」的地方。因此,DXT1 的處理方式,是犧牲一個顏色,用它的表示「透明」的 texel。

如果一個區塊需要存放透明色的話,那麼,顏色的產生方式,就變成:

RGB2 = (RGB0 + RGB1) / 2

和前面一樣,texel 的 index 仍是 2 bits。index = 0 ~ 2 時,分別是表示 RGB0 ~ RGB2。當 index = 3 時,就表示這個 texel 是「透明」的,它的顏色是黑色,且 alpha = 0。

不過,要怎麼區分「有 alpha」和「沒有 alpha」的情形呢?DXT1 使用了一個簡單的方法:如果 RGB0 比 RGB1 要大的話,那就表示區塊是沒有 alpha 的。相反的,就表示有 alpha channel 了。

當 alpha channel 不只是 1 bit 時,就需要其它的方式了。DXT2 ~ DXT5 就是在處理這種情形。因為它的原理和 DXT1 是相同的,所以就不再多介紹了。不過,DXT2 ~ DXT5 每個 4x4 區塊需要 128 bits,也就是說,它們的壓縮比只有 DXT1 的一半。

因為 S3TC 是針對每個 4x4 的區塊做壓縮,所以可以對貼圖做「部分更新」的動作。要更新貼圖中的某些部分,只要需更新這些部分的區塊即可,其它的區塊則完全不會被影響。所以,「部分更新」是很容易做到的。

在下一篇文章中,會簡單介紹 3dfx 的 FXT1 貼圖壓縮



FXT1 (3dfx Texture Compression )



在這篇文章中,會簡單介紹 3dfx 的 FXT1 貼圖壓縮技術。

基本上,FXT1 和 S3TC 是非常類似的。不過,FXT1 使用 8x4 的區塊,而非 S3TC 的 4x4 區塊。而且,相對於 S3TC 只有一種壓縮方式(即 DXT1,DXT2 ~ DXT5 只是將 DXT1 加上 alpha channel 而已),FXT1 有四種不同的方式。這使得在壓縮的時候,可以針對不同的情形,使用最適當的壓縮方式。

FXT1 有四種壓縮方式,都是使用 8x4 的區塊。第一種方式稱為 CC_HI,用來壓縮使用 1 bit alpha channel 來表示「透明 texel」的貼圖。

CC_HI 和 DXT1 非常類似,它也是存放兩個顏色。不過,和 DXT1 不同的是,CC_HI 用的是 15 bits 5-5-5 RGB 的格式,而不是 16 bits 5-6-5 RGB 的格式。

利用線性內插的方式(類似 DXT1 的方式),CC_HI 的兩個顏色會內插出五個顏色,合起來是七個顏色,再加上一個顏色表示「透明 texel」。每個 texel 則使用 3 bits 的 index 來指向這八個顏色
。另外,CC_HI 使用 2 bits 的 mode bits 來表示這個區塊是 CC_HI 格式。所以,一個 8x4 的區塊需要 2 + 2x15 + 32x3 = 128 bits。因此,如果貼圖是 16 bits 的話,壓縮比就是 1:4。

第二種方式稱為 CC_CHROMA,它是專門用來存放沒有 alpha channle 的貼圖。 基本上,CC_CHROMA 的方式很簡單:它存放四個 15 bits 的顏色,每個 texel 則用一個 2 bits 的 index 指向這四個顏色。它的 mode bits 是 3 bits,還有一個未使用的 bit,所以它需要的空間是 3 + 1 + 4x15 + 32x2 = 128 bits。

第三種方式稱為 CC_MIXED,這個模式非常的複雜。它將 8x4 的區塊分成兩個 4x4 的小區塊,每個小區塊有兩個 16 bits 5-6-5 RGB 的顏色。每個小區塊中的壓縮方式則和 DXT1 幾乎是相同的,但是它不是用顏色的大小來區分「是否有 alpha channel」,而是用一個 alpha bit 來區分。這個模式需要的空間也是 128 bits。

第四種方式則是 CC_ALPHA,是用來處理具有多位元 alpha channel 的模式(類似 DXT2 ~ DXT5)。它使用三個 20 bits 5-5-5-5 ARGB 格式的顏色,並有兩種模式:第一種模式,每個 texel 的 index(2 bits)指向這三個顏色,而第四個顏色則是表示「透明 texel」。第二種模式,則是將區塊分成兩個小區塊,並使用類似 DXT1 的方式(第一個小區塊用 COLOR0 和 COLOR1 為基礎色,而第二個小區塊則用 COLOR1 和 COLOR2 為基礎色),只不過有加上 alpha channel。這個格式的 mode bit 是 3 bits,再加上一個「模式 bit」,所以需要的空間是 3 + 1 + 20x3 + 32x2 = 128 bits。

基本上,FXT1 的壓縮比和 S3TC 並沒有很大的差別,但是一般來說,效果(特別是壓縮 24 bits 或 32 bits 的貼圖)則比 S3TC 要好一些。不過,它的區塊較大,也會使顯示晶片在處理時的效率較差。

FXT1 和 S3TC 都有相對應的 OpenGL extension 來提供支援。所以,如果想要取得更詳細的資料,可以到 OpenGL® Extension Registry 網站取得。S3TC 的 extension 稱為 GL_EXT_texture_compression_s3tc,而 FXT1 的 extension 則稱為 GL_3DFX_texture_compression_FXT1。在 extension 的文件中,有詳細的格式說明。

 



压缩纹理工具的使用
   每种压缩纹理以及相应的厂商都提供了压缩纹理的工具,工具都分两个版本:
   a. 可视化转换工具 (给美工或小白少量使用)
   b. 命令行转换工具 (给程序批量使用)

下面对每个工具的用法进行说明。
1)Imagination Technologies PowerVR
工具下载地址
http://www.imgtec.com/powervr/insider/sdkdownloads/index.asp?installer=Windows%20Installer

可视化转换界面

    
命令行转换脚本
for %%i in (*.tga) do PVRTexTool.exe -f PVRTC4 -i %%i
(将本目录下的所有tga文件,转换成"PVRTC4"编码格式的pvr文件,不带mipmap)
详细使用说明:PvrTexTool.exe /?

2)Qualcomm Adreno
工具下载地址
https://developer.qualcomm.com/mobile-development/mobile-technologies/gaming-graphics-optimization-adreno/tools-and-resources

可视化转换界面

   
命令行转换脚本
for %%i in (*.tga) do QCompressCmd.exe %%i %%i.ktx "ATC RGBA Explicit" yes
(将本目录下的所有tga文件,转换成"ATC RGBA Explicit"编码格式的ktx文件,带mipmap)
详细使用说明:QCompressCmd.exe /?

3)ARM Mali
工具下载地址
http://malideveloper.arm.com/develop-for-mali/mali-gpu-texture-compression-tool/

可视化转换界面

   
命令行转换脚本
for %%i in (*.tga) do PVRTexTool.exe -f ETC -i %%i
(将本目录下的所有tga文件,转换成"ETC"编码格式的pvr文件,不带mipmap这里还是使用的PVRTexTool.exe,也可以使用QCompressCmd.exe)
详细使用说明:PVRTexTool.exe /?

4)nVIDIA Tegra
可以使用DirectX SDK中自带的DirectX Texture Tool进行转换
可视化转换界面

   
命令行转换脚本
for %%i in (*.tga) do texconv.exe -f DXT5 %%i
(将本目录下的所有tga文件,转换成"DXT5"编码格式的dds文件,不带mipmap)
详细使用说明:TexConv.exe /?







參考網址
http://www.opengpu.org/forum.php?mod=viewthread&tid=417

http://zh.wikipedia.org/wiki/%E7%BA%B9%E7%90%86%E5%8E%8B%E7%BC%A9

http://m.mydrivers.com/newsview.aspx?id=266555&cid=1&p=2

http://www.blogjava.net/demibug/archive/2011/12/16/366543.html

http://www.cnblogs.com/luming1979/archive/2013/02/04/2891421.html


2013年6月23日 星期日

OpenGL基本瞭解(十九)(Mipmap in texture filtering)


這是一個高階的課題,不論是性能及顯示結果,或是如何啓動,都需要好好考慮。


在三維電腦圖形的貼圖渲染中有一個常用的技術被稱為Mipmapping。為了加快渲染速度和減少影像鋸齒,貼圖被處理成由一系列被預先計算和最佳化過的圖片組成的檔案,這樣的貼圖被稱為 MIP map 或者 mipmap。這個技術在三維遊戲中被非常廣泛的使用。「MIP」來自於拉丁語 multum in parvo 的首字母,意思是「放置很多東西的小空間」。Mipmap 需要佔用一定的內存空間,同時也遵循小波壓縮規則 (wavelet compression)。

Mipmap中每一個層級的小圖都是主圖的一個特定比例的縮小細節的複製品。雖然在某些必要的視角,主圖仍然會被使用,來渲染完整的細節。但是當貼 圖被縮小或者只需要從遠距離觀看時,mipmap就會轉換到適當的層級。事實上,在三線性過濾(trilinear filtering)起作用時,會在兩個相近的層級之間切換。
因為mipmap貼圖需要被讀取的像素遠少於普通貼圖,所以渲染的速度得到了提升。而且操作的時間減少了,因為mipmap的圖片已經是做過抗鋸齒處理的,從而減少了即時渲染的負擔。放大和縮小也因為mipmap而變得更有效率。+
如果貼圖的基本尺寸是256x256像素的話,它mipmap就會有8個層級。每個層級是上一層級的四分之一的大小,依次層級大小就 是:128x128;64x64;32x32;16x16;8x8;4x4;2x2;1x1(一個像素)。例如在一個場景中,渲染貼圖需要填滿的空間大小 是40x40像素的話,如果沒有三線性過濾,那32x32 會被放大顯示,或者有三線性過濾,會在64x64和32x32之間切換。最簡單的生成貼圖的方法就是依次做平均,當然也可以用更加高階的演算法。

圖為Mipmap產生的各種階段的小圖。

Mipmap visualization.


OPENGLES下的指令

手動產生方法一
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pImageData0);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, pImageData1);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, pImageData2);
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 2, 2, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, pImageData3);
glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 1, 1, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, pImageData4);
 
手動產生方法二
for (int level = 0; 
     level < description.MipCount; 
     ++level, width >>= 1, height >>= 1, ppData++)
{
    glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 
                 0, GL_RGBA, GL_UNSIGNED_BYTE, *ppData);
} 
 
自動產生方法
// OpenGL ES 1.1
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, ...);

// OpenGL ES 2.0
glTexImage2D(GL_TEXTURE_2D, 0, ...);
glGenerateMipmap(GL_TEXTURE_2D);
 
 
其中glTexImage2D的指令說明,目的在指定一个二维的纹理图片   

void glTexImage2D(
GLenum target, 

GLint level, 

GLint internalformat, 

GLsizei width, 

GLsizei height, 

GLint border, 

GLenum format, 

GLenum type,

const GLvoid * pixels
);

target     指定目标纹理,这个值必须是GL_TEXTURE_2D。
level       执行细节级别。0是最基本的图像级别,你表示第N级贴图细化级别。
internalformat     指定纹理中的颜色组件,这个取值和后面的format取值必须相同。可选的值有
                    GL_ALPHA,
                    GL_RGB,
                    GL_RGBA,
                    GL_LUMINANCE,
                    GL_LUMINANCE_ALPHA 等几种。
width     指定纹理图像的宽度,必须是2的n次方。纹理图片至少要支持64个材质元素的宽度
height     指定纹理图像的高度,必须是2的m次方。纹理图片至少要支持64个材质元素的高度
border    指定边框的宽度。必须为0。
format    像素数据的颜色格式,必须和internalformatt取值必须相同。可选的值有
                    GL_ALPHA,
                    GL_RGB,
                    GL_RGBA,
                    GL_LUMINANCE,
                    GL_LUMINANCE_ALPHA 等几种。
type        指定像素数据的数据类型。可以使用的值有                   
                    GL_UNSIGNED_BYTE,
                    GL_UNSIGNED_SHORT_5_6_5,
                    GL_UNSIGNED_SHORT_4_4_4_4,
                    GL_UNSIGNED_SHORT_5_5_5_1
pixels      指定内存中指向图像数据的指针

描述:

纹理映射一个指定的纹理图像的每一部分到相应的图元中。调用带GL_TEXTURE_2D参数的glEnable和glDisable函数来启用和禁止二维材质贴图。默认,二维材质贴图是禁用的。
调用glTexImage2D来定义材质图片。

glTexImage2D()的用法举例
glTexImage2D(GL_TEXTURE_2D, //此纹理是一个2D纹理
                              0,                                    //代表图像的详细程度, 默认为0即可
                               3,                                   //颜色成分
                              TextureImage[0]->sizeX,          //纹理的宽度
                              TextureImage[0]->sizeY,          //纹理的高度
                              0,                                         //边框的值                             GL_RGB,                               //告诉OpenGL图像数据由红、绿、蓝三色数据组成
                             GL_UNSIGNED_BYTE,                //组成图像的数据是无符号字节类型
                             TextureImage[0]->data);          //告诉OpenGL纹理数据的来源,此例中指向存放在
 
 
GL_RGB
Three-component color.
GL_RGBA
Four-component color; includes alpha.
GL_BGRA
Same as GL_RGBA but with the blue and red components swapped. This is a non-standard format, but available on the iPhone due to the GL_IMG_texture_format_BGRA8888 extension.
GL_ALPHA
Single component format used as an alpha mask. (We'll learn a lot more about alpha in the next chapter.)
GL_LUMINANCE
Single component format used as grayscale.
GL_LUMINANCE_ALPHA
Two component format: grayscale + alpha. Very useful for storing text.
Don't dismiss the non-RGB formats; if you don't need color, you can save significant memory with the one or two-component formats.

The type parameter in glTexImage2D can be one of these:

GL_UNSIGNED_BYTE
Each color component is 8 bits wide.
GL_UNSIGNED_SHORT_5_6_5
Each pixel is 16 bits wide; red and blue have five bits each, green has six. Requires the format to be GL_RGB. The fact that green gets the extra bit isn't random — the human eye is more sensitive to variation in green hues.
GL_UNSIGNED_SHORT_4_4_4_4
Each pixel is 16 bits wide, and each component is 4 bits. Can only be used with GL_RGBA.
GL_UNSIGNED_SHORT_5_5_5_1
Dedicates only one bit to alpha; a pixel can only be fully opaque or fully transparent. Each pixel is 16 bits wide. Requires format to be GL_RGBA.
It's also interesting to note the various formats supported by the PNG file format, even though this has nothing to do with OpenGL:

  • Five grayscale formats: each pixel can be 1, 2, 4, 8, or 16 bits wide.

  • Two RGB formats: each color component can be 8 or 16 bits.

  • Two "gray with alpha" formats: each component can be 8 or 16 bits.

  • Two RGBA formats: each component can be 8 or 16 bits.

  • Paletted formats — we'll ignore these.
 
 
 
 
 
參考網址
http://www.opengpu.org/forum.php?mod=viewthread&tid=100
 
http://zh.wikipedia.org/wiki/Mipmap 
 
 
指令參考
http://blog.163.com/hqq133@126/blog/static/168747811201211275111743/ 

OpenGL基本瞭解(十八)(Texture filtering)


在計算機圖形學中,紋理濾波(Texture filtering)是一種針對一個使用材質貼圖的像素,使用臨近的一個或多個紋素計算其紋理顏色的方法。從數學上來說,紋理濾波是抗鋸齒的一種,但它更著重於濾掉紋理中的高頻,而不像其他抗鋸齒技術那樣著重於改善邊界顯示效果。簡單來說,它使得同一個紋理可以被用於不同的形狀,尺寸和角度,同時儘可能減少顯示時的模糊和閃爍。

在應用紋理貼圖時,需要對於每一個像素中心所在的位置進行查詢紋理值的操作。但是由於被渲染的目標表面相對於視角,可能處於任意距離或者角度,一個像素不一定有一個紋素對應。所以需要應用某種濾波方式來決定其紋理值,缺少濾波或使用不當都會造成最終的圖像存在例如鋸齒和閃爍之類的瑕疵。

由於應用紋理貼圖的表面相對於視角的距離和角度不同,在表面之上的一個像素和對應的紋理之上一個或多個紋素之間可能存在多種對應關係,這也導致需要 應用不同的濾波方式。如果把一個正方形的紋理映射到一個正方形的表面上,在離視角的某一個距離上,螢幕上的一個像素和一個紋素幾乎等尺寸。如果比這個距離近,紋素就會比像素尺寸大,這是就需要將紋素相應地放大,這就是所謂的紋理放大。同理,如果比這個距離遠,紋素將比像素尺寸小,一個像素最終的紋理值就會從其覆蓋的多個紋素的值計算出,這也就是通常所說的紋理縮小。常見的圖像應用程序介面,例如OpenGL,提供了多種的縮小和放大濾波方式。
值得注意的是,即使在像素和紋素尺寸相等的情況下,其之間也不一定就存在一一對應的關係。例如可能存在錯位而導致一個像素覆蓋了相鄰四個紋素的各一部分。所以仍然需要某種濾波方式。


此議題的選擇對應計算量是一個高階選項,因此不要考慮太多,先用雙線性濾波(Bilinear filtering)就好了。

最近鄰插值(Nearest-neighbor interpolation)

最近鄰插值是最快速,也是最粗糙的濾波方式。最鄰近像素中心的紋素顏色將被作為像素的顏色。在紋理放大時,這種方式會導致色塊;而在紋理縮小時,則會導致閃爍和鋸齒。

最近鄰Mipmapping(Nearest-neighbor with mipmapping)

這種方式先根據距離選擇最近的mipmap層級,再從其中選擇最靠近像素中心的紋素。這對閃爍和鋸齒很有效,但不能減少色塊。

雙線性濾波(Bilinear filtering)

雙線性濾波會從最近的mipmap層次上,選擇最靠近像素中心的四個紋素,再根據他們靠近像素中心的具體進行權重插值。這時如果進行紋理放大,當像素相對於紋素移動時,像素顏色會從逐漸從一個紋素顏色變化到相鄰的紋素顏色,而不是像最近鄰插值那樣,在穿過兩個紋素的邊界時發生突變,這樣就消除色塊。雙線性濾波經常與mipmapping一起使用,但也可以單獨使用,但這時會出現閃爍和鋸齒化的問題。

一般來說,因為 bilinear interpolation 的效果已經相當不錯,再加上計算量又少,所以一般 3D 顯示晶片都是使用 bilinear interpolation 來處理貼圖的重新取樣問題,特別是在放大的部分。


三線性濾波(Trilinear filtering)

在使用mipmapping雙線性濾波時,當目標表面的距離變化時,會從一個mipmap層次突變到相鄰的層次。三線性濾波被用來解決這個問題,方法是在最相鄰的兩個mipmap層次上分別進行雙線性濾波,再用得到的兩個值進行線性插值。值得注意的是,當距離小於mipmap的零層次時(即紋素大小 超過像素大小時),三線性插值退化為雙線性插值。

各向異性濾波(Anisotropic filtering)

各向異性過濾是 現有消費級顯示卡所提供的圖像質量最佳的濾波方式。傳統的各項同性濾波中只是在正方形的mipmap層次間進行雙線性或三線性插值,但是當一個目標表面和 攝像機之間角度較大時,紋理的填充面積並不是正方形,這樣便引入了模糊和閃爍等瑕疵。 於是,各向異性濾波需要對一個非方形紋理進行採樣。在一些簡單的實現中,顯示卡使用長方形的紋理取代方形紋理,達到了較好的近似效果。但是這種方式在處理 邊界時效果依然不理想,原因是在傾斜的表面上,近端邊界比遠端邊界擁有更多的像素。於是一些高端顯示卡使用了梯形紋理,當然這也要求更大的運算量。

因此在OPENGL1.x中提供一個檢查的機制指令,來確認其最大運算能力。
    float degree;
    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &degree);


在OpenGL里面使用各異向性紋理過濾首先要系統運行的OpenGL實現支持EXT_texture_filter_anisotropic 這個OpenGL擴展。
OpenGL里面的各異向性紋理過濾的參數設置是獨立于紋理縮小和放大這兩種情況的,也就是說不需要為這兩種情況進行分別設置。參數設置十分簡單,只有一個參數就是最大各異向程度(TEXTURE_MAX_ANISOTROPY_EXT)。因為紋理縮放的各異向程度越大,就需要對更多的紋理單元進行采樣,這樣在處理速度上是不可接受的,所以必須設置一個最大各異向程度,當OpenGL進行各異向性過濾的時候,采用的各異向程度參數為紋理縮放的各異向程度和最大各異向程度之間的最小值,也就是說當紋理縮放的各異向程度大于設置的最大各異向程度時,將使用設置的最大各異向程度作為過濾使用的參數。顯然可見,當該參數設置為1的時候就是不進行各異向性過濾,1也是OpenGL為這個參數設定的缺省設置。

下面是一段示例程序:
//假設這是一個二維紋理并且已經設置了mipmap
//獲得運行的OpenGL實現支持的最大各異向程度
Glfloat largest_supported_anisotropy;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,
&largest_supported_anisotropy);
//設置紋理縮小時采用的過濾方法,這里設置的是三線性過濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
       //設置紋理放大時采用的過濾方法,這里設置的是線性過濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
       //用OpenGL實現支持的最大各異向程度設置最大各異向程度參數
glTexParameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT,
largest_supported_anisotropy);


原始圖片



雙線性濾波(Bilinear filtering)



OPENGLES指令

使用GL_TEXTURE_MIN_FILTER,用在貼圖區大於貼圖元素。有六種選項可用。
  
1. GL_NEAREST

2. GL_LINEAR

3. GL_NEAREST_MIPMAP_NEAREST

4. GL_LINEAR_MIPMAP_NEAREST

5. GL_NEAREST_MIPMAP_LINEAR (default)

6. GL_LINEAR_MIPMAP_LINEAR


使用GL_TEXTURE_MAG_FILTER,用在貼圖區域小於或等於貼圖元件。有兩種選項可用。
1. GL_NEAREST

2. GL_LINEAR (default)




                                    

範例
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);





參考網頁
http://zh.wikipedia.org/wiki/%E7%BA%B9%E7%90%86%E6%BB%A4%E6%B3%A2

http://www.opengpu.org/forum.php?mod=viewthread&tid=100

http://book.51cto.com/art/201208/352655.htm

指令使用說明
http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml

http://www.cs.nccu.edu.tw/~mtchi/3d12/lab/3d12-lab5.pdf

http://www.informit.com/articles/article.aspx?p=770639&seqNum=2

http://big5.china-code.net/ap-ccfmFMLu4k-9346.html

2013年6月15日 星期六

OpenGL基本瞭解(十六) (Polygonal modeling)

多邊形造型(Polygonal modeling)


參考wiki的說明  http://zh.wikipedia.org/wiki/%E5%A4%9A%E8%BE%B9%E5%BD%A2%E9%80%A0%E5%9E%8B

在三維電腦圖形學中,多邊形造型是用多邊形表示或者近似表示物體曲面的物體造型方法。多邊形造型非常適合於掃描線渲染,因此即時電腦圖形處理中的一項可以使用的方法。其它表示三維物體的方法有 NURBS 曲面、細分曲面以及光線跟蹤中所用的基於方程的表示方法。




以下是一個使用OPENGL1.1的範例參考網頁

在使用OpenGL繪製3D模型時
可以用glPolygonMode()搭配參數GL_LINE檢視模型網格的架構
不過,如果要「同時」顯示模型實體(solid)跟網格線(wireframe),該怎麼做好呢?

答案出乎意料的簡單,OpenGL Redbook上就有說明
利用glPolygonOffset()加上glPolygonMode()
將模型畫兩次,就可以達成囉~
為了減少程式碼的複雜度,建議先將繪圖部份以display list表示
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glShadeModel(GL_FLAT);
glColor3f( model_color );
glCallList( model_display_list );

glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f( wireframe_color );
glCallList( model_display_list );

如此一來,就可以畫出表面有網格線的模型實體了


OpenGL基本瞭解(十五) (法線)

法線Normal (geometry)

是垂直於表面的一條線


p = Evaluate(s, t)   (黑點位置)
u = Evaluate(s + ds, t) - p     (ds 極小值,相對於P以得到u線)
v = Evaluate(s, t + dt) - p      (dt 極小值,相對於P以得到v線)
N = Normalize(u × v)   (N = u , v乘積)

C++的乘積範例,此做法是由ㄧ個點,使用微小差異的方式來得出兩個向量,以此向量得出的平面,來求出法向量。
template <typename T>
struct Vector3 {
    // ...
    Vector3 Cross(const Vector3& v) const
    {
        return Vector3(y * v.z - z * v.y,
                       z * v.x - x * v.z,
                       x * v.y - y * v.x);
    }
    // ...
    T x, y, z;
};
 
 
 
 
在一般的3D資料中,如果給定的是face面資料,可以根據三角形之類或其它面型的點位置,
利用三點坐標去算出法向量
 
例如 
for each face in faces:
    vec3 a = positions[face.Vertex0]
    vec3 b = positions[face.Vertex1]
    vec3 c = positions[face.Vertex2]
    vec3 facetNormal = (a - b) × (c - b) 
 

再將facetNormal加到每一個點上,但因為每一個點可能對應到不同的面上,
然後我們將一個點上所對應到的多個法向量相加,就可以得多此點所對得的真實向量了。
 
 
 

2013年6月6日 星期四

OpenGL基本瞭解(十四) (光照基本資料)


一. 現實中的光照模型

1. 顏色是什麼?
在沒有學過光學的人的認識中,顏色是物體的自身屬性,很多的物體的顏色是一成不變的,比如雪是白色,樹葉是綠色,血液是紅色。但如果我們試着呆在一 個隔絕任何光線的純黑小屋中,我們會發現所有顏色都消失了,於是我們可以得到這样的結論:顏色並不是這样物體自身的屬性,不同的顏色,是物體表面光學特性 和光線相互作用的結果。
日光是所有可見光的集合,照射與物體表面時,某些波長的光被吸收,某些波長的光線則被反射,反射的光線最終進入人的眼睛,投影在視網膜,形成了顏色。比如紅色就是物體表面反射紅光,吸收其餘光線的結果。
2. 物體表面和光線不同夾角對顏色產生的影響:
我們都有這样的經曆,玻璃杯,瓷器等表面光滑的物件,無論表面原來的顏色是什麼,在日光下總會有一塊純白的“高光”區域,並且這個區域會隨着光照方 向的變化或者人觀察角度的變化,在物體表面移動。說明對於表面光滑的物體而言,顏色不但和表面特性,光線相關,還和光照角度和觀察角度相關。
3. 物體表面光滑度對顏色的影響:
同一束光線,照在同样顏色的光滑表面上和粗糙表面上,視覺效果也是不同的,明顯的區別是,在光滑表面上,通常都有那種前面說的高光效果,而且越光滑 越明顯,在粗糙表面上,那種高光效果消失了,顏色的分布變的很均勻,顏色的變化也變的很平滑, 改變光線照射的角度,依然會對顏色的分布產生影響,但是似乎已經和觀察角度無關了。這種反射,被稱为漫反射,實際上漫反射依然嚴格遵循光線的反射和折射定 律,只不過光線在接觸粗糙表面時,在微觀尺度上表面的不規則形狀之間進行了很多次的鏡面反射,因此出射角度已經隨機分布。 不過在計算機處理漫反射時,如果對微觀尺度上的鏡面反射進行完整的模擬,計算量過於龐大,所以會將其近似为均勻向所有方向散射。
4. 自發光物體在光線中產生的顏色:
如果我們要模擬的物體本身是個光源,那麼它在外部光源下會呈現什麼? 我們可以自己動手實驗 - 比如將發綠光的物體,置於紅色外部光源下,可以觀察到黃色。因此我們可以得到的結論是自發光體的顏色由自發光顏色和外部光源叠加產生。


运行 OpenGL 程序在屏幕上显示的最终颜色,受场景中光线的特性以及物体反射和吸收光的属性(即材质)影响。 

在OpenGL 光照模型中光源和光照效果可以细分为红,绿,蓝三个部分,光源由红,绿,蓝强度来定义,而物体表面材料由其反射红,绿,蓝的程度和方向来定义。OpenGL 光照模型使用的计算公式是对于现实世界光照的一个近似但效果非常好并适合快速计算。

OpenGL 光照模型中定义的光源可以分别控制,打开或关闭,OpenGL ES支持最多八个光源。

OpenGL 光照模型中最终的光照效果可以分为四个组成部分:Emitted(光源), ambient(环境光),diffuse(漫射光)和specular(镜面反射光),最终结果由这四种光叠加而成。

http://www.imobilebbs.com/wordpress/wp-content/uploads/2011/07/20110725002.png

1. Emitted (emission)发射光: 一般只发光物体或者光源,这种光不受其它光源的影响。

2. ambient 環境光: 指光线经过多次反射后已经无法得知其方向(可以看作来自所有方向),可以成为环境光,该光源如果射到某个平面,其反射方向为所有方向。 Ambient 不依赖于光源的方向。就是哪些在环境中进行了充分散射的光,而无法分辨其方向的光。光线在物体表面上向各个方向上均匀泛射,场景中的物体都会泛射光,这些泛射光又会照射到其他 物体上继续被泛射,直到光子能量耗尽为止,这样整个场景中散布着这样的泛射光。在编程时,可通过设置一个颜色常量来表示环境光或使用 ambient occlusion map (环境闭包贴图)来处理环境光。在 OpenGL 中,全局环境光的强度为 (0.2, 0.2, 0.2, 1.0),这弱弱的白色全局环境光确保即使没有额外的光源,场景中的物体依然是可见的。在白天非陽光直射,和外部光源很多的情況下,現實環境中會彌散着幾乎一致的亮度,OpenGL將這部分光稱作環境光,它给3D世界整體亮度設定了基線。

3. diffuse 漫反射光:当一束平行的入射光线射到粗糙的表面时,因面上凹凸不平,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同 的方向无规则地反射,这种反射称之为“漫反射”或“漫射”。这个反射的光则称为漫射光。漫射光射到某个平面时,其反射方向也为所有方向。diffuse 只依赖于光源的方向和法线的方向。因此為只和表面與光線入射夾角有關的光線。我们之所以能看到物体,就是因为物体将入射的光然后向各个方向反射(所以称之为漫反射)。物体的漫反射材质属性对物体的颜色起着决定性作用。

4. specular 鏡面反射光: 一般指物体被光源直射的高亮区域,也可以成为镜面反射区,如金属。specular依赖于光源的方向,法线的方向和视角的方向。不但和表面與光線入射夾角有關,而且還和觀察角度有關的光線,並且根據表面光滑程度,呈現不同亮度,越光滑,越容易產生高光區域。在 OpenGL 中,镜面光的强度可通过光泽度(shininess)来调节。 

 

同样的,對應於光線的類型,OpenGL也定義了3種材質屬性(Material):
Ambient,Diffuse, Specular. 每種材質類型的值實際上是代表各自的光線類型在最終合成的亮度上的權重 。也可以看作在物體表面,鏡面反射,漫反射和環境光反射各占多大成分。

尽管光源可能只发送某一频率的光线,但ambient,diffuse和specular可能不同。比如使用白光照射一堵红墙,散射的光线可能为红色。OpenGL允许为光源分别设置红,绿,蓝三个元素的值。
最终决定所看到物体的颜色除了光源的颜色和方向外,还取决于物体本身的颜色,比如红色的光照在红色的物体和蓝色的物体,最终看到的物体一个还是红 色,一个为黑色。OpenGL 中对物体材料(Material)的颜色是通过其反射红,绿,蓝的比例来定义的。 和光源一样,物体的颜色也可以有不同的ambient,diffuse和specular,表现为反射这些光的比例。ambient,diffuse反射 通常为同样的颜色,而specular常常表现为白色或灰色光,如使用白光照射一个红色的球,球的大部分区域显示为红色,而高亮区域为白色。




如何决定入射光和表面的夾角 - 法向量:
OpenGL中的表面,都是由三角形組成的,三角形的三個頂點,可以决定一個平面,凡是平面,就會有法線,所以我們只要知道了這個平面的法向量,那麼
入射光和平面的夾角= 90度-入射光向量和法向量的夾角。
不過不同於前述的一個三角形對應一個法向量,OpenGL中的法線向量是和頂點聯系在一起的(具體原因也許是數據組織的方便性),因此在光照模型 中,需要给每個頂點指定法向量,如不指定,則默認为(0,0,1)。最終三角形內部各個位置的法向量也由3個頂點的法向量線性插值而來。不過通常我們會保 持三角形三個頂點的法向量相同。


二,光照的计算


OpenGL中頂點顏色的最終合成:
我們已經知道了這4種類型的光線,以及它們各自的反射亮度受哪些因素的影響,那麼它們如何互相影響,最終决定一個頂點的顏色呢?
OpenGL给出了一套光線合成的標准公式,不論真實世界的光線是否真由如此組成,但這套公式無疑從經驗上是最接近現實效果的。
以下是OpenGLES1.1的固定渲染管線中,它們的合成公式:

vertex color =
the material emission at that vertex +
the global ambient light scaled by the material's ambient property at that vertex +
the ambient, diffuse, and specular contributions from all the light sources, properly attenuated
最終合成的顏色,即由自發光,全局環境光和所有點光源三部分叠加而成.

Ambient + Diffuse + Specular = Final (圖右)

Ambient + Diffuse + Specular = Final

其中全局環境光的公式为:
global ambient light = ambientlight model * ambientmaterial
點光源部分又由ambient,diffuse,specular三種光源各自的公式相加而成,並且光強按離光源的距離衰減:

contribution = attenuation factor * spotlight effect *
(ambient term + diffuse term + specular term)


另外衰減因子(attenuation factor) 和距離相關,距離越大,衰減因子越小。如不考慮衰減,則可用常量1代替。

光照计算的终极公式

光照颜色 = 发射颜色 + 全局环境颜色 + (环境颜色 + 漫反射颜色 + 镜面反射颜色) × 聚光灯效果 × 衰减因子
如果场景中有多个光源(包括环境光),那么分别计算来每个光源的光照颜色,然后把这些光照颜色累加即可。如果物体不发射光,则没有发射颜色这一成分。

以下是個別次項目的計算公式

1. 发射光计算

前面说过,在 OpenGL 中是给物体材质设置发射颜色来模拟发射光的,因此它的计算非常简单:
发射颜色 = 物体的发射材质颜色



2. 环境光计算

前面说到,一般我们是设置一个颜色常量来表示环境光(或来自 ambient occlusion map),因此环境光的计算也是很简单的。

其中環境光源公式:
ambient term=ambientlight *ambientmaterial
(环境颜色 = 光源的环境光颜色 × 物体的环境材质颜色)


3. 漫反射光计算

散射光源公式:

漫反射颜色 = 光源的漫反射光颜色 × 物体的漫反射材质颜色 × DiffuseFactor
其中漫反射因子 DiffuseFactor 是光线与顶点法线向量的点积:
(df)DiffuseFactor = max(0, dot(N, L))      ***  0 <= df <= 1

在图形学中,点积几何意义其实就是表示两个向量之间夹角的 cos 值。因此这个公式直观地揭示了漫反射的规律:顶点法线正对入射光线,漫反射效果最强,顶点法线背对入射光线(角度大于等于90度)就完全没有漫反射效果。

diffuse_light

In the diagram, L is the unit length vector pointing to the light source, and N is the surface normal, which is a unit-length vector that's perpendicular to the surface.

注意:在光照计算中,顶点法线必须是经过规范化的(normalize)。



如果將光源設在無限遠處,則可以簡化公式如下




我们可以设置一个颜色常量来表示漫反射材质颜色,来得到平滑颜色的表面。但有些物体表面是很粗糙的,如裂缝,隆起,刮痕等。为了获得这样的粗糙表面 效果,可以使用 displaced polygon 技术,但这需要大量的计算,效率低下。另外一种更为高效的方式就是使用凹凸贴图(bump map)。凹凸贴图就是一种纹理,其内容包含编码在RGB颜色空间中的经过扰动的顶点法线。在使用凹凸贴图进行漫反射计算时时,首先和前面一样用正常法线 计算出 NormalDiffuseFactor,再根据扰动的顶点法线计算出 PerturbedDiffuseFactor,然后将两者相乘作为最终的 DiffuseFactor。如下图所示:

 diffuse  diffuse_bump_map


4. 鏡面光源公式:

镜面反射颜色 (Specular Lighting)= 光源的镜面光颜色 × 物体的镜面材质颜色 × SpecularFactor
SpecularFactor = power(max(0, dot(N, H)), shininess)
H = normalise(L + E)

當觀眾在無限遠處時,E可以簡化成  [0, 0, 1]

与漫反射不同,镜面反射受观察者的位置影响,这一点在上面的计算公式中可以清楚地看出来。

1. H 向量是视线向量 E 与光线向量 L 的半向量(注意:它经过规划化的)H向量又稱為半角(half-angle),因為它是位於E與L的中間。

2. L代表的是光線入射方向的反向,其几何意义就是视线与光线夹角的平分线。

3. 而 H 和 N 的点积的几何意义就是说这个平分线与法线的夹角的 cos 值,然后将这个 cos 值进行 shininess 次乘方计算得到最终的镜面反射因子 Specularfactor。

这里的关键点在于视线与光线的平分线与法线的点积计算上,这表示,当视线与光线在表面处的反射光线夹角(可看成是N与H的夹角)越少时,镜面反射效果最明显(角度越小,cos 值越大)。
一般可使用常量颜色作为镜面材质颜色,但这样得到的效果有时候并不理想。同漫反射一样,我们也可以使用镜面贴图来获得更好的镜面反射效果。镜面贴图通过控制物体表示上特定像素允许的镜面反射强度来获得较为真实的效果。



specular_theroy
 

普通镜面反射                               镜面贴图反射
specular   specular_map

5. 衰减因子

光源发射的光线在其传播过程中,会与空气中的其他粒子碰撞,其能量会逐渐衰减。在 OpenGL 中,这是通过将光照强度乘以随传播距离变化的衰减因子来模拟实现的。这个衰减因子的计算公式如下:
衰减因子 = 1.0/(距离衰减常量 + 线性衰减常量 × 距离 + 二次衰减常量 × 距离的平方)
其中距离衰减常量,线性衰减常量和二次衰减常量均为常量值。
注意:环境光,漫反射光和镜面光的强度都会受随着距离的增大而衰减,只有发射光和全局环境光的强度不会受此影响。


6. 聚光灯因子

在这里,我们讨论聚光灯的发射光照计算(也即位置型光源:如台灯,相对方向性光源:如太阳)。聚光灯就是朝某个特定发射发射光线的光源。你可以想象 下漆黑的夜晚里,一个手电筒给与你光明的这个场景,手电筒就是一个很好的聚光灯示例。聚光灯的计算分为两部分:在光线照射角度范围之外的部分被忽略,只有 在照射角度范围之内的部分需要计算。
聚光灯夹角cos值 = power(max(0, dot(单位光源向量, 单位光线向量)), 聚光灯指数)
其中单位光线向量是从光源指向顶点的单位向量,聚光灯指数表示聚光灯的亮度程度。前面说过点积的几何意义就是表示角度的,这里聚光灯因子就表示光源向量与光线向量之间的夹角。

而为了模拟真实聚光灯光环效果,在照射角度范围之内与之外的接壤处,设置一个渐变过渡区域,以避免光照从有到无巨变:
无过渡
有过渡
spotlight spotlight_falloff
增加过渡区之后的计算如下:
spotlight_falloff_compute
内环是完全光照的,而过渡区域(中环)是从完全光照到完全没有光照的渐变过渡,外环是完全没有光照的。
聚光灯因子 = clamp((外环的聚光灯角度cos值 - 当前顶点的聚光灯角度cos值)/(外环的聚光灯角度cos值 - 内环聚光灯角度cos值), 0, 1)
clamp 函数是将聚光灯因子限定在[0, 1]之间,这样,内环是完全光照的,而中环是从完全光照到没有光照的渐变过渡,外环是没有光照的。因此:
聚光灯效果 = 聚光灯光源颜色  × 聚光灯因子




三,高洛德着色(Gouraud Shading)与冯氏着色(Phong Shading)

在图形渲染中有两种着色方式,高洛德着色与冯氏着色。高洛德着色也被称为Per-Vertex着色,它是在顶点着色阶段对顶点进行颜色计算,然后在 光栅化阶段对这些顶点颜色进行线性插值形成片元的颜色;冯氏着色也被称为Per-Pixel像素着色,它是在片元着色阶段对每一个片元(像素)进行颜色计 算。无疑,插值的颜色效果没有针对每一个片元进行颜色计算的效果好(除非你的图元切分到像素近似大小,不过这样 GPU 肯定吃不消,计算量巨大!)。
Gouraud 着色 Phong 着色
Gauroud Phong




參考網頁
http://www.cnblogs.com/kesalin/archive/2012/12/29/light_theroy.html
http://rritw.com/a/bianchengyuyan/C__/20130306/318310.html