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

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

發(fā)布時間:2014-7-22 11:22    發(fā)布者:eechina
關(guān)鍵詞: OpenGL
緩沖和紋理包含了OpenGL程序所需要的原材料,但是沒有著色器,它們只是無效的字節(jié)塊。如果你還記得我們概要中的繪圖管線,渲染需要一個頂點(diǎn)著色器將我們的頂點(diǎn)映射到屏幕空間,還需要一個片元著色器,對生成的三角形的光柵化片元進(jìn)行著色。OpenGL中的著色器是使用一種叫作GLSL(GL Shading Language)的語言寫的,它看起來跟C語言很像。在這篇文章中,我們將展示我們的"hello world"程序的著色器代碼,然后寫C代碼來加載,編譯并將它鏈接到OpenGL。

頂點(diǎn)著色器

這個是我們的頂點(diǎn)著色器的GLSL代碼,在hello-gl.v.glsl中:

#version 110
attribute vec2 position;
varying vec2 texcoord;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
texcoord = position * vec2(0.5) + vec2(0.5);
}

我先總結(jié)這個著色器做什么事情,然后再給出關(guān)于GLSL更多的一些細(xì)節(jié)。這個著色器首先將頂點(diǎn)的屏幕坐標(biāo)賦值到gl_Position,它是GLSL提供的一個預(yù)定義變量。在屏幕空間中,坐標(biāo)(-1,-1)和(1,1)分別代表framebuffer的左下角和右上角;由于我們的頂點(diǎn)數(shù)組也是這樣的矩形,我們可以直接拷貝每個頂點(diǎn)position值的x和y。gl_Position的另外兩個向量組成是用于深度測試和透視投影(譯者:perspective projection是專業(yè)術(shù)語吧?如何翻譯);我們將在下一節(jié)用于3D數(shù)學(xué)的時候好好看一下它們,F(xiàn)在,我們僅僅是將它們的值設(shè)為0和1。著色器然后做了一些數(shù)學(xué)計算來將我們的屏幕空間點(diǎn)positions從屏幕空間(-1到1)映射到紋理空間(0到1)并將結(jié)果賦值給頂點(diǎn)的texcoord。



跟C很相似,GLSL著色器從main函數(shù)開始執(zhí)行,在GLSL中main函數(shù)不接受參數(shù)并返回void。GLSL借用了C的預(yù)處理關(guān)鍵字用于它自己的指令。#version指令表明下面源代碼的GLSL版本;我們的#version聲明了我們使用GLSL版本1.10(GLSL版本跟OpenGL版本綁定得很緊;1.10是對應(yīng)于OpenGL 2.0)。GLSL去掉了指針和大多數(shù)的C中的各種大小的數(shù)值類型,只保留了常用的bool,int和float類型,但是它添加了一系列的向量和矩陣類型,長度最多為4個單元大小。這里你看到的vec2和vec4類型分別是兩元素和四元素的float向量。類型名也可以作為這些類型的構(gòu)造函數(shù)使用;你可以使用單值構(gòu)造一個向量,構(gòu)成的向量的每個元素都將是這個值,或者從向量和單值的混合構(gòu)造,它們會綁到一起成為一個更大的向量。GLSL的數(shù)學(xué)操作和一些內(nèi)置函數(shù)是定義在這些向量類型之上的,可以執(zhí)行元素級的計算。除了數(shù)值類型,GLSL還提供特殊的sampler數(shù)據(jù)類型用于紋理取樣,在下面片元著色器中我們將會看到。這些基本類型可以集合成數(shù)組和用戶自定義的struct類型。

頂點(diǎn)著色器使用GLSL程序中特殊定義的全局變量和繪圖管線環(huán)境進(jìn)行通信。它的輸入來自于uniform變量以及attribute變量,分別提供狀態(tài)值和頂點(diǎn)數(shù)組的每個頂點(diǎn)屬性。著色器將它的每個頂點(diǎn)輸出賦值到varying變量。GLSL預(yù)定義了一些varying變量來接收繪圖管線中使用的特殊的輸出,包括這里我們使用的gl_Position變量。

片元著色器

現(xiàn)在讓我們看一下片元著色器源代碼,在hello-gl.f.glsl中:

#version 110
uniform float fade_factor;
uniform sampler2D textures[2];

varying vec2 texcoord;
void main()
{
gl_FragColor = mix(
texture2D(textures[0], texcoord),
texture2D(textures[1], texcoord),
fade_factor
);
}

在片元著色器中,有些輕微的變化。varying變量成了這里的輸入:每個片元著色器中的varying變量是跟頂點(diǎn)著色器中的同名變量鏈接在一起的,并且對這個變量,每個片元著色器調(diào)用都接收到一個光柵化的頂點(diǎn)著色器的輸出。片元著色器也給出了一系列不同的gl*預(yù)定義變量。glFragColor是其中最重要的,著色器將會給它一個vec4的RGBA顏色值。片元著色器可以訪問到跟頂點(diǎn)著色器同樣的uniform系列,但是不能訪問到attribute變量。



我們的片元著色器使用GLSL內(nèi)置的texture2D函數(shù)來對兩個紋理從texcoord的uniform狀態(tài)進(jìn)行取樣。然后它調(diào)用內(nèi)置的mix函數(shù)基于當(dāng)前的fade_factor值對兩個紋理值進(jìn)行組合:0會輸出只有第一個紋理的取樣,1只會輸出第二個紋理的取樣,而中間的值會給出兩者的一個混色。

既然我們已經(jīng)察看了GLSL著色器代碼,讓我們回到C并加載著色器到OpenGL。

存儲我們的著色器對象

static struct {
/* ... fields for buffer and texture objects */
GLuint vertex_shader, fragment_shader, program;

struct {
GLint fade_factor;
GLint textures[2];
} uniforms;

struct {
GLint position;
} attributes;

GLfloat fade_factor;
}
g_resources;

首先,讓我們添加一些域到我們的gresources結(jié)構(gòu)體中,存儲我們的著色器對象名字和創(chuàng)建后的程序?qū)ο。類似緩沖和紋理對象,著色器和程序?qū)ο笠彩怯肎Luint句柄命名。我們還添加了一些域來存放整型變量,我們需要在我們的著色器的uniform和attribute變量引用它們。最后,我們添加了一個域來存浮點(diǎn)數(shù)值,我們將在每一幀把fadefactor賦值給它。

編譯著色器對象


static GLuint make_shader(GLenum type, const char *filename)
{
GLint length;
GLchar *source = file_contents(filename, &length);
GLuint shader;
GLint shader_ok;

if (!source)
return 0;

OpenGL從GLSL源代碼編譯著色器對象并保存生成的GPU機(jī)器碼。沒有一個標(biāo)準(zhǔn)的方式來將GLSL程序預(yù)編譯成一個二進(jìn)制--你必須每次都從源代碼編譯著色器。這里我們在一個單獨(dú)的文件中寫著色器代碼,這樣每次我們改變著色器代碼時就不用重編譯我們的C代碼。

shader = glCreateShader(type);
glShaderSource(shader, 1, (const GLchar**)&source, &length);
free(source);
glCompileShader(shader);

著色器和程序?qū)ο竺撾x了緩沖和紋理所使用的那套glGen和glBind協(xié)議。不像緩沖和紋理函數(shù),操作著色器和程序的函數(shù)直接使用對象的整數(shù)名作為參數(shù)。對象不需要綁定到任何目標(biāo)。這里,我們對過調(diào)用glCreateShader創(chuàng)建一個著色器對象,著色器參數(shù)可以是GLVERTEXSHADER或者GLFRAGMENTSHADER。然后我們提供一個源代碼的字符串指針給glShaderSource,并告訴OpenGL去使用glCompileShader編譯著色器。這一步跟C的編譯處理過程很類型;編譯的著色器對象也是類型一個.o或者.obj文件。正如C項目中一樣,任意多的頂點(diǎn)著色器和片元著色器可以被鏈接到一起形成一個工作的程序,每個著色器對象引用到其它同類型著色器對象中定義的函數(shù),只要被引用函數(shù)全部可以被解析并且頂點(diǎn)著色器和片元著色器的main函數(shù)都提供了。

glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
if (!shader_ok) {
fprintf(stderr, "Failed to compile %s:\n", filename);
show_info_log(shader, glGetShaderiv, glGetShaderInfoLog);
glDeleteShader(shader);
return 0;
}
return shader;
}

同樣正如C程序,一個著色器的代碼塊可能會由于語法錯誤,引用不存在的函數(shù),或者類型不匹配而鏈接失敗。OpenGL對每個著色器對象維護(hù)一個由GLSL編譯器發(fā)出的錯誤或警告信息記錄。在編譯著色器之后,我們需要使用glGetShaderiv檢查它的GLCOMPILESTATUS。如果編譯失敗了,我們使用showinfolog函數(shù)顯示信息記錄并放棄。下面是showinfolog函數(shù):

static void show_info_log(
GLuint object,
PFNGLGETSHADERIVPROC glGet__iv,
PFNGLGETSHADERINFOLOGPROC glGet__InfoLog
)
{
GLint log_length;
char *log;

glGet__iv(object, GL_INFO_LOG_LENGTH, &log_length);
log = malloc(log_length);
glGet__InfoLog(object, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
}

我們將glGetShaderiv和glGetShaderInfoLog函數(shù)作為參數(shù)傳給showinfolog,這樣我們可以在后面對程序?qū)ο笾赜煤瘮?shù)(那些PFNGL*函數(shù)指針名是由GLEW提供的)。我們使用GLINFOLOG_LENGTH參數(shù)調(diào)用glGetShaderiv來得到信息記錄的長度,分配緩沖來存放它,并使用glGetShaderInfoLog來得到它的內(nèi)容。

鏈接程序?qū)ο?/strong>

static GLuint make_program(GLuint vertex_shader, GLuint fragment_shader)
{
GLint program_ok;

GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);

如果著色器對象是GLSL編譯過程的對象文件,那么程序?qū)ο笤谕瓿蓵r是可執(zhí)行的。我們使用glCreateProgram創(chuàng)建一個程序?qū)ο螅褂胓lAttachShader附上著色器對象跟它進(jìn)行鏈接,最后使用glLinkProgram調(diào)用鏈接過程。

glGetProgramiv(program, GL_LINK_STATUS, &program_ok);
if (!program_ok) {
fprintf(stderr, "Failed to link shader program:\n");
show_info_log(program, glGetProgramiv, glGetProgramInfoLog);
glDeleteProgram(program);
return 0;
}
return program;
}

當(dāng)然,鏈接也可能會失敗,由于被引用函數(shù)未定義,缺少main函數(shù),片元著色器使用了非頂點(diǎn)著色器提供的varying輸入,以及其它一些類似C程序鏈接失敗的原因。我們檢查程序的GLLINKSTATUS并將它的日志信息使用showinfolog導(dǎo)出,這次使用用于program的glGetProgramiv和glGetProgramInfoLog函數(shù)。

現(xiàn)在我們將make_resources用來編譯和鏈接我們著色器的最后一部分填上:

static int make_resources(void)
{
/* make buffers and textures ... */
g_resources.vertex_shader = make_shader(
GL_VERTEX_SHADER,
"hello-gl.v.glsl"
);
if (g_resources.vertex_shader == 0)
return 0;

g_resources.fragment_shader = make_shader(
GL_FRAGMENT_SHADER,
"hello-gl.f.glsl"
);
if (g_resources.fragment_shader == 0)
return 0;

g_resources.program = make_program(
g_resources.vertex_shader,
g_resources.fragment_shader
);
if (g_resources.program == 0)
return 0;

查找著色器變量位置


g_resources.uniforms.fade_factor
= glGetUniformLocation(g_resources.program, "fade_factor");
g_resources.uniforms.textures[0]
= glGetUniformLocation(g_resources.program, "textures[0]");
g_resources.uniforms.textures[1]
= glGetUniformLocation(g_resources.program, "textures[1]");

g_resources.attributes.position
= glGetAttribLocation(g_resources.program, "position");
return 1;
}

GLSL鏈接器將一個GLint位置賦值到每個uniform變量和頂點(diǎn)的attribute。uniforms或者attributes的結(jié)構(gòu)體和數(shù)組會被繼續(xù)分解,每個域都會對它的位置賦值。當(dāng)我們使用程序進(jìn)行渲染時,將變量賦值到uniform變量以及映射頂點(diǎn)數(shù)組的屬性,我們將需要使用這些整數(shù)位置。這里,我們使用函數(shù)glGetUniformLocation和glGetAttribLocation來查找這些位置,以字符串形式給它們變量名,結(jié)構(gòu)體域名,或者數(shù)組元素名字。我們?nèi)缓笤谖覀兂绦虻膅_resource結(jié)構(gòu)體中記錄這些位置。程序鏈接在一起,并且記錄中有了uniform和attribute位置,我們可以準(zhǔn)備好了使用程序進(jìn)行渲染。

下次,渲染

我知道我在吊你胃口,最后部分還沒完成,還沒有一個完整的可以運(yùn)行的程序。我將在在下次,也就是本章最后一部分,修復(fù)它,到時我會寫代碼讓繪圖管線運(yùn)作起來渲染我們的場景。
本文地址:http://www.qingdxww.cn/thread-131049-1-1.html     【打印本頁】

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

廠商推薦

  • Microchip視頻專區(qū)
  • Dev Tool Bits——使用MPLAB® Discover瀏覽資源
  • Dev Tool Bits——使用條件軟件斷點(diǎn)宏來節(jié)省時間和空間
  • Dev Tool Bits——使用DVRT協(xié)議查看項目中的數(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ù) 返回頂部 返回列表
主站蜘蛛池模板: 四虎影视在线麻豆国产 | 97久久精品国产成人影院 | 国产精品高清久久久久久久 | 黄视频网站免费观看 | 国产三级网址 | 高清不卡免费一区二区三区 | 黑人巨大精品欧美一区二区 | 在线天堂中文www官网 | 国产免费一区二区三区免费视频 | 久久久久久国产视频 | 亚洲一区二区三区在线播放 | 九九精品视频在线 | www.56pao| 西野翔有码中文字幕在线 | 青青青草视频在线观看 | 欧美视频一区二区 | 日本免费人成在线网站 | 韩国一级特黄清高免费大片 | 中文字幕一区在线 | 欧美巨大精品欧美一区二区 | 男女性高爱潮是免费 | 欧美成人黄色片 | 国产精品一久久香蕉产线看 | 69热视频在线观看免费自拍 | 亚洲网在线 | 国产90后美女露脸在线观看 | 国产原创巨作精品 | 青青草国产精品人人爱99 | 美女被猛男躁免费视频网站 | 免费韩国一级毛片 | 欧美人与性动交a欧美精品 欧美人与禽zzz000xxx | 欧美特黄视频在线观看 | 青青视频免费在线 | 欧美日韩在线视频观看 | 欧美aaaaaaaa| 国产特级毛片aaaaaa高清 | 免费人成在线观看网站 | 91短视频在线观看免费 | 亚天堂| 欧美日韩免费在线 | 免费99精品国产自在现线观看 |