实现 creator spine 根据灰度渐变着色

项目背景

想要将spine整体进行变色,大概效果如下图

效果分析

简单说就是将整体效果灰度化后,然后进行目标颜色的着色,具体着色算法为根据灰度值进行插值,也就是从mixColor->white渐变。

实现过程

像素灰度

算法想好了,接下来就开始实现, 先置灰

ini 复制代码
float gray = dot(vec3(finalColor.r, finalColor.g, finalColor.b), vec3(0.2126, 0.7152, 0.0722));
gray = max(min(1.0,gray),0.0);
finalColor.r = finalColor.g = finalColor.b = gray;
gl_FragColor = finalColor;

效果和预期的一致,变成了灰度图

着色

接下来就是着色

ini 复制代码
 float gray = dot(vec3(finalColor.r, finalColor.g, finalColor.b), vec3(0.2126, 0.7152, 0.0722));
 gray = max(min(1.0,gray),0.0);
 finalColor.r = mix(mixColor.r, 1.0, gray);
 finalColor.g = mix(mixColor.g, 1.0, gray);
 finalColor.b = mix(mixColor.b, 1.0, gray);
 gl_FragColor = finalColor;

发现透明区域出现了mixColor

这个很好理解,因为透明区域计算出来的gray为0,mix之后就是mixColor

discard处理透明区域

解决办法:可以将透明度为0的丢弃掉,这种办法会导致出现很多毛边

if ( finalColor.a <= 0.0 ) discard;

预乘出现黑边

所以废弃discard这种方案,可以采用alpha预乘

ini 复制代码
finalColor.r = mix(mixColor.r, 1.0, gray) * texColor.a;
finalColor.g = mix(mixColor.g, 1.0, gray) * texColor.a;
finalColor.b = mix(mixColor.b, 1.0, gray) * texColor.a;

可以看到效果有明显的提升,但是发现嘴巴附近有黑边,这个黑边主要就是来自边缘的过渡色

ALPHA_TEST

ALPHA_TEST可以缓解这个问题,但是会带来锯齿问题

因为ALPHA_TEST本质也是discard

c 复制代码
#if USE_ALPHA_TEST 
    uniform float alphaThreshold; 
#endif 

void ALPHA_TEST (in vec4 color) 
{ 
#if USE_ALPHA_TEST 
    if (color.a < alphaThreshold) discard; 
#endif 
}

void ALPHA_TEST (in float alpha) 
{ 
#if USE_ALPHA_TEST 
    if (alpha < alphaThreshold) discard;
#endif 
}

基于源纹理处理

如果再顺着这个思路解决下去,好像到了死胡同,卡了我好几天,最后还是热心网友大华的帮助,顺利解决了这个问题,感谢大华哥

以上的所有处理都是基于最终计算(finalColor)的颜色处理的,再次理清需求,发现我们要基于纹理的颜色处理。

ini 复制代码
 float gray = dot(vec3(texColor.r,texColor.g, texColor.b), vec3(0.2126, 0.7152, 0.0722));
 gray = max(min(1.0,gray),0.0);
 float r = mix(mixColor.r, 1.0, gray);
 float g = mix(mixColor.g, 1.0, gray);
 float b = mix(mixColor.b, 1.0, gray);
 vec3 grayColor = vec3(r,g,b) * texColor.a; // 预乘
 finalColor = vec4(grayColor, texColor.a);

发现嘴巴部分还是有黑边

spine 纹理alpha预乘

检查完毕逻辑,发现的确算法是符合预期的,那么问题只可能出在纹理上,在spine中有这个选项,可以将输出的纹理预乘。

尝试还原下纹理颜色,基于纹理真实的颜色进行灰度

ini 复制代码
vec3 color = texColor.rgb / texColor.a;
float gray = dot(color, vec3(0.2126, 0.7152, 0.0722));

至此,黑边也消失了,效果也就符合我们的预期了

v_light 处理

最后,我们还需要还原spine原有的颜色处理逻辑,也就是要增加灯光的处理。

下图是v_light的不同效果,可以看到阴影处的不同,没有按照预期着色

解决办法也简单,对原始颜色处理下v_light就可以了

其他地方的预乘

spine组件的预乘

查看引擎源码,你会发现这个预乘是作用于blend的

js 复制代码
let srcBlendFactor = this.premultipliedAlpha 
    ? cc.gfx.BLEND_ONE 
    : cc.gfx.BLEND_SRC_ALPHA;
let dstBlendFactor = cc.gfx.BLEND_ONE_MINUS_SRC_ALPHA;
baseMaterial.setBlend(
    true,
    cc.gfx.BLEND_FUNC_ADD,
    srcBlendFactor, srcBlendFactor,
    cc.gfx.BLEND_FUNC_ADD,
    dstBlendFactor, dstBlendFactor
);

图片资源的预乘属性

和spine的预乘一个道理,都是对纹理图片的修改

预乘的意义

Premultiplied Alpha 最重要的意义是使得带透明度图片纹理可以正常的进行线性插值

相关推荐
孔令飞5 小时前
Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中
前端
溪语流沙6 小时前
【Web全栈进阶】PostgreSQL上手:Docker跑库 + 把早报站从SQLite迁过去
前端·docker·postgresql
IT_陈寒6 小时前
SpringBoot自动配置的坑:你以为的捷径可能是弯路
前端·人工智能·后端
paopaokaka_luck6 小时前
高校社团管理(AI辅助任务分配、协同过滤算法推荐、ECharts数据可视化、活动参与闭环、校园交流与反馈、器材借还管理)
java·前端·javascript·spring boot·数据分析·echarts
Dovis(誓平步青云)6 小时前
导览音频切换太快,旧讲解不能覆盖新展品
android·前端·javascript·ecmascript·音视频·宠物
福兮说17 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理17 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
小呆呆66618 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
Dovis(誓平步青云)18 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan19 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js