1.硬件:Insta360 Link 2C摄像机
2.引用shader
Shader "Demo/ChromaKey"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_KeyColor("KeyColor", Color) = (0,1,0,0)
_TintColor("TintColor", Color) = (1,1,1,1)
_ColorCutoff("Cutoff", Range(0, 1)) = 0.2
_ColorFeathering("ColorFeathering", Range(0, 1)) = 0.33
_MaskFeathering("MaskFeathering", Range(0, 1)) = 1
_Sharpening("Sharpening", Range(0, 1)) = 0.5
_Despill("DespillStrength", Range(0, 1)) = 1
_DespillLuminanceAdd("DespillLuminanceAdd", Range(0, 1)) = 0.2
}
SubShader
{
Tags
{
// "RenderPipeline"="HDRenderPipeline"
// "RenderType"="HDUnlitShader"
"Queue" = "Transparent+1"
}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
cull off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 _MainTex_ST;
float4 _KeyColor;
float4 _TintColor;
float _ColorCutoff;
float _ColorFeathering;
float _MaskFeathering;
float _Sharpening;
float _Despill;
float _DespillLuminanceAdd;
// Utility functions -----------
float rgb2y(float3 c)
{
return (0.299 * c.r + 0.587 * c.g + 0.114 * c.b);
}
float rgb2cb(float3 c)
{
return (0.5 + -0.168736 * c.r - 0.331264 * c.g + 0.5 * c.b);
}
float rgb2cr(float3 c)
{
return (0.5 + 0.5 * c.r - 0.418688 * c.g - 0.081312 * c.b);
}
float colorclose(float Cb_p, float Cr_p, float Cb_key, float Cr_key, float tola, float tolb)
{
float temp = (Cb_key - Cb_p) * (Cb_key - Cb_p) + (Cr_key - Cr_p) * (Cr_key - Cr_p);
float tola2 = tola * tola;
float tolb2 = tolb * tolb;
if (temp < tola2) return (0);
if (temp < tolb2) return (temp - tola2) / (tolb2 - tola2);
return (1);
}
float maskedTex2D(sampler2D tex, float2 uv)
{
float4 color = tex2D(tex, uv);
// Chroma key to CYK conversion
float key_cb = rgb2cb(_KeyColor.rgb);
float key_cr = rgb2cr(_KeyColor.rgb);
float pix_cb = rgb2cb(color.rgb);
float pix_cr = rgb2cr(color.rgb);
return colorclose(pix_cb, pix_cr, key_cb, key_cr, _ColorCutoff, _ColorFeathering);
}
//-------------------------
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float4 frag(v2f i) : SV_Target
{
// Get pixel width
float2 pixelWidth = float2(1.0 / _MainTex_TexelSize.z, 0);
float2 pixelHeight = float2(0, 1.0 / _MainTex_TexelSize.w);
// Unmodified MainTex
float4 color = tex2D(_MainTex, i.uv);
// Unfeathered mask
float mask = maskedTex2D(_MainTex, i.uv);
// Feathering & smoothing
float c = mask;
float r = maskedTex2D(_MainTex, i.uv + pixelWidth);
float l = maskedTex2D(_MainTex, i.uv - pixelWidth);
float d = maskedTex2D(_MainTex, i.uv + pixelHeight);
float u = maskedTex2D(_MainTex, i.uv - pixelHeight);
float rd = maskedTex2D(_MainTex, i.uv + pixelWidth + pixelHeight) * .707;
float dl = maskedTex2D(_MainTex, i.uv - pixelWidth + pixelHeight) * .707;
float lu = maskedTex2D(_MainTex, i.uv - pixelHeight - pixelWidth) * .707;
float ur = maskedTex2D(_MainTex, i.uv + pixelWidth - pixelHeight) * .707;
float blurContribution = (r + l + d + u + rd + dl + lu + ur + c) * 0.12774655;
float smoothedMask = smoothstep(_Sharpening, 1, lerp(c, blurContribution, _MaskFeathering));
float4 result = color * smoothedMask;
// Despill
float v = (2 * result.b + result.r) / 4;
if (result.g > v) result.g = lerp(result.g, v, _Despill);
float4 dif = (color - result);
float desaturatedDif = rgb2y(dif.xyz);
result += lerp(0, desaturatedDif, _DespillLuminanceAdd);
return float4(result.xyz, smoothedMask) * _TintColor;
}
ENDCG
}
}
}
3.代码
public RawImage rawImage;//相机渲染的UI
private string WebCamName = @"Insta360 Virtual Camera";
private WebCamTexture webCamTexture;
void Start()
{
ToOpenCamera();
}
/// <summary>
/// 打开摄像机
/// </summary>
public void ToOpenCamera()
{
StartCoroutine("OpenCamera");
}
public IEnumerator OpenCamera()
{
int maxl = Screen.width;
if (Screen.height > Screen.width)
{
maxl = Screen.height;
}
// 申请摄像头权限
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
if (Application.HasUserAuthorization(UserAuthorization.WebCam))
{
if (webCamTexture != null)
{
webCamTexture.Stop();
}
// 监控第一次授权,是否获得到设备(因为很可能第一次授权了,但是获得不到设备,这里这样避免)
// 多次 都没有获得设备,可能就是真没有摄像头,结束获取 camera
int i = 0;
while (WebCamTexture.devices.Length <= 0 && 1 < 300)
{
yield return new WaitForEndOfFrame();
i++;
}
if (WebCamTexture.devices.Length <= 0)
{
Debug.LogError("没有摄像头设备,请检查");
}
else
{
webCamTexture = new WebCamTexture(WebCamName, maxl == Screen.height ? Screen.width : Screen.height, maxl, 30)
{
//使纹理平铺
wrapMode = TextureWrapMode.Repeat
};
// 渲染到 UI 或者 游戏物体上
if (rawImage != null)
{
rawImage.texture = webCamTexture;
}
webCamTexture.Play();
}
}
else
{
Debug.LogError("未获得读取摄像头权限");
}
}
private void OnApplicationPause(bool pause)
{
// 应用暂停的时候暂停camera,继续的时候继续使用
if (webCamTexture != null)
{
if (pause)
{
webCamTexture.Pause();
}
else
{
webCamTexture.Play();
}
}
}
private void OnDestroy()
{
if (webCamTexture != null)
{
webCamTexture.Stop();
}
}