1. 程式人生 > >【GLSL教程】(二)在OpenGL中使用GLSL

【GLSL教程】(二)在OpenGL中使用GLSL

設定GLSL

這一節講述在OpenGL中配置GLSL,假設你已經寫好了頂點shader和畫素shader。如果你還沒有準備好,可以從如下網址獲得相關內容:

http://www.3dshaders.com/home/

http://www.opengl.org/sdk/tools/ShaderDesigner/

http://developer.amd.com/archive/gpu/rendermonkey/pages/default.aspx

在OpenGL中,GLSL的shader使用的流程與C語言相似,每個shader類似一個C模組,首先需要單獨編譯(compile),然後一組編譯好的shader連線(link)成一個完整程式。

這裡將忽略ARB擴充套件,只列舉OpenGL2.0的程式碼。建議使用GLEW庫:

http://glew.sourceforge.net/

下面的程式碼檢查OpenGL 2.0是否可用:

  1. #include <GL/glew.h>
  2. #include <GL/glut.h>
  3. void main
    (int argc, char **argv)
  4. {
  5. glutInit(&argc, argv);
  6. ...
  7. glewInit();
  8. if
    (glewIsSupported( "GL_VERSION_2_0"))
  9. printf( "Ready for OpenGL 2.0\n");
  10. else
  11. {
  12. printf( "OpenGL 2.0 not supported\n");
  13. exit( 1);
  14. }
  15. setShaders();
  16. glutMainLoop();
  17. }

下圖顯示了建立shader的必要步驟,函式的具體使用方法將在下面各小結描述:


建立shader

下圖顯示了建立shader的步驟:


首先建立一個物件作為shader的容器,這個建立函式將返回容器的控制代碼。

  1. GLuint glCreateShader(GLenum shaderType);
  2. 引數:
  3. ·shaderType – GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
你可以建立許多shader,但記住所有的頂點shader只能有一個main函式,所有畫素shader也一樣。

下一步將新增原始碼。shader的原始碼是一個字串陣列,新增的語法如下:

  1. void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);
  2. 引數:
  3. ·shader – the handler to the shader.
  4. ·numOfStrings – the number of strings in the array.
  5. ·strings – the array of strings.
  6. ·lenOfStrings – an array with the length of each string, or NULL, meaning that the strings are NULL terminated.
最後編譯shader:

  1. void glCompileShader(GLuint shader);
  2. 引數:
  3. •shader – the handler to the shader.


建立程式

下圖顯示了獲得一個可以執行的shader程式的步驟:


首先建立一個物件,作為程式的容器。此函式返回容器的控制代碼。

GLuint glCreateProgram(void);

你可以建立任意多個程式,在渲染時,可以在不同程式中切換,甚至在某幀返回固定功能流水線。比如你想用折射和反射shader繪製一個茶杯,然後回到固定功能生成立方體環境貼圖(cube map)顯示背景。

下面將把上一節編譯的shader附加到剛剛建立的程式中。方法如下:

  1. void glAttachShader(GLuint program, GLuint shader);
  2. 引數:
  3. ·program – the handler to the program.
  4. ·shader – the handler to the shader you want to attach.
如果同時有頂點shader和片斷shader,你需要把它們都附加到程式中。你可以把多個相同型別(頂點或畫素)的shader附加到一個程式中,如同一個C程式可以有多個模組一樣,但它們只能有一個main函式。

你也可以把一個shader附加到多個程式,比如你想在不同程式中使用某個相同的shader。

最後一步是連線程式。方法如下:

  1. void glLinkProgram(GLuint program);
  2. 引數:
  3. ·program – the handler to the program.
在連線操作之後,shader的原始碼可以被修改並重編譯,並不會影響到整個程式。

程式連線後,可以呼叫glUseProgram來使用程式。每個程式都分配了一個控制代碼,你可以事先連線多個程式以備使用。

  1. void glUseProgram(GLuint prog);
  2. 引數:
  3. ·prog – the handler to the program you want to use, or zero to return to fixed functionality.
當一個程式被使用後,如果被再次連線,它將被自動替換並投入使用,所以沒有必要再次呼叫上面這個函式。如果使用的引數為0,表示將使用固定功能流水線。

 例子

下面的程式碼包含了上面描述的所有步驟,引數p,f,v是全域性的GLuint型變數。

  1. void setShaders()
  2. {
  3. char *vs,*fs;
  4. v = glCreateShader(GL_VERTEX_SHADER);
  5. f = glCreateShader(GL_FRAGMENT_SHADER);
  6. vs = textFileRead( "toon.vert");
  7. fs = textFileRead( "toon.frag");
  8. const char *vv = vs;
  9. const char *ff = fs;
  10. glShaderSource(v, 1, &vv, NULL);
  11. glShaderSource(f, 1, &ff, NULL);
  12. free(vs); free(fs);
  13. glCompileShader(v);
  14. glCompileShader(f);
  15. p = glCreateProgram();
  16. glAttachShader(p, v);
  17. glAttachShader(p, f);
  18. glLinkProgram(p);
  19. glUseProgram(p);
  20. }
GLUT版的完整例子如下:

http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl_2.0.zip

完整例子中包含了shader程式碼及文字檔案讀入程式。

 

錯誤處理

除錯shader是很困難的。目前還沒有像printf這樣的東西,雖然未來可能出現有除錯功能的開發工具。

編譯階段的狀態可以用如下函式獲得:

  1. void glGetShaderiv(GLuint object, GLenum type, int *param);
  2. 引數:
  3. ·object – the handler to the object. Either a shader or a program
  4. ·type – GL_COMPILE_STATUS.
  5. ·param – the return value, GL_TRUE if OK, GL_FALSE otherwise.
連線階段的狀態可以用如下函式獲得:

  1. void glGetProgramiv(GLuint object, GLenum type, int *param);
  2. 引數:
  3. ·object – the handler to the object. Either a shader or a program
  4. ·type – GL_LINK_STATUS.
  5. ·param – the return value, GL_TRUE if OK, GL_FALSE otherwise.
如果發生錯誤,就需要從InfoLog中找到更多的資訊。這個日誌儲存了最後一次操作的資訊,比如編譯時的警告、錯誤,連線時發生的各種問題。這個日誌甚至可以告訴你硬體是否支援你的shader。不幸的是InfoLog沒有一個規範,所以不同的驅動/硬體可能產生不同的日誌資訊。

為了獲得特定shader或程式的日誌,可以使用如下程式:

  1. void glGetShaderInfoLog(GLuint object, int maxLen, int *len, char *log);
  2. void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);
  3. 引數:
  4. ·object – the handler to the object. Either a shader or a program
  5. ·maxLen – The maximum number of chars to retrieve from the InfoLog.
  6. ·len – returns the actual length of the retrieved InfoLog.
  7. · log – The log itself.
GLSL規範有必要在這裡進行一些改進:你必須知道接收InfoLog的長度。為了找到這個準確的值,使用下面的函式:

  1. void glGetShaderiv(GLuint object, GLenum type, int *param);
  2. void glGetProgramiv(GLuint object, GLenum type, int *param);
  3. 引數:
  4. ·object – the handler to the object. Either a shader or a program
  5. ·type – GL_INFO_LOG_LENGTH.
  6. ·param – the return value, the length of the InfoLog.

下面的函式可以用來列印InfoLog的內容:

  1. void printShaderInfoLog(GLuint obj)
  2. {
  3. int infologLength = 0;
  4. int charsWritten = 0;
  5. char *infoLog;
  6. glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
  7. if (infologLength > 0)
  8. 相關推薦

    GLSL教程OpenGL使用GLSL

    設定GLSL 這一節講述在OpenGL中配置GLSL,假設你已經寫好了頂點shader和畫素shader。如果你還沒有準備好,可以從如下網址獲得相關內容: http://www.3dshaders.com/home/ http://www.opengl.org/sdk/tools/Shader

    Pycharm教程設定字型大小

    轉載:http://blog.csdn.net/chenggong2dm/article/details/8639318 pycharm 是很好的一個IDE,在windows下,和macOS下,都能很好的執行。唯一缺點是啟動慢。 預設字型太小,在mac下,需要瞪大24

    GLSL教程OpenGL向shader傳遞資訊

    引言 一個OpenGL程式可以用多種方式和shader通訊。注意這種通訊是單向的,因為shader的輸出只能是渲染到某些目標,比如顏色和深度快取。 OpenGL的部分狀態可以被shader訪問,因此程式改變OpenGL某些狀態就可以與shader進行通訊了。例如一個程式想把光的顏色傳給shade

    GLSL教程紋理貼圖

    簡單的紋理貼圖(Simple Texture)為了在GLSL中應用紋理,我們需要訪問每個頂點的紋理座標。GLSL中提供了一些屬性變數,每個紋理單元一個: attribute vec4 gl_MultiTexCoord0;

    GLSL教程逐畫素的光照

    逐畫素的方向光(Directional Light per Pixel)這一節將把前面的shader程式碼改為逐畫素計算的方向光。我們需要將工作按照兩個shader拆分,以確定哪些是需要逐畫素操作的。首先看看每個頂點接收到的資訊:•法線•半向量•光源方向我們需要將法線變換到視點空間然後歸一化。我們還

    GLSL教程其他說明

    法線矩陣在很多頂點shader中都用到了gl_NormalMatrix。這裡將介紹這個矩陣是什麼,以及它的作用。大部分計算是在檢視空間內完成的,主要原因是光照的運算要放在這個空間內,否則一些依賴觀察點座標的效果,比如鏡面反射光就很難實現。所以我們需要將法線變換到檢視空間。變換一個頂點到檢視空間的方法

    GLSL教程逐頂點的光照

    引言在OpenGL中有三種類型的光:方向光(directional)、點光(point)、聚光(spotlight)。本教程將從方向光講起,首先我們將使用GLSL來模仿OpenGL中的光。我們將向shader中逐漸新增環境光、散射光和高光效果。 後面的教程中我們將使用逐畫素

    GLSL教程卡通著色

    引言卡通著色可能是最簡單的非真真實模式shader。它使用很少的顏色,通常是幾種色調(tone),因此不同色調之間是突變的效果。下圖顯示的就是我們試圖達到的效果:茶壺上的色調是通過角度的餘弦值選擇的,這個角度是指光線和麵的法線之間的夾角角度。如果法線和光的夾角比較小,我們使用較亮的色調,隨著夾角變大

    GLSL教程shder的簡單示例

    GLSL的Hello World 這一節中包含一個最基本的shader,它提供如下功能:頂點變換然後使用單一的顏色渲染圖元。 頂點shader 前面已經說過,頂點shader負責完成頂點變換。這裡將按照固定功能的方程完成頂點變換。 固定功能流水線中一個頂點通過模型檢視矩陣以及投影矩陣進行變換

    GLSL教程圖形流水線

    這是一些列來自 lighthouse3d 的GLSL教程,非常適合入門。我將邊學習邊翻譯該教程的內容,同時記錄在這裡,方便以後查詢。 流水線概述 下圖描述了一個簡化的圖形處理流水線,雖然簡略但仍然可以展示著色器程式設計(shader programming)的一些重要概念。 一

    D3.js資料視覺化系列教程--最簡單的開始:新增元素

    1. 新增元素語法:[selection].append("p"); 2. 怎麼做?將D3.js解壓到桌面,同時在桌面建立一個index.html<html> <head>

    知識積累、深入Regex正則表示式

    \:將下一個字元標記符、或一個向後引用、或一個八進位制轉義符。例如,“\\n”匹配\n。“\n”匹配換行符。序列“\\”匹配“\”而“\(”則匹配“(”。即相當於多種程式語言中都有的“轉義字元”的概念。 ^:匹配輸入字串的開始位置。如果設定了RegExp物件的Multiline屬性,^也匹配“\n

    設計模式-附錄A:介面

    前言 最近發現大話設計模式這本書越往後學越困難了,所以還是非常有必要把附錄A的基礎知識整理整理了。 由來 為什麼要搞出一個介面來呢? 因為C#,JAVE不支援多重繼承,但是同一個類可以實現多個介面。C++支援多重繼承,不用走介面的概念。 概念 1.介面是把隱式公共方法和屬

    知識圖譜知識圖譜基礎之RDF和RDFS

    第二章知識圖譜基礎2.1知識表示和其查詢語言 知識表示和知識推理是人工智慧領域中致力於表示世界上各種資訊的技術,有了這項技術,計算機在解決一個複雜任務時可以根據相關知識來依靠自動推理作為輔助決策。知識圖譜可以被視為語義網路的現代版本。2.1.1RDF和RDFS 在這部分,我們

    必須知道的八大種排序演算法java實現 選擇排序,插入排序,希爾演算法詳解

    一、選擇排序   1、基本思想:在要排序的一組數中,選出最小的一個數與第一個位置的數交換;然後在剩下的數當中再找最小的與第二個位置的數交換,如此迴圈到倒數第二個數和最後一個數比較為止。   2、例項   3、演算法實現    /** * 選擇排序演算法 * 在未

    Machine Learning第九講推薦系統-- 協同過濾

    一、Collaborative Filtering(協同過濾) 協同過濾能夠自行學習所需要使用的特徵。 來看下面的例子: 在之前講的基於內容的推薦系統中,我們需要事先建立特徵並知道特徵值,這是比較困難的。 假設我們某一使用者的喜好,即假如Alice、Bob喜歡romance的電影,carol

    Machine Learning第九講異常檢測-- 建立一個異常檢測系統

    一、Developing and Evaluating an Anomaly Detection System(異常檢測系統的衡量指標) 對於某一演算法,我們可以通過藉助某些數字指標來衡量演算法的好壞,仍舊以飛機引擎的例子來說: 假設有10000個正常的引擎,20個有瑕疵的引擎(異常)

    Axure學習Axure遮罩層

    遮罩層實現方案: 1. 在網站上面加一層動態面板,大小和網站相同。 2. 在該層上面再加一個動態面板(登陸框), 3. 當點選登陸框的關閉按鈕時,遮罩層和登入框都隱藏。(回到主頁面) 4. 這兩個動態面板初始都設為隱藏狀態,當點選主頁面的【登陸】按鈕時

    pycharm 教程安裝和首次使用

    Opencv學堂 http://mp.weixin.qq.com/s?__biz=MzA4MDExMDEyMw==&mid=100000109&idx=1&sn=7540b49e869c3e27f87c84f6f3dfe9a8&chksm

    AOP系列—AOP相關概念

    前提   在閱讀本篇博文之前,請先閱讀上篇博文【AOP系列】(一)—靜態代理VS動態代理(Java) ,因為下文中在解釋一些概念時,會用到上篇博文中的例子。 思維導圖 概念解釋