需求背景:产品希望美术只输出一份素材,比如一棵树,程序渲染出不同的美术效果,实现春/夏/秋/冬/低等级/高等级等不同的情况。
技术方案:目前想到的是通过 shader模拟实现类似ps的 调整色相/饱和度/色彩平衡/亮度/对比度等算法,最终修改像素颜色实现。
问题:请教各位大佬,shader是实时计算渲染的,这个在性能上是否可行?
模拟这个场景测试:
200 draw call 图片平均尺寸 505*505
小米11pro 微信扫码: 原图fps约50-60 shader处理的fps约36-37
iphone12pro 微信扫码: 原图fps约42-47 shader处理的fps约25-32
个人认为加了shader处理的这个实时性能有点勉强,因为现在是项目初期,不好预测最终 同屏会达到多少drawcall。
如果实时渲染性能上无法满足,设想的一种方法是,把shader处理1次的图片存储在本地(手机存储卡上),下次读取就直接用处理过的图片显示出来。这种方案是否存在什么弊端或风险?
shader处理的大概算法如下:
vec3 liangDuDuiBiDu(in vec4 co,float B,float C){
B = B / 200.;
C = C / 200.;
B = B + 1.;
C = C + 1.;
vec3 finnalColor = co.rgb * B;
float luminance = 0.2125 * co.r + 0.7154 * co.g + 0.0721 * co.b;
vec3 luminanceColor = vec3(luminance);
finnalColor = lerp(luminanceColor,finnalColor,1.);
vec3 avgColor = vec3(0.5);
finnalColor = lerp(avgColor,finnalColor,C);
return finnalColor;
}
vec3 seCaiPingHeng(in vec4 coA, vec3 yy, vec3 zj, vec3 gg){
float BB = 255.;
vec3 u_shadows = vec3(yy[0]/BB, yy[1]/BB, yy[2]/BB); // 阴影的色彩平衡调整量
vec3 u_midtones = vec3(zj[0]/BB, zj[1]/BB, zj[2]/BB); // 中间调的色彩平衡调整量
vec3 u_highlights = vec3(gg[0]/BB, gg[1]/BB, gg[2]/BB); // 高光的色彩平衡调整量
// 阴影、中间调、高光的分界点
float SHADOWS_THRESHOLD = 0.3333;
float HIGHLIGHTS_THRESHOLD = 0.6666;
// 计算亮度(Luminance)
float luminance = 0.2126 * coA.r + 0.7152 * coA.g + 0.0722 * coA.b;
// 定义色彩调整的权重
vec3 adjustment = vec3(0.0);
float weight = 0.0;
// 判断亮度区域并应用不同的色彩平衡调整
if (luminance < SHADOWS_THRESHOLD) {
// 阴影部分
weight = smoothstep(0.0, SHADOWS_THRESHOLD, luminance);
adjustment = u_shadows; // 应用阴影调整 + vec3(0.0,1.0,1.0)
}
else if (luminance < HIGHLIGHTS_THRESHOLD) {
// 中间调部分
weight = smoothstep(SHADOWS_THRESHOLD, HIGHLIGHTS_THRESHOLD, luminance);
adjustment = u_midtones; // 应用中间调调整 + vec3(1.0,0.0,1.0)
}
else {
// 高光部分
weight = smoothstep(HIGHLIGHTS_THRESHOLD, 1.0, luminance);
adjustment = u_highlights; // 应用高光调整 + vec3(1.0,1.0,0.0)
}
// 应用色彩平衡调整
vec3 rgb = coA.rgb;
vec3 balancedColor = mix(rgb, rgb + adjustment, weight);
// 保持亮度不变(可选),避免颜色反转
float originalLuminance = calculateLuminance(rgb);
float newLuminance = calculateLuminance(balancedColor);
balancedColor.rgb *= originalLuminance / (newLuminance + 0.0001); // 防止除0
return balancedColor; }