update: 2012/05/25
reference:
1. Tutorial - Getting Started with the OpenGL Shading Language (GLSL)
2. OpenGL: Starting with the Shading Language-0
3. 著色器 (Shader) « 逍遙文工作室
A. 說明:
1. 開始本篇文章前, 請先看: OpenGL: Starting with the Shading Language-0 .
2. 本篇文章內容的主要來源為: joshbeam.com GLSL , 在此並不會作全文翻譯,
主要是對原始程式碼作部分的說明, 並會參考其它相關資料.
3. 本文除了介紹 OpenGL Shading Language (GLSL) 外, 還展示了:
漫射/散射(diffuse)光與鏡射光(specular)的效果.
-----------------------------------------------------------------------------------------
B. GLSL 概觀:
Shaders(著色器)是在圖形繪製的過程中, 在每個頂點(vertex)或每個像素(pixel)
上執行的小程式. (也有 geometry<幾何> shaders, 它是用來對基本的幾何圖形
作操作, 在此文將不會討論到) 相關參考: 著色器 (Shader)
-----------------------------------------------------------------------------------------
C. Shader 與 Program Objects:
1. Program objects: 是一個用來容納 shaders 的容器(container).
2. Shaders 需要先被編譯(compile)並連結(link), 才可在圖形繪製的過程中使用.
3. 資料可能會從某個 shader stage 傳到另一個 shader stage (例如: vertex shaders
經常會將產生的訊息傳送給 fragment shaders 使用); 因此, 將多個 shaders 連結
到同一個 program object 的機制是必要的.
4. 一個 shader object 代表一種確定型別的單一 shader(例如: vertex shader
或 fragment shader).
5. 一般情況下, 我們會先建立一個 shader object, 將 shader 的 source code 以
字串的方式傳入, 然後將它編譯.
-----------------------------------------------------------------------------------------
D. 編譯一個 GLSL shader:
編譯一個 GLSL shader 的方式如下: (需傳入一個包含 source code 的檔案路徑)
開啓 shader.cpp 檔案:
/*
* Returns a shader object containing a shader
* compiled from the given GLSL shader file.
*/
static GLuint
shaderCompileFromFile(GLenum type, const char *filePath)
{
char *source;
GLuint shader;
GLint length, result;
/* get shader source */
//
// shaderLoadSource 函式, 亦定義在此檔案中.
// 根據給定的檔案路徑(vertex/fragment shader source file)回傳字串內容.
source = shaderLoadSource(filePath);
if(!source)
return 0;
/* create shader object, set the source, and compile */
shader = glCreateShader(type);
length = strlen(source);
// sets the shader's source
glShaderSource(shader, 1, (const char **)&source, &length);
// compile the shader
glCompileShader(shader);
// 釋放包含 shader source string 的記憶體
free(source);
/* make sure the compilation was successful */
// 執行錯誤檢查
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if(result == GL_FALSE) {
char *log;
/* get the shader info log */
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
//@fixed: Assigning to 'char *' from incompatible type 'void *';
//log = malloc(length);
log = (char *)malloc(length);
glGetShaderInfoLog(shader, length, &result, log);
/* print an error message and the info log */
fprintf(stderr, "shaderCompileFromFile(): Unable to compile %s: %s\n", filePath, log);
free(log);
glDeleteShader(shader);
return 0;
}
// 回傳一個 GLuint 的值, 可用來參照到此 shader object
return shader;
}
-----------------------------------------------------------------------------------------
E. 將 shader 附加到 program object 上:
一旦 shader 編譯好後, 就應該將它附加(attached)到一個 program object 上.
開啓 shader.cpp 檔案:
/*
* Compiles and attaches a shader of the
* given type to the given program object.
*/
void
shaderAttachFromFile(GLuint program, GLenum type, const char *filePath)
// 參數說明:
//
// program: shader 要 attach 到那個 program object(可用 glCreateProgram 建立).
// type: shader 的類型, 例如: GL_VERTEX_SHADER
// 或 GL_FRAGMENT_SHADER.
// filePath: 包含 shader 原始碼的檔案路徑.
{
/* compile the shader */
GLuint shader = shaderCompileFromFile(type, filePath);
if(shader != 0) {
/* attach the shader to the program */
glAttachShader(program, shader);
/* delete the shader - it won't actually be
* destroyed until the program that it's attached
* to has been destroyed */
// 一直要等到 Attach 到的 program object 被 destroyed 了,
// shader 才會真正被刪除.
glDeleteShader(shader);
}
}
-----------------------------------------------------------------------------------------
F. 連結 Program Object:
一旦 shaders 被 attache 到 program object 後, 就可以用 glLinkProgram 函式
來連結 program object 了.
開啓 scene.cpp 檔案:
void
sceneInit(void)
{
GLint result;
/* create program object and attach shaders */
g_program = glCreateProgram();
shaderAttachFromFile(g_program, GL_VERTEX_SHADER, "data/shader.vp");
shaderAttachFromFile(g_program, GL_FRAGMENT_SHADER, "data/shader.fp");
/* link the program and make sure that there were no errors */
glLinkProgram(g_program);
glGetProgramiv(g_program, GL_LINK_STATUS, &result);
if(result == GL_FALSE) {
GLint length;
char *log;
/* get the program info log */
glGetProgramiv(g_program, GL_INFO_LOG_LENGTH, &length);
//@fixed: Assigning to 'char *' from incompatible type 'void *';
//log = malloc(length);
log = (char *)malloc(length);
glGetProgramInfoLog(g_program, length, &result, log);
/* print an error message and the info log */
fprintf(stderr, "sceneInit(): Program linking failed: %s\n", log);
free(log);
/* delete the program */
glDeleteProgram(g_program);
g_program = 0;
}
//***************************************************************
/* get uniform locations */
//
// 在 program object 連結好後, 我們可使用 glGetUniformLocation 函式,
// 到 shaders 裡取得一些被定義的 uniform 變數(在 shaders 原始檔看得到的)
// 之 locations.
// (這些 locations 即是 uniform 變數對應到顯示卡 Register 的編號地址)
//
// 之後, 將會看到這些 uniform 變數的 locations, 將允許我們傳遞訊息到 shaders 裡.
// 即是: 攝影機位置, 三個光源的位置及顏色的資訊.
// uniform vec3 cameraPosition;
g_programCameraPositionLocation = glGetUniformLocation(g_program, "cameraPosition");
// uniform vec3 lightPosition[NUM_LIGHTS];
g_programLightPositionLocation = glGetUniformLocation(g_program, "lightPosition");
// uniform vec3 lightColor[NUM_LIGHTS];
g_programLightColorLocation = glGetUniformLocation(g_program, "lightColor");
/* set up red/green/blue lights */
g_lightColor[0] = 1.0f; g_lightColor[1] = 0.0f; g_lightColor[2] = 0.0f;
g_lightColor[3] = 0.0f; g_lightColor[4] = 1.0f; g_lightColor[5] = 0.0f;
g_lightColor[6] = 0.0f; g_lightColor[7] = 0.0f; g_lightColor[8] = 1.0f;
/* create cylinder */
// 建立圓柱體
createCylinder(36);
/* do the first cycle to initialize positions */
g_lightRotation = 0.0f;
sceneCycle();
/* setup camera */
g_cameraPosition[0] = 0.0f;
g_cameraPosition[1] = 0.0f;
g_cameraPosition[2] = 4.0f;
glLoadIdentity();
glTranslatef(-g_cameraPosition[0], -g_cameraPosition[1], -g_cameraPosition[2]);
}
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。