Shader实例:一台旧电视

准备:
1.一段小视频
2.一张电视机贴图
3.一张过滤图

效果:
让视频内容只在电视机屏幕区域显示

Shader代码:有注释

Shader "Joe/old_tv"
{
    Properties
    {
        _MainTex("main tex", 2d) = ""{}//主贴图
        _TVTex("TV tex",2d) = ""{}//屏幕内容
        _TVMask("TV mask",2d) = ""{}//过滤贴图
    }
 
    SubShader
    {
        Tags
        {
            "Queue"  = "Transparent"
        }
 
        Blend SrcAlpha OneMinusSrcAlpha
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
 
            #include "UnityCG.cginc"
 
            struct v2f
            {
                float4 vertex:POSITION;
                float4 uv:TEXCOORD0;
            };
 
            sampler2D _MainTex;
            sampler2D _TVTex;//视频内容从脚本本中设置
            sampler2D _TVMask;
 
            v2f vert(appdata_base v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv.xy = v.texcoord.xy;
                return o;
            }
 
            half4 frag(v2f i):COLOR
            {
                //采样电视机贴图
                half4 tv = tex2D(_MainTex,i.uv.xy);
 
                //采样过滤贴图
                half4 mask = tex2D(_TVMask,i.uv.xy);
 
                //得到用过滤图的alpha值作为权重 影响过后的uv
                half2 maskuv = i.uv.xy * mask.a;
 
                //用该uv,采样屏幕内容,根据过滤图的alpha值,得到内容只在电视机屏幕区域显示的效果
                half4 tvcontent = tex2D(_TVTex,maskuv);
                tvcontent.a = mask.a;
 
                //return tvcontent;
                //return tv;
 
                half4 result = tv;
                //是屏幕上的区域
                if(mask.a==1)
                {
                    //和屏幕内容颜色混合
                    result = tv + tvcontent;
                    result.rgb=result.rgb/2;
                }
                else
                {
                    //是电视机外壳区域,什么也不做,保持原来的颜色
                }
                return result;
            }            
 
            ENDCG
        }
    }
 
    FallBack "Diffuse"
}

C#脚本代码:就是把视频内容传递给shader代码里面的uniform sampler2D _TVTex

using UnityEngine;
using System.Collections;
 
public class playTv : MonoBehaviour
{
    public MovieTexture movie;
 
    void Start () 
    {
        this.GetComponent<Renderer>().material.SetTexture("_TVTex",movie);
        movie.loop = true;
        movie.Play();
    }
}

不足:
以为这样就完美了吗?
不是,既然是旧电视,必然有那种,吱~吱~吱~ 的闪烁。
屏幕绘制不完美的断裂,从左到右的一个uv移动。

Try it yourself!
我是个怀旧之人,小时候爷爷房间里就有这样的一台电视机。
你完全可以搞一张IMAX的图片,然后在上面播放好莱坞大片。

posted @ 2016-05-13 15:43  Joe师傅  阅读(997)  评论(0编辑  收藏  举报