最近公司要求做一个抠图程序,作者想到接一个百度AI来实现抠图,做出来之后效果不是太好,然后领导说想要实时抠图,让用户现场体验更好些,没办法,只能推倒重来,然后在网上找个shader,然后自己改改,就实现了。
首先是shader代码
Shader "UniversalChromaKey" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Sens ("Sensibilidad", Range (0,.9)) = .3
_Cutoff ("Recorte", Range (0,.9)) = .2
_Color ("Chroma", Color) = (0, 1.0, 0)
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert alpha
sampler2D _MainTex;
float _Cutoff;
float _Sens;
half3 _Color;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Emission = c.rgb;
float aR = abs(c.r - _Color.r) < _Sens ? abs(c.r - _Color.r) : 1;
float aG = abs(c.g - _Color.g) < _Sens ? abs(c.g - _Color.g) : 1;
float aB = abs(c.b - _Color.b) < _Sens ? abs(c.b - _Color.b) : 1;
float a = (aR + aG + aB) / 3;
if(a < _Cutoff){
o.Alpha = 0;
}else{
o.Alpha = 1;
}
}
ENDCG
}
FallBack "Diffuse"
}
控制shader脚本
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class ShaderControls : MonoBehaviour {
float sensS, cutoffS;
Color colS;
// Use this for initialization
void Start () {
sensS = GetComponent<RawImage>().material.GetFloat("_Sens");
cutoffS = GetComponent<RawImage>().material.GetFloat("_Cutoff");
colS = GetComponent<RawImage>().material.GetColor("_Color");
sens = sensS;
cutoff = cutoffS;
}
// Update is called once per frame
void Update () {
}
public float sens, cutoff;
public string r = "99", g = "205", b ="77";
//void OnGUI()
//{
// sens = GUI.HorizontalSlider(new Rect(25, 25, 100, 30), sens, 0.0f, 1.0f);
// cutoff = GUI.HorizontalSlider(new Rect(25, 70, 100, 30), cutoff, 0.0f, 1.0f);
// r = GUI.TextField(new Rect(25, 120, 40, 20), r);
// g = GUI.TextField(new Rect(70, 120, 40, 20), g);
// b = GUI.TextField(new Rect(120, 120, 40, 20), b);
// if (GUI.Button(new Rect(25, 160, 100, 30), "Reset"))
// {
// sens = sensS;
// cutoff = cutoffS;
// r = (colS.r * 255f).ToString();
// g = (colS.g * 255f).ToString();
// b = (colS.b * 255f).ToString();
// }
// GetComponent<RawImage>().material.SetFloat("_Sens", sens);
// GetComponent<RawImage>().material.SetFloat("_Cutoff", cutoff);
// try
// {
// Color col = new Color(int.Parse(r) / 255f, int.Parse(g) / 255f, int.Parse(b) / 255f);
// //print (col);
// GetComponent<RawImage>().material.color = col;
// }
// catch (UnityException e)
// {
// }
//}
}
控制外部摄像机脚本
using UnityEngine;
using System.Collections;
using UnityEngine.Video;
using UnityEngine.UI;
using System.IO;
public class CameraControl : MonoBehaviour {
/// <summary>
/// 外部摄像头
/// </summary>
private WebCamTexture webTex;
/// <summary>
/// UI父物体
/// </summary>
private Canvas canvas;
/// <summary>
/// 摄像头映射画面
/// </summary>
private RawImage Camera_image;
private void Start()
{
canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
Camera_image = canvas.transform.Find("Camera_screen").GetComponent<RawImage>();
StartCoroutine(CallCamera());
}
/// <summary>
/// 打开摄像头
/// </summary>
/// <returns></returns>
IEnumerator CallCamera()
{
//等待用户允许访问
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
//如果用户允许访问,开始获取图像
if (Application.HasUserAuthorization(UserAuthorization.WebCam))
{
WebCamDevice[] devices = WebCamTexture.devices;
string devicename = devices[0].name;
webTex = new WebCamTexture(devicename, Screen.width, Screen.height);
Camera_image.texture = webTex;
webTex.Play();
}
}
}
控制shader脚本和打开摄像头脚本挂载到一个RawImage上面,shader脚本放在材质球上,然后把材质球也放在RawImage上面,
最后效果
由于绿幕不平和有阴影导致的绿幕没有扣掉(测试用的绿幕),如果现场绿幕是平的,效果会更好,作者把项目工程源文件分享出来了,想要的可以下载,如果有不明白的地方可以加QQ群:636926481(互相交流)。
Demo:https://download.csdn.net/download/qq_39954479/12330999