国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

【連載】現(xiàn)代OpenGL介紹(三)

發(fā)布時(shí)間:2014-7-22 11:19    發(fā)布者:eechina
關(guān)鍵詞: OpenGL
上一次,我們得到了一個(gè)打開的窗口并等待渲染我們的hello world程序的指令。但是在我們實(shí)際畫任何東西之前,我們必須通過創(chuàng)建各種各樣的對象并將它們作為數(shù)據(jù)傳給OpenGL。讓我們過一遍我們需要設(shè)置的對象:

再看管線



回顧一下我們第一章中的[圖像管線](),這次從我們的"hello world"程序的視角,我們需要哪些對象就很清晰了。從輸入結(jié)束開始,我們的頂點(diǎn)數(shù)組包含四個(gè)頂點(diǎn),頂點(diǎn)著色器將會把它們賦值給窗口的各個(gè)角。元素?cái)?shù)組會將這四個(gè)頂點(diǎn)組合成兩個(gè)三角形,形成一個(gè)覆蓋窗口的矩形。我們會創(chuàng)建一些小的緩沖對象來將這些數(shù)組存儲在顯存中。我們 uniform 狀態(tài)將由我們的兩個(gè)"hello"圖片以及用于將它們混色的因子組成。這些圖片每個(gè)需要一個(gè)紋理對象。除了將我們的頂點(diǎn)映射到屏幕的角上,頂點(diǎn)著色器還會將一系列的紋理坐標(biāo)賦值給每個(gè)頂點(diǎn),將頂點(diǎn)映射到它所對應(yīng)的紋理的角上。然后光柵化過程將會使用紋理坐標(biāo)對矩形區(qū)域表面進(jìn)行插值,這樣,最終我們的像素著色器可以對兩個(gè)紋理進(jìn)行取樣并將它們使用一個(gè)混合因子進(jìn)行混色。為了將著色器加入到OpenGL里面,我們創(chuàng)建一個(gè)program對象來將頂點(diǎn)著色器和像素著色器鏈接起來。在這篇文章中,我們將設(shè)置好緩沖對象和紋理對象;下一次,我們將操作著色器。

OpenGL中的C類型

OpenGL定義了它自己的跟標(biāo)準(zhǔn)C類型相對應(yīng)的GL*類型:GLubyte,GLbyte,GLushort,GLshort,GLuint,GLint,GLfloat和GLdouble。OpenGL還提供了一些更具有語義的類型定義:

GLchar*,用于處理以null結(jié)束的ASCII字符串
GLclampf和GLclampd,它們只是GLfloat和GLdouble的typedef,但是用于表示范圍在0到1之間的值
GLsizei,是整型的typedef,用于表示內(nèi)存塊的大小,類型于標(biāo)準(zhǔn)C庫中的size_t
GLboolean,是GLbyte的typedef目的是存GLTRUE或者GLFALSE,類似于C++或者C99中的bool
GLenum,是GLuint的typedef用于存一個(gè)預(yù)定義的 GL_* 常量
GLbitfield,又是一個(gè)GLuint的typedef,用于存位組或者一個(gè)或多個(gè)GL*BIT mask

存儲我們的資源


static struct {
GLuint vertex_buffer, element_buffer;
GLuint textures[2];

/* fields for shader objects ... */
} g_resources;

在這里,使用一個(gè)像gresources這樣的全局結(jié)構(gòu)體變量用于在我們的初始化代碼和GLUT回調(diào)之間共享數(shù)據(jù)是最簡單的。OpenGL使用GLuint值作為對象的句柄。我們的gresources結(jié)構(gòu)體中包含兩個(gè)GLuint域,我們將用它存放我們的頂點(diǎn)名和緩沖對象的元素?cái)?shù)組。我們將添加更多的域來存放我們的著色器對象,當(dāng)我們在下篇文章中創(chuàng)建它們時(shí)。

OpenGL對象模型

OpenGL操作對象的約定有點(diǎn)不同尋常。你可以通過使用glGen*s函數(shù)(例如glGenBuffers或者glGenTextures)來創(chuàng)建一個(gè)或多個(gè)對象。正如前面提到的,得到的句柄是GLuint值。任何由對象所擁有或者關(guān)聯(lián)的數(shù)據(jù)都是由OpenGL內(nèi)部管理的。這是很典型的。你如何使用這些句柄就是不一樣的地方:為了操作一個(gè)對象,你先要通過調(diào)用相應(yīng)的glBind*函數(shù)(glBindBuffer或者glBindTexture)綁定到一個(gè)OpenGL定義的目標(biāo)。然后你將target作為參數(shù)提供給OpenGL調(diào)用,這個(gè)OpenGL調(diào)用會設(shè)置屬性或者上傳數(shù)據(jù)到綁定的對象中。目標(biāo)綁定還影響到一些不顯示使用目標(biāo)作為參數(shù)的相關(guān)的OpenGL調(diào)用,后面我們討論渲染的時(shí)候會看到的。現(xiàn)在,我們看看創(chuàng)建完緩沖對象的模板是什么樣子的:

緩沖對象

static GLuint make_buffer(
GLenum target,
const void *buffer_data,
GLsizei buffer_size
) {
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(target, buffer);
glBufferData(target, buffer_size, buffer_data, GL_STATIC_DRAW);
return buffer;
}

緩沖對象是交給OpenGL管理的內(nèi)存。它們用于存儲頂點(diǎn)數(shù)組(使用GLARRAYBUFFER)和元素?cái)?shù)組(使用GLEMEMENTARRAY)。當(dāng)你使用glBufferData分配一個(gè)緩沖時(shí),你提供一個(gè)使用提示來表明你想要改變緩沖中數(shù)據(jù)的頻率,OpenGL將基于這個(gè)提示決定最好是將它的數(shù)據(jù)存儲在CPU還是GPU。這個(gè)提示實(shí)際上并不會限制緩沖的使用方式,但是以與提示不符的方式去使用會導(dǎo)致性能低下。在我們的程序中,我們的頂點(diǎn)和元素?cái)?shù)組都是常量,不需要改變,因此我們給了glBufferData一個(gè)GLSTATICDRAW的提示。其中STATIC部分表明我們不會想去改變數(shù)據(jù)。緩沖的提示還可以設(shè)置為DYNAMIC,表明我們頻繁地寫到這個(gè)緩沖里,或者STREAM,表明我們將周期性地替換掉緩沖的內(nèi)容。DRAW部分表明我們希望緩沖只會被GPU讀取。與DRAW相對的是READ,表明一個(gè)緩沖主要會被CPU讀回去,還有COPY,表明這個(gè)緩沖是CPU和GPU之間的一個(gè)管道,不應(yīng)該偏重于任一方。頂點(diǎn)數(shù)組和元素?cái)?shù)組幾乎總是使用GL*DRAW提示。

static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
static const GLushort g_element_buffer_data[] = { 0, 1, 2, 3 };
glBufferData看待你的數(shù)據(jù)源很類似memcpy:僅僅就是一串沒有特別意義的字節(jié)流。直到我們渲染它們之前,我們不會告訴OpenGL我們數(shù)組的結(jié)構(gòu)。這允許緩沖以幾乎任何格式存儲頂點(diǎn)屬性以及其它數(shù)據(jù),或者同一份數(shù)據(jù)給不同的渲染任務(wù)以不同的方式去處理。在這里,我們僅僅是以四個(gè)兩元素向量的集合指定我們的矩形的角。



我們的元素矩陣也很簡單,一個(gè)GLushorts數(shù)組依次索引四個(gè)頂點(diǎn)元素,這樣就可以將它們匯編成一個(gè)矩形的三角形帶。在桌面版OpenGL,一個(gè)元素?cái)?shù)組可以由8位GLubyte,16位GLushort,或者32位GLuint成員組成;對于OpenGL ES,只可以使用GLubyte或者GLushort。我們現(xiàn)在像下面這樣在我們的make_resource中調(diào)用make_buffer來分配和填充我們的緩沖:

static int make_resources(void)
{
g_resources.vertex_buffer = make_buffer(
GL_ARRAY_BUFFER,
g_vertex_buffer_data,
sizeof(g_vertex_buffer_data)
);
g_resources.element_buffer = make_buffer(
GL_ELEMENT_ARRAY_BUFFER,
g_element_buffer_data,
sizeof(g_element_buffer_data)
);
/* make textures and shaders ... */
}

紋理對象

static GLuint make_texture(const char *filename)
{
GLuint texture;
int width, height;
void *pixels = read_tga(filename, &width, &height);

if (!pixels)
return 0;

就像我在上篇文章中提到的,我使用TGA格式來存儲我們的"hello world"圖片。我不會在這里浪費(fèi)時(shí)間分析代碼;如果你想看它的話,它在Github倉庫的util.c。TGA的像素?cái)?shù)據(jù)以順序的,未壓縮的三字節(jié)RGB一組打包的數(shù)組存儲(實(shí)際上是以BGR的順序),像素的順序是從圖片的左下角開始,然后從那里向右,再然后向上。接下來我們將看到,這種格式用于OpenGL紋理非常好。如果讀圖片失敗,我們返回0,它是絕不會被真正的OpenGL對象使用的"空對象"名字。

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

紋理對象提供處理結(jié)構(gòu)化數(shù)組的GPU內(nèi)存專門用于存儲紋理數(shù)據(jù)。OpenGL支持多種類型的紋理,每種都有它自己的紋理目標(biāo),包括1D(GLTEXTURE1D),2D(GLTEXTURE2D)和3D(GLTEXTURE3D)紋理。還有一些更特殊的紋理類型我們在接下來可能會遇到。2D紋理目前是最常見的類型。這里我們?yōu)槲覀兊膱D片生成并綁定一個(gè)GLTEXTURE2D紋理。紋理對象和緩沖對象不同,因?yàn)镚PU處理紋理內(nèi)存和緩存內(nèi)存有著很大的著別。

紋理取樣和紋理參數(shù)

頂點(diǎn)數(shù)組是一次一個(gè)元素地提供給頂點(diǎn)著色器,并且頂點(diǎn)著色器沒有任何方式訪問到其它的元素。然而在頂點(diǎn)著色器或者像素著色器的任何調(diào)用中,整個(gè)紋理內(nèi)容都是可用的。著色器在一個(gè)或多個(gè)浮點(diǎn)數(shù)紋理坐標(biāo)中取樣。紋理數(shù)組中的元素均勻地分布到紋理空間中,紋理空間是一個(gè)正方型的坐標(biāo)跨度從(0,0)到(1,1)(或者一個(gè)0-1的線性劃分,對于1D紋理,或者是一個(gè)正方體的劃分從(0,0,0)到(1,1,1)對于3D紋理)。為了和對象空間的x,y,z坐標(biāo)進(jìn)行區(qū)分,OpenGL像紋理空間的坐標(biāo)軸標(biāo)記為s,t,r。紋理空間均勻地分布在軸線上形成矩形的單元格,與原數(shù)組的寬高一至。格子邊界(0,0)映射到紋理空間的第一個(gè)元素,隨后的元素沿s坐標(biāo)軸和t坐標(biāo)軸向右和向上分布。在這些格子中心對紋理進(jìn)行取樣得到相應(yīng)的紋理數(shù)組中的元素。



注意,t坐標(biāo)軸可以被看作向上或者向下(事實(shí)上或者是任何方向)增長的,依賴于底層數(shù)組表示。紋理空間的另外一個(gè)坐標(biāo)軸也同樣是任意的。由于TGA圖片將它的像素自左向右,自下向上的存儲,這就是我所描繪的坐標(biāo)軸。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
如何對紋理格子之間的紋理,或者是坐標(biāo)在0-1范圍之外的紋理進(jìn)行取樣,是由glTexParameteri函數(shù)的紋理參數(shù)控制的。

參數(shù) GLTEXTUREMINFILTER 和 GLTEXTUREMAGFILTER 分別控制當(dāng)分辨率高于或低于紋理自身的分辨率時(shí),落于樣本的像素點(diǎn)之間的取樣。我們將它們設(shè)置為 GLLINEAR 來告訴GPU我們使用線性插值來對最接近取樣點(diǎn)的四個(gè)點(diǎn)進(jìn)行平滑的混色。如果用戶改變窗口大小,紋理圖片將平滑地縮放。設(shè)置填充參數(shù)為GLNEAREST將告訴GPU返回離取樣點(diǎn)最近的紋理元素,這會導(dǎo)到縮放時(shí)像素縮放時(shí)會有鋸齒。



參數(shù) GLTEXTUREWRAPS 和 GLTEXTUREWRAPT 控制當(dāng)坐標(biāo)超出坐標(biāo)軸中0-1范圍時(shí)如何處理;在這里,我們不打算對范圍之外進(jìn)行取樣,因此我們使用GLCLAMPTOEDGE,它將坐標(biāo)限制在(0,0)到(1,1)。如果一個(gè)或者兩個(gè)坐標(biāo)軸的參數(shù)是GLWRAP將造成紋理圖片在紋理空間中沿坐標(biāo)軸無限地重復(fù)。

如果抽象地說,紋理取樣可能聽起來就像復(fù)雜的2D數(shù)組索引。如果我們看一下我們的像素著色器是如何采樣紋理的可能會更有意義:



在我們的頂點(diǎn)著色器中,我們會將紋理空間的角賦值給我們的矩形頂點(diǎn)。當(dāng)光柵化的矩形的大小和紋理大小匹配時(shí)(也就是,我們的窗口大小和圖片大小一致),片元著色器會一像素一像素地取樣,正如左圖中你所看到的。如果矩形的光柵化大小和紋理不匹配,每個(gè)片元將會在我們的紋理格子中心取樣,線性濾波將使我們在紋理元素之間得到一個(gè)平滑的梯度,正如右邊所示。

分配紋理

glTexImage2D(
GL_TEXTURE_2D, 0, /* target, level of detail */
GL_RGB8, /* internal format */
width, height, 0, /* width, height, border */
GL_BGR, GL_UNSIGNED_BYTE, /* external format, type */
pixels /* pixels */
);
free(pixels);
return texture;
}

glTexImage2D(或者-1D或-3D)函數(shù)為紋理分配內(nèi)存。紋理可以有多個(gè)levels of detail,當(dāng)從更低分辨率取樣時(shí)可以依次從更小的"mipmaps"層次中取樣,但是在這里我們只是提供基本的第0級。不像glBufferData,glTexImage2D要求對分配內(nèi)存的所有的格式信息預(yù)先提出。internal format參數(shù)告訴GPU每個(gè)紋理元素使用的顏色組分,以及以什么樣的精度存儲。OpenGL支持各種的不同圖片格式;這里我將只提一下我們所使用的。我們的TGA文件使用24位的RGB像素,換句話說,每個(gè)像素由三個(gè)8位組成。這個(gè)對應(yīng)于GL_RGB8內(nèi)部格式。寬度和高度參數(shù)指定紋理元素在s和t坐標(biāo)軸上的數(shù)目(border參數(shù)是廢棄的并且總是應(yīng)該設(shè)置為0)。外部格式和類型參數(shù)聲明了我們的像素的組成順序和類型,我們的像素指向一個(gè)width*height打包的特定格式的紋理元素。TGA以BGR順序采用unsigned byte存儲它的像素,因此我們的外部格式參數(shù)使用GLBGR,類型使用GLUNSIGNED_BYTE。

讓我們在我們的make_resources函數(shù)中添加一些make_texture調(diào)用來創(chuàng)建我們的紋理對象:

static int make_resources(void)
{
/* ... make buffers */
g_resources.textures[0] = make_texture("hello1.tga");
g_resources.textures[1] = make_texture("hello2.tga");

if (g_resources.textures[0] == 0 || g_resources.textures[1] == 0)
return 0;
/* make shaders ... */
}

接下來,著色器

我們現(xiàn)在已經(jīng)準(zhǔn)備好我們的頂點(diǎn)和圖片數(shù)據(jù)了,并且準(zhǔn)備好啟動我們的繪圖管線。下一步將是寫著色器來通過GPU操控?cái)?shù)據(jù)并將它加載到屏幕上。這將是我們這一章的下一部分要做的。
本文地址:http://www.qingdxww.cn/thread-131048-1-1.html     【打印本頁】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區(qū)
  • Dev Tool Bits——使用MPLAB® Discover瀏覽資源
  • Dev Tool Bits——使用條件軟件斷點(diǎn)宏來節(jié)省時(shí)間和空間
  • Dev Tool Bits——使用DVRT協(xié)議查看項(xiàng)目中的數(shù)據(jù)
  • Dev Tool Bits——使用MPLAB® Data Visualizer進(jìn)行功率監(jiān)視
  • 貿(mào)澤電子(Mouser)專區(qū)
關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 黄色免费观看网站 | 欧美操操 | 爱豆传媒免费最新视频下载 | 国产香蕉视频在线观看 | 一二三四在线视频社区8 | chinese在线播放91国内 | 日韩在线免费视频观看 | 国产精品久久香蕉免费播放 | 在线视频观看国产 | 亚洲视频在线精品 | 色综合久久天天综线观看 | 国产香蕉视频在线播放 | 一级毛片在线播放 | 人间正道是沧桑全集免费下载高清 | 亚洲精品中文字幕无乱码麻豆 | 国产一二三区精品 | 久久99精品福利久久久 | 伊人久久久综在合线久久在播 | 99re在线观看视频 | 国内精品视频在线播放一区 | 在线播放三级 | 国产一区二区久久久 | 上海一级片| 久热综合 | 香港黄页亚洲一级 | 亚洲第一区精品日韩在线播放 | 曰韩高清一级毛片 | 恐怖星球在线观看完整版免费 | 窝窝社区精品免费视频 | 可以看的黑人性较视频 | 在线播放国产精品 | 成人精品第一区二区三区 | 亚洲精品欧美日本中文字幕 | 亚洲日本欧美产综合在线 | 99福利在线 | 性欧美大战久久久久久久野外黑人 | 最新日韩欧美不卡一二三区 | 在线欧美国产 | 日本爽爽爽爽爽爽在线观看免 | 茄子香蕉草莓丝瓜芭乐绿巨人 | 国产一卡二卡四卡免费 |