最近在cocos creator上打算寫個U3D中shader功能的插件(能在屬性面板調整shader屬性)。
對其中一個功能有點疑惑,就是U3D中一個渲染物體上可以掛多個材質,后來查詢了下,一個物體上掛多個材質的時候,每個材質負責渲染對應的子mesh,但如果一個object只有一個mesh時,
那么掛載在其下的所有材質都會作用在這個mesh上,達到了混合的作用。(實際上,Unity並不建議將多個材質作用於同一個mesh上,官方建議的做法是通過多個shader pass解決多種shader效果需求)
但是在OpenGl渲染中,每次渲染只能用一個shader,而每個物體也只能掛一個shader被渲染。
因此不能直接給一個物體掛多個着色器,當初我第一時刻想到的,就是shader文件混合,比如將兩個着色器的main函數里的內容混合在一起,然后分別將計算結果加起來賦予到output。
今天偶然逛到一個網站,是一個類似ShaderToy的網站,能在線編輯Shder並演示(說白了就是Webgl),不過這個網站除了能在線寫glsl代碼,還有一個比較好玩的功能,就是可視化編輯shader
這個功能很簡單,就是可以將多個代碼實現的shader作為節點,組合成一個新的shader,當然,目前版本比較簡單,只提供加減乘除等基礎操作。
仔細一想,這個功能不就跟我想要的shader混合一樣么?仔細做了個試驗,發現他的混合實現果然是跟我想的一樣。
首先,我在這個網站寫了兩個非常簡單的着色器:
Shader 1:
Shader 2:
組合Shader:
將這個組合Shader導出后,查看它的Shader文件:
// 片段着色器
precision highp float; precision highp int; uniform vec3 color; vec4 Simple_Shader_11475135391321_521_main() { vec4 Simple_Shader_11475135391321_521_gl_FragColor = vec4(0.0); Simple_Shader_11475135391321_521_gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4); return Simple_Shader_11475135391321_521_gl_FragColor *= 1.0; } vec4 Simple_Shader_21475135525837_573_main() { vec4 Simple_Shader_21475135525837_573_gl_FragColor = vec4(0.0); Simple_Shader_21475135525837_573_gl_FragColor = vec4(color, 1.0); return Simple_Shader_21475135525837_573_gl_FragColor *= 1.0; } void main() { gl_FragColor = (Simple_Shader_11475135391321_521_main() + Simple_Shader_21475135525837_573_main()); } // 頂點着色器 precision highp float; precision highp int; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; attribute vec3 position; vec4 Simple_Shader_11475135391321_521_main() { vec4 Simple_Shader_11475135391321_521_gl_Position = vec4(0.0); Simple_Shader_11475135391321_521_gl_Position = vec4(position, 1.0); return Simple_Shader_11475135391321_521_gl_Position *= 1.0; } vec4 Simple_Shader_21475135525837_573_main() { vec4 Simple_Shader_21475135525837_573_gl_Position = vec4(0.0); Simple_Shader_21475135525837_573_gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); return Simple_Shader_21475135525837_573_gl_Position *= 1.0; } void main() { gl_Position = Simple_Shader_11475135391321_521_main() + Simple_Shader_21475135525837_573_main(); }
果然不出所料,拿頂點着色器來說,首先提取兩個着色器的變量並放在一起,並剔除重復的,然后將兩個shader各自的main提取為一個子函數,並將之前的gl_Position替換為renturn,然后在main中將這個兩個函數的返回值加起來,達到混合的目的,當然,他還加入了縮放因子控制混合比例。
非常簡單粗暴。
而且這種做法,還能將drawcall控制為一個,unity我不知道他的實現原理,不過就目前來看,添加多個着色器,會導致dc相應增加,應該不是用這種做法。