原文
歡迎訪問我的個人主頁了解更多關於OpenGL的知識
前言
GLSL是OpenGL的著色語言,在編寫GLSL的過程中,復用代碼是一件比較麻煩的事情,GLSL基本是不支持#include預編譯指令的。
目前我已知的OpenGL對於GLSL include的支持僅限於擴展ARB_shading_language_include,如果你的系統支持該OpenGL擴展,那麼你就可以在GLSL中使用include。不過似乎只有nvidia的OpenGL驅動對它有支持。
復用GLSL代碼的級別
既然官方的include使用如此艱難,我們就來自己造輪子吧。首先我們要確定在什麼級別復用代碼。有兩種選擇:
程序代碼運行時將可復用的GLSL代碼塊合並成可運行的GLSL代碼。
程序編譯時跑一個腳本,將可復用的GLSL代碼合並成可運行的GLSL文件,然後在運行時使用生成好的GLSL文件。
我之前嘗試過第一種方法,運行時合並GLSL代碼,不過調試不是很方便,報錯時不好定位到哪行,而且運行時生成終究會消耗一些性能。所以這一次我打算探索第二條路。
預編譯工具m4
在研究第二種方式時,碰巧找到了一個非常符合解決本次問題的工具m4。m4說白的就是一個預編譯工具,將寫有宏的文本進行預編譯展開。如果你使用Mac。在終端輸入
m4 --version
如果得到如下,恭喜你,你已經擁有了此工具。
GNU M4 1.4.6 Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Written by Rene' Seindal.
當然你也可能是其他版本。如果沒有出現,你可以使用homebrew安裝。
brew install m4
如果你喜歡使用源碼安裝,可以訪問m4的官網。
m4的使用示例
我們先來寫一個例子來感受一下m4的功能。在同一個目錄下創建2個文件,Test.m4和inc.m4。
在inc.m4中輸入下面內容。
這裡是被包含的內容
在Test.m4中我們做兩件事情,包含inc.m4,定義一個變量。
include(`inc.m4') define(`content', `例子') 這是一個content
注意,inc.m4左邊不是單引號,是`,右邊是單引號。content和 例子也是一樣。include(`inc.m4')將inc.m4包含到Test.m4中,define(`content', `例子')將例子這個值賦給content。我們使用m4預處理一下看看結果。在終端運行。
m4 Test.m4
結果如下。
這裡是被包含的內容 這是一個例子
將m4運用於GLSL
下面是我的一個GLSL程序結構目錄,我使用m4將這些復用代碼合並到一起。
這裡我寫了兩個光照模型,lambert_phong和lambert_blinn,它們大部分代碼都是一樣的,只有高光部分代碼不一樣。targets文件夾下是最終被m4處理的文件。處理完後直接被OpenGL使用。我們看一下其中的一個文件frag_lambert_phong.glsl。
// defines include(`fragment shader components/frag_base_header.glsl') include(`fragment shader components/frag_structs.glsl') include(`fragment shader components/frag_in_vars.glsl') include(`fragment shader components/frag_uniform_vars.glsl') // functions include(`fragment shader components/frag_normal.glsl') include(`fragment shader components/frag_light_base.glsl') include(`fragment shader components/frag_light_lambert.glsl') include(`fragment shader components/frag_light_phong.glsl') // light model include(`fragment shader light model/frag_light_model_lambert_phong.glsl')
其實我只用到了m4的include功能,我們將這個文件和frag_lambert_blinn對比一下。
// defines include(`fragment shader components/frag_base_header.glsl') include(`fragment shader components/frag_structs.glsl') include(`fragment shader components/frag_in_vars.glsl') include(`fragment shader components/frag_uniform_vars.glsl') // functions include(`fragment shader components/frag_normal.glsl') include(`fragment shader components/frag_light_base.glsl') include(`fragment shader components/frag_light_lambert.glsl') include(`fragment shader components/frag_light_blinn.glsl') // light model include(`fragment shader light model/frag_light_model_lambert_blinn.glsl')
只有最後兩個include不一樣,很好的滿足了我復用GLSL的需求。最後我寫了一個簡單的腳本批量處理targets下的文件。
#!env python import os import subprocess target_files = os.listdir("./targets") for file in target_files: print("building " + file + "...") command = str.format("m4 ./targets/{0} > ../{0}", file) subprocess.call(command, shell=True) print(file + " build finish.")
將這個腳本集成到你的編譯系統中,就可以做到完全自動化復用和預處理GLSL了。
作者:handyTOOL
鏈接:http://www.jianshu.com/p/960337be3547
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。