1. 程式人生 > >New程式媛OpenGL全解析之—紋理

New程式媛OpenGL全解析之—紋理

大家好


本期視訊的連結地址是:

https://www.bilibili.com/video/av24529999/

大家也可以直接在bi站首頁搜尋:New程式媛 ,即可看到相應視訊

本期的資源和程式碼下載連結是:

連結:https://pan.baidu.com/s/11DhBfRjnYGDc78z_iKE-PA 密碼:h8xk

視訊搭配文章一起效果更贊哦

丹丹今天要給大家帶來的是紋理部分的知識。讓我們的物體穿上美膩的外衣!

之前繪製的物體都是通過設定定點顏色讓物體看起來來花(tu)花(li)綠(土)綠(氣)的~

現在我們把紋理也就是通俗意義上說的圖片載入到應用程式中,並且給每個繪製的定點設定好紋理座標,再對我們的程式碼稍加修改就可以讓物體穿上外衣也就是貼上紋理了。

Texture—紋理 

看咱們這張圖片是不是粉喜慶哇~

紋理座標的範圍是[0,1],也就是笑臉的左下角是紋理自身座標系的[0,0],而笑臉的右上角則是紋理座標系的[1,1]座標。

要來講解紋理首先程式碼要做的第一件事情就是載入紋理圖片到程式碼中。

每張紋理圖片其實都是一個寫滿了顏色等資料的檔案,只要瞭解了每種圖片的資料儲存順序也就是格式,我們就可以讀取檔案的方式把圖片顏色資訊,寬高等資訊都讀取出來。

但實際上,很多第三方都已經幫我們做好了這些事情,比如FreeImage就是一個圖片的第三方載入庫。而丹丹今天要給大家介紹的是SOIL(Simple OpenGL Image Library),一個簡易的OpenGL影象庫,它支援大多數流行的影象格式,使用起來也很簡單,我們可以從他們的主頁下載。

主頁地址是:http://www.lonesock.net/soil.html

點到Download中的藍色here按鈕即可下載。

下載解壓後有一個叫projects的資料夾

開啟找到VC9資料夾,點開SOIL.sln解決方案,重新編譯即可得到.lib檔案

把Lib檔案新增到我們的專案中,同時在project同級路徑中找到src資料夾,把資料夾中所有的.h檔案也加入到專案中就OK拉~

程式碼中首先新增好標頭檔案

之後編寫一個載入紋理的函式如下:

該函式中

就是使用SOIL庫載入圖片。

那麼其它的程式碼做的事情是什麼呢?

首先來看:

GLuint textureID;

和其它的OpenGL物件一樣,紋理也是使用ID引用的,所以需要定義一個textureID對應它。

glGenTextures(1, &textureID);

函式第一個引數是紋理的數量,第二個是儲存對應紋理的ID陣列資料。

glBindTexture(GL_TEXTURE_2D, texture);

繫結紋理ID

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,

GL_UNSIGNED_BYTE, image);

繫結好紋理對應ID,就可以通過glTexImage2D來生成紋理,讓我們一起來看看引數的意義

引數一:指定紋理目標,GL_TEXTURE_2D表示是一個2D紋理。

引數二:為紋理指定多級漸遠紋理的級別,0表示基本級別。

引數三:告訴OpenGL紋理儲存的格式。

引數四:紋理寬度。

引數五:紋理高度。

引數六:總是被設為0(歷史遺留問題)。

引數七:原圖的格式。

引數八:原圖資料型別。

引數九:真正的影象資料。

glGenerateMipmap

該函式是用來生成Mipmap紋理。

那麼什麼是Mipmap紋理呢?

簡單來說就是一系列的紋理影象,後一個紋理影象是前一個的二分之一如下圖:

物體因為距離眼睛的距離而有有近大遠小的現象。遠處的物體顯示的只是一個很小的色塊,OpenGL從高解析度紋理中為這些片段獲取正確的顏色值就很困難,因為它需要對一個跨過紋理很大部分的片段只拾取一個紋理顏色。會產生不真實的感覺,更不用說對它們使用高解析度紋理浪費記憶體的問題了。

而Minmap紋理就很好的解決了這個問題。它會去選取最適合物體的距離的那個大小的紋理作為當前紋理來解決這個問題。

接下來的程式碼是:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

這兩個函式的作用是什麼呢?

它設定的是紋理的環繞模式,什麼叫環繞模式呢?我們已知紋理的座標範圍是[0,1],那麼如果設定的紋理座標大於1是怎麼處理的呢?這就是通過設定環繞模式來實現,環繞模式有如下圖這四種:

通過圖示可以很直觀的看到四種不同處理方式顯示出的效果。

GL_REPEAT對紋理的預設行為。重複紋理影象。
GL_MIRRORED_REPEAT和GL_REPEAT一樣,但每次重複圖片是映象放置的。
GL_CLAMP_TO_EDGE紋理座標會被約束在0到1之間,超出的部分會重複紋理座標的邊緣,產生一種邊緣被拉伸的效果。
GL_CLAMP_TO_BORDER超出的座標為使用者指定的邊緣顏色。

如果我們選定的是GL_CLAMP_TO_BORDER模式,則通過以下函式設定邊緣顏色:

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

glTexParameteri的第一個引數指定了我們的紋理目標。

第二引數的可選項有三種

GL_TEXTURE_WRAP_S

GL_TEXTURE_WRAP_T

GL_TEXTURE_WRAP_R

它們分別對應xyz軸。

到這一步驟我們的環繞模式就已經設定好了。

來看看接下來的程式碼

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

這兩個函式的意義是什麼呢?就是設定紋理過濾啦~

那什麼是紋理過濾呢?當你要貼紋理的表面非常大,但是你的紋理圖片又解析度不夠高的時候,就需要通過設定紋理過濾讓紋理看起來更適合你要表現的效果,今天給大家主要介紹兩種GL_NEAREST鄰近過濾和GL_LINEAR線性過濾。GL_NEAREST是OpenGL預設的紋理過濾方式,這種方式下OpenGL會選擇中心點最接近紋理座標的那個畫素作為最終的顏色片段,二線性過濾方式則是會基於紋理座標附近的紋理畫素,計算出一個插值,近似出這些紋理畫素之間的顏色,兩種的區別是一種能看到明顯的邊緣和畫素塊,而另一中線性的會看起來更平滑。

最後通過繫結0來解綁當前紋理物件glBindTexture(GL_TEXTURE_2D, 0);。

並通過SOIL_free_image_data(image)函式來釋放圖片資源。

紋理的載入就全部結束了,咱們再來看看程式碼的變化。

資料的初始化

此時我們的頂點資料不僅包含了位置座標資料,還包含了紋理資料。

著色器部分

我們在頂點著色器中傳入了頂點資料座標和紋理座標資料。並把紋理座標資料作為傳出資料傳遞給片元著色器,片元著色器中聲名了uniform sampler2D的紋理。最終片元著色器的顏色是由設定的紋理和頂點著色器傳遞過來的紋理座標決定的。

繪製程式碼

就醬紫我們今天的任務就完成啦~~~

丹丹期待大家的意見和建議,歡迎小夥伴們積極留言