UnityVR消防项目(一)颜色过滤


本教程是关于一个Shader满天飞的项目,涉及到的知识点有:

  • 摄像头获取
  • 颜色过滤
  • 多摄像头图像拼接
  • 带高度图的调色板
  • 像素捕捉定位
  • 动态水效果
  • 燃烧融化效果

如果对图形学吃不消的同学,可以先去买冯乐乐的Shader入门书籍:
https://book.douban.com/subject/26821639/?from=tag

最近有朋友联系我,需要做一个VR版的消费演习项目。这已经是这个月第三个朋友找我做逃生演习项目,难道最近广州又有土豪老板开始千万级的融资???反正不关我事,我就是程序员,负责做好项目就行。把项目需求拿过来,需求很奇葩,不使用Kinect不使用Slam算法做一个消防逃生演习项目。具体需求是这样子滴:

  1. 需要用3个摄像头对真实世界的人物进行捕捉,并把人物绘制到Unity的主场景
  2. 使用图像识别技术,判断人物在场景里面的位置,并做相对应的触发时间
    • 人物走到左边沙发开始燃烧
    • 人物走到中间天花板掉落
    • 人物走到右边有水的涟漪产生
    • 人物走到终点门打开,有烟雾散发进来
  3. 不使用Kinect和Slam,将开发成本压缩在2W左右。
  4. 场景布置图如下
  5. 时限是两周的时间

咋看一下,功能很简单,无非就是Unity截获Camera的图像,显示在面片上,场景搭个面片把截获的信息显示出来。2W的项目妥妥的接。
但是后来的事实证明了,根本不是我想的那么简单,开始的需求是折纸飞机,后面开始让我弄波音747,没办法,10万的项目2万的接,自己揽的锅跪下都要背。

首先我们来看看具体需求:
1。需要用3个摄像头对真实世界的人物进行捕捉,并把人物绘制到Unity的主场景。

Unity是最大支持4个摄像头,但是我测试只需要拿一个就行了。思路就是把摄像头截取,把画面显示在Quad上面

代码:

IEnumerator Start()
{
    yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
    if (Application.HasUserAuthorization(UserAuthorization.WebCam))
    {
        WebCamDevice[] devices = WebCamTexture.devices;
    
        WebCamTexture tex = new WebCamTexture(devices[0].name, 400, 400, 12);
        mCameraTex.GetComponent<MeshRenderer>().material.mainTexture = tex;
        tex.Play();

    }
}

重写了Start,因为Unity底层使用反射调用Start,所以需要把void Start删掉。为啥要用携程,因为截获摄像头的图像有延时,必须在每次
渲染完摄像头才能截取,所以必须用协程把时间错开。

出来的结果是这样的:

我们人物在场景出来了,背景也出来了。但是我们要的效果是只要人物,那么背景怎么去掉呢?
我第一想到的是用抠颜色的方法,把背景抠掉。但是这样就有疑问,如果把人物也抠了怎么办?
多方研究发现,绿色是和人体颜色相似度最差的颜色,我们使用绿色背景打底,人物走过就能把绿色抠掉了。但是如果有人穿绿色的衣服,那我也没办法,这年头穿绿色套装出社会本来就有危险= =!

绿色布搞来了,下面开始动工!!!

现在要做的事情就是抠图!抠图!抠图!

网上找了个抠图插件很难用,很多依赖弄不掉,决定自己写!!

思路无非就是找到颜色匹配的那块像素,把他变成透明,同时Shader要支持透明通道还有透明队列。

颜色匹配的算法我想了很久,最后还是决定使用方差公式,即Color1和Color2的相似度等于。

sqrt(pow((Color1.r - Color2.r),2) + pow((Color1.g - Color2.g),2) + pow((Color1.b - Color2.b),2))

得出来的值越小,说明和目标颜色越接近,很明显,上面的Color2就是我决定使用的绿色

Shader "MyShader/FilterfColor" { 
Properties { 
    _MainTex ("Base (RGB)", 2D) = "white" {} 
    _FilterfColor("Ridof (RGB)",Color)=(1,1,1,1) 
    _Range("Range",range(0,1))=0

    _X("X",range(0,1))=0
} 
SubShader { 
    Tags { "RenderType"="Opaque" "Queue"="Transparent"} 
    Blend SrcAlpha OneMinusSrcAlpha 
    pass 
    { 
        CGPROGRAM 

        #pragma vertex vertext_convert
        #pragma fragment fragment_convert
        #include "UnityCG.cginc" 

        sampler2D  _MainTex; 
        sampler2D  _MainTex1; 
        float4  _FilterfColor; 
        float4 _MainTex_ST;
        float   _Range;

        float   _X;   
        struct Inputvrite 
        { 
            float4 vertex : POSITION; 
            float4 texcoord : TEXCOORD0; 
        }; 
        struct Inputfragment 
        { 
            float4 pos : SV_POSITION; 
            float2 uv : TEXCOORD0; 
        }; 

        float ColorLerp(float3 tmp_nowcolor,float3 tmp_FilterfColor) 
        { 
            float3 dis = float3(abs(tmp_nowcolor.x - tmp_FilterfColor.x),abs(tmp_nowcolor.y - tmp_FilterfColor.y),abs(tmp_nowcolor.z - tmp_FilterfColor.z)); 
            float dis0 =sqrt(pow(dis.x,2)+pow(dis.y,2)+pow(dis.z,2)); 
            float maxdis = sqrt(3); 
            float dis1 = lerp(0,maxdis,dis0); 
            if(dis1 < _Range){
                dis1 = dis1 *dis1 *dis1;
            }
            return dis1; 
        } 

        Inputfragment vertext_convert(Inputvrite i) 
        { 
            Inputfragment o; 
            o.pos = mul(UNITY_MATRIX_MVP,i.vertex); 

            o.uv = TRANSFORM_TEX(i.texcoord, _MainTex);  
            return o; 
        } 

        float4 fragment_convert(Inputfragment o) : COLOR 
        { 
    //    o.uv.x  *= _X;
            float4 c = tex2D(_MainTex,o.uv); 
            c.a *=ColorLerp(c.rgb,_FilterfColor.rgb); 
       //     c.a *= c.a;
            return c; 
        } 


    ENDCG 
    } 
} 
FallBack "Diffuse" 
}

稍作调整可以看到下面的效果,绿色被我抠掉了!!

但是后面还有更多艰巨的任务等着我,一个是调色板方便客户抠图,一个是要判断小人走到地图哪个位置。

两周时间第一天就只做了个抠图。其实好戏还在后头= =*

下一期要讲的内容是:像素遍历判断小人的位置。


(程序是个永无止境的东西,必须每天保持学习)

版权所有,违责必究

菜鸟在线 林老师 2017.7.29

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容