注:此處所說Cocos creator版本為3.X,和其他版本會(huì)有區(qū)別。
Cocos effect是基于opengl的,使用glsl語(yǔ)法和函數(shù)。但是經(jīng)過了cocos進(jìn)行封裝,所以一般看不到main函數(shù),直接寫關(guān)鍵函數(shù)即可。點(diǎn)擊寫好的effect,在Cocos creator屬性面板可以看到生成的完整代碼。
effect一般會(huì)有三個(gè)部分:
- CCEffect 聲明部分
- CCProgram vs 頂點(diǎn)著色器
- CCProgram fs 片段著色器
CCEffect中每個(gè)passes都需要指定頂點(diǎn)著色器和片段著色器,一般都是vs:vert和fs:frag兩個(gè)函數(shù)。而CCProgram就是具體實(shí)現(xiàn)了。
聲明部分可以參考官方文檔,這部分文檔還算全面,在此就不再贅述。下面主要介紹頂點(diǎn)著色器。
頂點(diǎn)著色器有2個(gè)參數(shù),a_position和a_color。如果有紋理的話,還會(huì)多個(gè)a_texCoord參數(shù)。a_position是世界坐標(biāo),a_color是設(shè)定的渲染顏色(如果是sprite,可以看到屬性面板有個(gè)color屬性,就是這個(gè)),a_texCoord是當(dāng)前點(diǎn)對(duì)應(yīng)紋理的位置。
一般來(lái)說,世界坐標(biāo)是無(wú)法直接使用的,需要轉(zhuǎn)換成視圖投影(你可以理解成,世界坐標(biāo)需要轉(zhuǎn)換成攝像頭坐標(biāo),攝像頭坐標(biāo)的(0,0)代表屏幕中間。ccc是這么定的。)我們需要引用#include <cc-global>,得到視圖投影矩陣cc_matViewProj,返回cc_matViewProj * pos即可完成頂點(diǎn)著色器。
注意:這是2D情況,3D還需要引用#include <cc-local>得到模型空間轉(zhuǎn)世界空間矩陣cc_matWorld,再乘以這個(gè)。而2D情況下不能引用這個(gè)文件,否則會(huì)報(bào)錯(cuò)。
片段著色器是核心部分,一般要做什么效果都要在這里寫。如果只是單純的顯示圖片,return texture(cc_spriteTexture, uv);即可。texture函數(shù)會(huì)把圖片當(dāng)前位置的顏色返回出來(lái),提供給片段著色器完成渲染。其他更復(fù)雜的處理就看后續(xù)學(xué)習(xí)了。
下面是基于 陳皮皮寫的某個(gè)effect進(jìn)行適配的示例,原始文件在這里
CCEffect %{
techniques:
- passes:
- vert: vs:vert
frag: fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendDstAlpha: one_minus_src_alpha
rasterizerState:
cullMode: none
properties:
center: { value: [0.5, 0.5], editor: { tooltip: '模糊中心點(diǎn)' } }
strength: { value: 0.03, editor: { tooltip: '模糊強(qiáng)度' } }
}%
CCProgram vs %{
precision highp float;
#include <cc-global>
in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;
out vec2 v_uv0;
vec4 vert () {
vec4 pos = vec4(a_position, 1);
pos = cc_matViewProj * pos;
v_uv0 = a_texCoord;
return pos;
}
}%
CCProgram fs %{
precision highp float;
in vec2 v_uv0;
#pragma builtin(local)
layout(set = 2, binding = 10) uniform sampler2D cc_spriteTexture;
//定義文件里寫的屬性可以這樣獲取
uniform Properties {
vec2 center;
float strength;
};
// 獲取徑向模糊顏色
vec4 getRadialBlurColor(vec2 coord) {
// 偏移
vec2 offset = coord.xy - center;
// 采樣次數(shù)
const int samples = 10;
// 強(qiáng)度
float perStrength = strength / float(samples - 1);
// 采樣
vec4 color = vec4(0.0);
for(int i = 0; i < samples; i++) {
vec2 uv = offset * (1.0 + (float(i) * perStrength)) + center;
color += texture(cc_spriteTexture, uv);
}
color /= float(samples);
// 完成
return color;
}
vec4 frag () {
vec4 o = vec4(1, 1, 1, 1);
o *= getRadialBlurColor(v_uv0);
return o;
}
}%