兩種方法實(shí)現(xiàn)亮度/飽和度/對比度的調(diào)整!Cocos Creator !
效果預(yù)覽
uniform方案和assembler方案的實(shí)現(xiàn)。
GT 在Assembler 源碼解讀及使用 一文中提到自定義渲染可以實(shí)現(xiàn)很多酷炫的 shader 特效,目前常用的有兩種方法:
- 創(chuàng)建自定義材質(zhì),給材質(zhì)增加參數(shù)。這個(gè)參數(shù)會作為
uniform變量傳入 shader 由于渲染合批要求材質(zhì)參數(shù)保持一致,所以如果大量對象使用自定義材質(zhì)時(shí),并且材質(zhì)參數(shù)各不相同,是無法進(jìn)行合批渲染的,一個(gè)對象占一個(gè)draw call。 - 創(chuàng)建自定義
assembler,在頂點(diǎn)數(shù)據(jù)輸入渲染管道前修改它的值。
本文將用這兩種方案實(shí)現(xiàn)亮度/飽和度/對比度的調(diào)整。(注意效果圖中不同方式的draw call不同)
如何使用uniform 方案
新建 Sprite 組件,選擇材質(zhì) BrightSaturaContrastUniform.mtl ,添加用戶腳本 BrightSaturaContrastUniform.ts ,調(diào)整對應(yīng)參數(shù)即可。

assembler 方案
新建一個(gè)節(jié)點(diǎn),添加用戶腳本 BrightSaturaContrastAssemblerSprite.ts ,選擇材質(zhì) BrightSaturaContrastAssembler.mtl ,調(diào)整對應(yīng)參數(shù)即可。

調(diào)色效果的邏輯參考《Unity Shader入門精要》中的介紹。
亮度的調(diào)整只需要把原顏色乘以亮度系數(shù)
brightness即可。然后,我們計(jì)算該像素對應(yīng)的亮度值(luminance),這是通過對每個(gè)顏色分量乘以一個(gè)特定的系數(shù)再相加得到的。我們使用該亮度值創(chuàng)建了一個(gè)飽和度為0的顏色值,并使用saturation屬性在其和上一步得到的顏色之間進(jìn)行插值,從而得到希望的飽和度顏色。對比度的處理類似,我們首先創(chuàng)建一個(gè)對比度為0的顏色值(各分量均為0.5),再使用contrast屬性在其和上一步得到的顏色之間進(jìn)行插值,從而得到最終的處理結(jié)果。
uniform 方案
新建一個(gè) BrightSaturaContrastUniform.effect 。
在片元著色器中定義一個(gè) uniform 塊。
uniform lamyoung_com {
float brightness;
float saturation;
float constrast;
};
寫一個(gè)計(jì)算插值方法。
vec3 lerp(vec3 a, vec3 b, float w){
return a + w*(b-a);
}
參考《Unity Shader入門精要》中的介紹,翻譯一下計(jì)算過程即可,主要代碼如下。
CCTexture(texture, v_uv0, o);
// apply brightness
vec3 finnalColor = o.rgb * brightness;
// apply saturation
float luminance = 0.2125 * o.r + 0.7154 * o.g + 0.0721 * o.b;
vec3 luminanceColor = vec3(luminance, luminance, luminance);
finnalColor = lerp(luminanceColor, finnalColor, saturation);
// apply constrast
vec3 avgColor = vec3(0.5, 0.5, 0.5);
finnalColor = lerp(avgColor, finnalColor, constrast);
o.rgb = finnalColor.rgb;
接著新建材質(zhì) BrightSaturaContrastUniform.mtl,選擇 BrightSaturaContrastUniform.effect。

最后寫一個(gè) BrightSaturaContrastUniform.ts 腳本去控制 uniform 參數(shù),主要代碼如下。
this._sprite.getMaterial(0).setProperty('brightness',?this._brightness);
this._sprite.getMaterial(0).setProperty('saturation',?this._saturation);
this._sprite.getMaterial(0).setProperty('constrast',?this._constrast);
assembler 方案
shader
新建一個(gè) BrightSaturaContrastAssembler.effect 。
因?yàn)檫@里用的是頂點(diǎn)數(shù)據(jù),所以在頂點(diǎn)著色器中定義一些要傳入片元著色器的屬性。
in float a_brightness;
out float v_brightness;
in float a_saturation;
out float v_saturation;
in float a_constrast;
out float v_constrast;
并把這些屬性值傳給片元著色器。
v_brightness = a_brightness;
v_saturation = a_saturation;
v_constrast = a_constrast;
片元著色器接收這些屬性。
in float v_brightness;
in float v_saturation;
in float v_constrast;
在片元著色器的處理和uniform的類似。
CCTexture(texture, v_uv0, o);
// apply brightness
vec3 finnalColor = o.rgb * v_brightness;
// apply saturation
float luminance = 0.2125 * o.r + 0.7154 * o.g + 0.0721 * o.b;
vec3 luminanceColor = vec3(luminance, luminance, luminance);
finnalColor = lerp(luminanceColor, finnalColor, v_saturation);
// apply constrast
vec3 avgColor = vec3(0.5, 0.5, 0.5);
finnalColor = lerp(avgColor, finnalColor, v_constrast);
o.rgb = finnalColor.rgb;
新建材質(zhì) BrightSaturaContrastAssembler.mtl,選擇 BrightSaturaContrastAssembler.effect。
assembler
新建 BrightSaturaContrastAssembler.ts 繼承Assembler 源碼解讀及使用 中的 GTSimpleSpriteAssembler2D。
因?yàn)橐玫搅炼?飽和度/對比度這些屬性,所以定義頂點(diǎn)屬性的時(shí)候要加上這些屬性。
//?自定義頂點(diǎn)格式,在vfmtPosUvColor基礎(chǔ)上,加入?a_brightness??a_saturation??a_constrast
let?gfx?=?cc.gfx;
const?vfmtCustom?=?new?gfx.VertexFormat([
????{?name:?gfx.ATTR_POSITION,?type:?gfx.ATTR_TYPE_FLOAT32,?num:?2?},
????{?name:?gfx.ATTR_UV0,?type:?gfx.ATTR_TYPE_FLOAT32,?num:?2?},
????{?name:?gfx.ATTR_COLOR,?type:?gfx.ATTR_TYPE_UINT8,?num:?4,?normalize:?true?},
????{?name:?'a_brightness',?type:?gfx.ATTR_TYPE_FLOAT32,?num:?1?},
????{?name:?'a_saturation',?type:?gfx.ATTR_TYPE_FLOAT32,?num:?1?},
????{?name:?'a_constrast',?type:?gfx.ATTR_TYPE_FLOAT32,?num:?1?},
]);
更新頂點(diǎn)數(shù)據(jù)時(shí),只需要找到對應(yīng)的偏移量就可以了。
let?dstOffset;
let?verts?=?this._renderData.vDatas[0];
for?(let?i?=?0;?i?this.verticesCount;?++i)?{
????//?fill?
????let?floatsOffset?=?this.floatsPerVert?*?i;
????dstOffset?=?floatsOffset?+?this.brightnessOffset;
????verts[dstOffset]?=?this.brightness;
????dstOffset?=?floatsOffset?+?this.saturationOffset;
????verts[dstOffset]?=?this.saturation;
????dstOffset?=?floatsOffset?+?this.constrastOffset;
????verts[dstOffset]?=?this.constrast;
}
最后寫一個(gè) BrightSaturaContrastAssemblerSprite.ts 使用BrightSaturaContrastAssembler.ts,并在需要的時(shí)候更新數(shù)據(jù)。更新數(shù)據(jù)的代碼如下。
assembler.brightness?=?this.brightness;
assembler.constrast?=?this.constrast;
assembler.saturation?=?this.saturation;
this.setVertsDirty();
更多精彩小結(jié)需要注意的是
drawcall數(shù)量并不是越少越好,最佳性能往往是CPU與GPU負(fù)載均衡的結(jié)果。
以上為白玉無冰使用 Cocos Creator v2.4.0 實(shí)現(xiàn) "亮度/飽和度/對比度的調(diào)整" 的技術(shù)分享。歡迎分享給身邊的朋友!
任何行動(dòng)往往都比沒有行動(dòng)好,特別是當(dāng)你一直停滯在不愉快的情勢下很長時(shí)間的時(shí)候。如果這是一個(gè)錯(cuò)誤,至少你學(xué)到了一些東西。這樣一來,它就不再是一個(gè)錯(cuò)誤。如果你仍然選擇停滯不前,那么你就學(xué)不到任何東西。
做或者不做。

轉(zhuǎn)一轉(zhuǎn)

贊一贊

看一看



