在Android用vulkan完成蓝绿幕扣像

Chroma Key
如上所说,项目对接外部实现的vulkan层是否方便,在这重新生成一个模块aoce_vulkan_extra,在这我选择UE4 Matting里的逻辑来测试,因为这个逻辑非常简单,也算让我对手机的性能有个初步的了解。

首先把相关逻辑整理下,UE4上有相关节点,看下实现整理成glsl compute shader实现。

#version 450

// https://www.unrealengine.com/en-US/tech-blog/setting-up-a-chroma-key-material-in-ue4

layout (local_size_x = 16, local_size_y = 16) in;// gl_WorkGroupSize
layout (binding = 0, rgba8) uniform readonly image2D inTex;
layout (binding = 1, rgba8) uniform image2D outTex;

layout (std140, binding = 2) uniform UBO {
// 0.2 控制亮度的强度系数
float lumaMask;
float chromaColorX;
float chromaColorY;
float chromaColorZ;
// 用环境光补受蓝绿幕影响的像素(简单理解扣像结果要放入的环境光的颜色)
float ambientScale;
float ambientColorX;
float ambientColorY;
float ambientColorZ;
// 0.4
float alphaCutoffMin;
// 0.5
float alphaCutoffMax;
float alphaExponent;
// 0.8
float despillCuttofMax;
float despillExponent;
} ubo;

const float PI = 3.1415926;

vec3 extractColor(vec3 color,float lumaMask){
float luma = dot(color,vec3(1.0f));
// 亮度指数
float colorMask = exp(-luma2PI/lumaMask);
// color*(1-colorMask)+color*luma
color = mix(color,vec3(luma),colorMask);
// 生成基于亮度的饱和度图
return color / dot(color,vec3(2.0));
}

void main(){
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(outTex);
if(uv.x >= size.x || uv.y >= size.y){
return;
}
vec3 inputColor = imageLoad(inTex,uv).rgb;
vec3 chromaColor = vec3(ubo.chromaColorX,ubo.chromaColorY,ubo.chromaColorZ);
vec3 ambientColor = vec3(ubo.ambientColorX,ubo.ambientColorY,ubo.ambientColorZ);
vec3 color1 = extractColor(chromaColor,ubo.lumaMask);
vec3 color2 = extractColor(inputColor,ubo.lumaMask);
vec3 subColor = color1 - color2;
float diffSize = length(subColor);
float minClamp = diffSize-ubo.alphaCutoffMin;
float dist = ubo.alphaCutoffMax - ubo.alphaCutoffMin;
// 扣像alpha
float alpha= clamp(pow(max(minClamp/dist,0),ubo.alphaExponent),0.0,1.0);
// 受扣像背景影响的颜色alpha
float inputClamp = ubo.despillCuttofMax - ubo.alphaCutoffMin;
float despillAlpha = 1.0f- clamp(pow(max(minClamp/inputClamp,0),ubo.despillExponent),0.0,1.0);
// 亮度系数
vec3 lumaFactor = vec3(0.3f,0.59f,0.11f);
// 添加环境光收益
vec3 dcolor = inputColorlumaFactorambientColorubo.ambientScaledespillAlpha;
// 去除扣像背景
dcolor -= inputColorchromaColordespillAlpha;
dcolor += inputColor;
// 为了显示查看效果,后面屏蔽
dcolor = inputColoralpha + ambientColor(1.0-alpha);
imageStore(outTex,uv,vec4(dcolor,alpha));
}
这里面代码最后倒数第二句实现混合背景时去掉,在这只是为了显示查看效果。

然后引用aoce_vulkan里给的基类VkLayer,根据接口完成本身具体实现,相关VkChromKeyLayer的实现可以说是非常简单,至少我认为达到我想要的方便。

还是一样,先说遇到的坑,

开始在glsl中的UBO,我特意把一个float,vec3放一起,想当然的认为是按照vec4排列,这里注意,vec3不管前后接什么,大部分结构定义下,都至少占vec4,所以后面为了和C++结构align一样,全部用float.

层启用/不启用会导致整个运算graph重置,一般情况下,运算线程与结果输出线程不在一起,在重置时,运算线程相关资源会重新生成,而此时输出线程还在使用相关资源就会导致device lost错误,在这使用VkEvent用来表示是否在资源重置中。

然后就是与android UI层对接,android的UI没怎么用过,丑也就先这样吧。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部