引擎版本:3.8.5
您好,我是鶴九日!
回顧
稍微回顧下前面兩篇博客講解的內容:
一、Cocos渲染效果的實現需要Material材質和Effect資源的互相配合。
二、Effect資源負責Shader片段的編寫和屬性配置,Material材質負責對Effect資源的包裝和可視化調整。
三、官方引擎使用的是OpenGL ES渲染,語言是類C語言的GLSL。
四、在可編程渲染管線中用戶只需關注頂點著色器和片段著色器的編寫,頂點著色器用于坐標轉換,片段著色器用于著色。
學習Shader,我們需要做到:遵循引擎設定規則,按照官方要求規范,才能更好的理解、使用Shader。
簡介
上篇文章中,我們介紹了下OpenGL的渲染流程和GLSL的一些語法,主要為了能夠理解著色器的一些流程原理。
但是這些內容,在引擎的設定規則中:Shader著色器代碼相關,僅屬于Effect資源配置的一部分。
Effect資源,結構主要有兩部分:
一、借助 GLSL 類C語言,實現頂點、片段著色器的部分代碼編寫,通過CCProgram
來配置。
二、借助 YAML 類Json語言,聲明的渲染流程的一些屬性參數,通過CCEffect
來配置。
兩部分內容互相補充,才能共同構建一個完整的渲染流程描述,這樣的描述才能被Material材質資源使用。
Effect資源的大概結構如下:
CCEffect %{// 渲染技術、過程、狀態、材質和屬性參數的配置
}CCProgram sprite-vs %{// 頂點著色器的片段代碼
}%CCProgram sprite-fs %{// 片段著色器的片段代碼
}%
CCEffect %{}%
實現渲染參數配置相關CCProgram %{}%
實現著色器片段代碼邏輯
今天的內容,講解關于Effect資源下的流程配置參數,即CCEffect
。
理解了它,再結合著色器片段代碼,我們便理解:Material材質對Effect包裝后,通過屬性檢查器的一些屬性展示,以及后續如何通過代碼來配置自定義的屬性參數。
注:能力有限,理解可能有誤,期待您的諒解,并歡迎您的指出,感謝。
YAML
CCEffect的配置是通過YAML實現的,它是一種數據序列化格式,主要用于配置文件、數據交換等。
特點:簡潔易讀、層次結構清晰,支持多種數據類型,兼容性強,可轉換為Json、XML、CSV等。
剛開始學習的階段,YAML語言看似對初學者是不友好的。
還好,官方的引擎采用的是YAML 1.2標準的解析器,我們也能使用JSON進行配置,只是JSON的配置難免會繁瑣些。
以builtin-sprite.effect為例,看下官方內置的Effect屬性配置。
路徑:../internal/effects/builtin-sprite.effect
CCEffect %{techniques:- passes:- vert: sprite-vs:vertfrag: sprite-fs:fragdepthStencilState:depthTest: falsedepthWrite: falseblendState:targets:- blend: trueblendSrc: src_alphablendDst: one_minus_src_alphablendDstAlpha: one_minus_src_alpharasterizerState:cullMode: noneproperties:alphaThreshold: { value: 0.5 }
}%
將它轉換為Json內容:
這樣的對比,是否能看清晰的看到YAML和JSON的區別呢。工具相關
https://www.lddgo.net/convert/yaml-to-json : 沒有廣告,但不支持XML、CSV的轉換
https://codebeautify.org/yaml-to-json-xml-csv:功能強大,但有廣告
特性
YAML語言,真正的強大不是簡潔,而是是引用和繼承。
先以官方文檔的示例演示下:
-
引用的主要結構是:
&name
和*name
-
繼承的主要結構是:
&name
和<<: *name
再以builtin-unit.effect的部分配置為例:
路徑:../internal/effects/builtin-unit.effect
注: 右側便是最下面引用的數據字段
引用和繼承,這兩個特性是可以實現對配置的復用的。
語法
YAML的語法,沒有想象中的那么難,只是新的東西,恐懼讓我們畏難而已。
注意:千萬不要將CCEffect的參數設置認定為語法的組成部分,我當時就是這么想的,愁壞我了…
語法相關,主要內容相關如下:
一、行首的空格代表數據的層級
二、所有的引號、逗號都可以省略,但空格和冒號不可省略
三、以減號加空格開頭的,表示數組元素
四、引用的主要結構是: &name
和 *name
五、繼承的主要結構是:&name
和 <<: *name
這就夠用了。
屬性結構
YAML語法的使用,主要是用于配置渲染的屬性參數,這些參數類型可以這樣劃分:
一、以techniques命名的渲染技術, CocosShader定義的重要概念
二、以passes命名的渲染過程, CocosShader定義的重要概念
每個渲染過程 pass 主要包括的參數有:
-
必備參數:頂點、片段著色器的名字配置
-
可選參數:著色器不同狀態的設置,比如深度、模板、混合模式、光柵化等
-
可選參數:自定義屬性參數的配置,主要用于
uniform
或材質中屬性的調整
簡單的理解:渲染技術用于實現不同的渲染模式,渲染過程用于配置不同渲染模式下的參數和屬性。
渲染技術可定義多個,每個渲染技術可包含多個渲染過程,每個渲染過程必須帶有頂點和片段著色器的配置。
這就是YAML配置下的整體CCEffect的結構。
以bultin-sprite.effect為例, 配置屬性如下:
注:如果渲染技術只有一個,name名字可忽略
CCEffect %{# 聲明渲染技術techniques:# 聲明渲染流程- passes:# 聲明頂點、片段著色器名和入口名 - vert: sprite-vs:vertfrag: sprite-fs:frag# 設置深度、模板測試的狀態depthStencilState:depthTest: falsedepthWrite: false# 設置混合模式blendState:targets:- blend: trueblendSrc: src_alphablendDst: one_minus_src_alphablendDstAlpha: one_minus_src_alpha# 設置光柵化狀態rasterizerState:cullMode: none# 自定義屬性properties:alphaThreshold: { value: 0.5 }
}%
注:在學習2D shader的過程中,此屬性結構除了properties自定義屬性外,大多為通用性配置。
接下來,我們簡要說明下每塊的屬性相關。
渲染技術(Technique)
渲染技術是Cocos Shader定義的一個重要概念,用于描述渲染過程(pass)的整體結構和配置。
多個渲染技術存在的情況下,每個渲染技術都必須特定的名稱(name),用于標記渲染技術的用途,CCEffect配置支持定義多個,但實際的應用只能有一個。
Cocos引擎,這樣的設計目的可能是:
一、通過定義多個不同技術,用于實現不同的渲染模式。就如builtin-unlit.effect
中包含四種技術:
- opaque 用于渲染不透明物體
- transparent 用于渲染半透明物體
- add 采用加法混合模式,渲染半透明物體
- alpha-blend 采用透明混合模式,渲染半透明物體
二、滿足不同場景的需求,優化性能,避免不必要的計算和渲染開銷。
三、作為跨平臺引擎,用于滿足不同平臺的特性
在Material材質的屬性檢查器中,通過Technique 便可選擇不同類型的渲染技術。
渲染過程(Pass)
它同樣是Cocos Shader定義的一個重要概念,它主要用于定義和配置對象的渲染狀態和屬性。
每一個Pass都是一個獨立的渲染指令集合,在每個渲染技術(technique)中,可包含多個。
每個渲染過程(pass)都必須配置vert
和frag
的名字和入口參數,其它都是可選。
注:名字和入口,可以是文件中CCProgram聲明的,也可以是引擎提供的標準頭文件相關
比如:我們創建的無光照effect文件,它的頂點著色器就是引用的引擎提供的:
techniques:- name: opaquepasses:# 引擎提供的通用性片段相關,在引擎中這些封裝被稱為Chunks- vert: legacy/main-functions/general-vs:vert # builtin header]# Effect資源配置文件下的內部定義frag: unlit-fs:frag...
注:自定義的著色器入口名不要使用main,因為引擎編譯的時候會自動添加main作為渲染的入口
在CocosShader的渲染中,渲染過程是按照順序依次執行的,組合起來便是復雜的渲染效果。
以builtin-unlit.effect的opaque渲染技術為例:
- Pass 0: 基礎渲染,用于渲染不透明物體的主體部分
- Pass 1: 平面陰影渲染,用于在場景中添加簡單的陰影效果。
- Pass 2: 延遲前向渲染
渲染管線狀態
渲染過程(pass)中配置一些參數,比如:光柵化、混合模式、深度和模版測試等,這些又被官方稱為PipelineStates。
更多的參數說明可參考官方文檔:PipelineStates
這里簡單羅列三個:
一、DepthStencilState 光柵化時的可選渲染狀態
二、RasterizerState 深度和模板緩存的測試與狀態
三、BlendState 材質混合狀態
# 配置深度、模板測試depthStencilState:# 禁用深度測試,它用于判斷一個像素是否被其他像素遮擋depthTest: false# 禁用深度寫入depthWrite: false# 配置透明混合狀態blendState:targets:# 啟用混合模式# 這種混合模式是最常見的 透明度混合模式,公式為:# Final Color = SrcColor * SrcAlpha + DstColor * (1 - SrcAlpha)# 它適用于常見的半透明效果,例如透明紋理、UI元素等。- blend: true# 源因子設置為 src_alpha,表示使用片段顏色的 alpha 值作為混合因子blendSrc: src_alpha# 目標因子設置為 one_minus_src_alpha,表示使用 1 - src_alpha 作為混合因子blendDst: one_minus_src_alphablendDstAlpha: one_minus_src_alpha# 配置光柵器狀態rasterizerState:# 禁用面剔除,常見參數有:front, back, nonecullMode: none
注:能力有限,后續的學習再逐漸的補充原理相關…
屬性參數(properties)
屬性參數在CCEffect
配置中,簡單可理解為:
一、定義著色器中的unifrom變量,用于處理著色器的實現邏輯。
二、在Material的屬性檢查器中顯示,用于Shader效果的可視化調整。
雖然是自定義,但畢竟涉及到Shader的實現和可視化。除了通用的屬性值:value 以外,我們可以將其分為兩部分:
注:更多參數可參考:Property 參數列表
一、samples 紋理相關
二、editor參數
主要應用于編譯器的屬性檢查器中, 主要屬性有:
簡單的示例:
lightCenterPoint: { value: [0.2, 0.2], editor: { tooltip: "光束中心點坐標" }}
lightAngle: { value: 36.0, editor: { tooltip: "光束傾斜角度" }}
最后
今天的文章內容大概就說到這里了,內容相關部分參考了官方文檔的一些說明,主要有:
著色器語法 :文檔內容主要講解的是Effect資源的配置結構
Pass可選配置參數: 文檔內容主要對Pass渲染中的參數進行了詳細的說明
YAML 語法:主要說明了YAML語法的使用
不瞞您說,Shader的基礎理論的確枯燥無味,然而又不得不懂,學習的過程中,好奇是雖然都存在的,我們都一樣。
就看能不能熬下去了,這里想說兩點:
一、為自己的能力不足,不能為您深入講解感到抱歉
二、期待與您一起在學習的路上變的強大
我是鶴九日,祝您生活愉快!