模型淡出Shader实现

来源:互联网 发布:ipadmini2怎么下载软件 编辑:程序博客网 时间:2024/06/06 01:30

一些特殊的动画,在unity中并不能使用。最近需要实现一种线条慢慢生长的过程,从无到有,还要掉头。这种动画貌似可以使用一些插件来使用,但想想更好的方案就是利用Shader来实现,虽然学习Shader很长时间了,但具体用它来做功能的项目还是比较少。这也算是个相对简单的Shader,其中用到的算法也比较初级,但基本功能也初步实现了,故mark一下。

方案

1.以空物体做标记记录关键点

  如下图所示,如果模型有多个转弯的点,就可以制作多少个节点,不只局限于cube,可以是很多弯头的线。

 

2.以线为轴心计算相对半径

利用脚本将当前进度的点的列表传入到Shader中,然后判断是否满足渲染的要求。


3.舍去不在区域内的像素

在半径内的点渲染出来,不在半径内的点舍去



源码

using System;using UnityEngine;using System.Collections;public class ClipLine : MonoBehaviour{    public string matName;    public float speed = 0.2f;    public bool once = true;    public float span = 0.01f;    private Material mat;    private float lastdistence;    private float distenceAll;    private float distence;    private Vector4[] posList;    private float[] distenceList;    private int count;    void Start()    {        Renderer render = GetComponent<Renderer>();        if (string.IsNullOrEmpty(matName))        {            mat = render.material;        }        else        {            mat = Array.Find<Material>(render.materials, x => x.name == matName);        }        if (!mat || transform.childCount < 2)        {            this.enabled = false;        }        else        {            distenceList = new float[transform.childCount - 1];            for (int i = 0; i < transform.childCount; i++)            {                if (i > 0)                {                    distenceList[i - 1] = Vector3.Distance(transform.GetChild(i - 1).position, transform.GetChild(i).position);                    distenceAll += distenceList[i - 1];                }            }        }    }    void Update()    {        distence += Time.deltaTime * speed;        if (distence > distenceAll)        {            distence = 0;            if (once)            {                mat.SetInt("_Count", 0);                enabled = false;                return;            }        }        if (Mathf.Abs(distence - lastdistence) > 0.01f)        {            CalcutPoistionList();            OnPositionChanged();            lastdistence = distence;        }    }    void CalcutPoistionList()    {        float distenceTemp = 0f;        count = 1;        for (int i = 0; i < distenceList.Length; i++)        {            count++;            distenceTemp += distenceList[i];            if (distenceTemp > distence)            {                distenceTemp -= distenceList[i];                    break;            }        }        posList = new Vector4[20];        int index = 0;        for (; index < count - 1; index++)        {            posList[index] = transform.GetChild(index).localPosition;            posList[index].w = 1;        }        posList[index] = Vector4.Lerp(transform.GetChild(index - 1).localPosition, transform.GetChild(index).localPosition,            (distence - distenceTemp) / distenceList[index - 1]);    }    void OnPositionChanged()    {        mat.SetInt("_Count", count);#if UNITY_5_6_OR_NEWER        mat.SetVectorArray("_Pos", posList);#elif UNITY_5_3_OR_NEWER        for (int i = 0; i < posList.Length; i++)        {            mat.SetVector("_Pos" + i, posList[i]);        }#endif    }}
Shader "Unlit/ClipLine"{Properties{_Color("Color",Color) = (1,1,1,1)_MainTex("Texture", 2D) = "white" {}    _Round("Round",Float) = 0}SubShader{Tags{ "RenderType" = "Opaque" }LOD 100Pass{Cull BackCGPROGRAM#pragma vertex vert#pragma fragment fragbool IsInsidePosList(float4 vec);#include "UnityCG.cginc"sampler2D _MainTex;float4 _MainTex_ST;float4 _Color;float _Round;int _Count;uniform vector _Pos[20];int _Index;//区域struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float4 op :TEXCOORD1;};v2f vert(appdata v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.op = v.vertex;return o;}fixed4 frag(v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);    if (!IsInsidePosList(i.op)){clip(-1);}    return col * _Color;}///在指定的区域内bool IsInsidePosList(float4 vec){if (_Count == 0) return true;for (int i = 0; i < _Count -1; i++){float3 dir1 = vec.xyz - _Pos[i + 1].xyz;float3 dir2 = vec.xyz - _Pos[i].xyz;float3 dirtemp = _Pos[i].xyz - _Pos[i + 1].xyz;float dot1 = dot(dir1, dirtemp);float dot2 = dot(dir2,-dirtemp);if (dot1 * dot2 > 0){float angle = acos(dot1 / (length(vec.xyz - _Pos[i + 1].xyz) * length(_Pos[i].xyz - _Pos[i + 1].xyz)));float dis = length(vec.xyz - _Pos[i + 1].xyz)*sin(angle);if (dis < _Round){return true;}}}return false;}ENDCG}}}



说明

1.距离问题

  如果模型本身带有缩放,那么shader中的距离需要相应的调整

2.版本问题

  新版本(5.6.0)的Shader格式不一样,需要将首行重写

3.点集问题

  5.6.0传一组数据,长度要和Shader中一样






原创粉丝点击