欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

unity实现3D物体的残影效果

程序员文章站 2022-07-13 22:31:19
...

很久之前我写过一篇用对象池等知识实现的2D的残影效果
好像有挺多小伙伴看的添加链接描述
然后这几天我有入门了一下shader 接触了透明的效果
之后我就飘了 想实现一下3D残影的效果
但是这个仅限于unity自带的规则物体 我这用的是球(sphere)
而且我写的代码没有做优化 可能有点混乱

老规矩我还是给出demo吧
unity实现3D物体的残影效果

我这里的想法是 我弄几个小球 让后边的小球跟着前边的走
前边的后边 后边的就怎么走
这个我们利用unity的特性很容易可以实现

private void FixedUpdate()
    {
        transform.position = LastObject.position;
    }

这样就很容易的实现了小球的跟随效果

这时候我们就想到了透明的效果了
我们要用shader自己去写一个材质

Shader "Custom/Chapter"
{
     Properties{
        _MainTex("Main Texture",2D) = "white"{}
        _BaseColor("Base Color",Color) = (1.0,1.0,1.0,1.0)
        _AlphaScale("Alpha Threshold",Range(0,1)) = 1
    }

    SubShader{
        Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        //记住Transparent就完事了
        
        pass{
            ZWrite On
            ColorMask 0    // 控制该Pass不输出任何颜色
        }
        pass{
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            //关闭深度写入,同时开启混合。这里我们的混合因子选择了SrcAlpha 和OneMinueSrcAlpha
            //这两个计算因子最终可以得到半透明混合的效果。

            Tags{"LightMode"="ForwardBase"}
            //不变

            CGPROGRAM
            #pragma vertex Vertex
            #pragma fragment Pixel
            #include "Lighting.cginc"

            struct vertexInput{
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            struct vertexOutput{
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            sampler2D _MainTex;
            fixed4 _BaseColor;
            fixed _AlphaScale;

            vertexOutput Vertex(vertexInput v){
                
                vertexOutput o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                o.uv = v.texcoord;

                return o;
            }
            fixed4 Pixel(vertexOutput i):SV_TARGET{

                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed3 albedo = tex2D(_MainTex,i.uv).xyz * _BaseColor.xyz;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.xyz * albedo * saturate(dot(worldNormal,lightDir));

                return fixed4(diffuse + ambient,_AlphaScale);
            }

            ENDCG
            }
      }
}

然后我们可以通过c#中的方法来修改透明度 从而实现残影的效果

  private void Start()
    {
        lattmat = GetComponent<Renderer>().material;
    }
    private void Update()
    {
        lattmat.SetFloat("_AlphaScale", alpyh);
    }

之后我们就要思考 怎么能把后边的球联系起来

  public followobject lastscript;//上一个物体的脚本
    public Transform  LastObject;//上一个物体
    private  Material lattmat;//本物体的材质
    public float alpyh;//设置的透明度

之后我们在unity中赋值
unity实现3D物体的残影效果

这里的赋值都上上一个物体

然后我给出完整的源码 给大家参考

后边子物体的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class followobject : MonoBehaviour
{
    public followobject lastscript;//上一个物体的脚本
    public Transform  LastObject;//上一个物体
    private  Material lattmat;//本物体的材质
    public float alpyh;//设置的透明度


    private void Start()
    {
        lattmat = GetComponent<Renderer>().material;
    }
    private void Update()
    {
        lattmat.SetFloat("_AlphaScale", alpyh);
    }
    private void FixedUpdate()
    {
        transform.position = LastObject.position;
        if (lastscript == null)
        {
            alpyh = ConShader.Instance.a;
        }
        else
        {
            alpyh = lastscript.alpyh;
        }
       
    }
    
}

可键盘控制的物体

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ConShader : MonoBehaviour
{

    public float a = 1;
    public bool isstart = false;

    public static ConShader Instance;

    private void Awake()
    {
        Instance = this;
    }

    private void Update()
    {
        transform.Translate(new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Time.deltaTime * 20);
        if (isstart)
        {
            a -= Time.deltaTime;
        }
        if (a < 0)
        {
            isstart = false;
            a = 0;
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            a = 1;
            isstart = true;
        }

    }
}

shader源码

Shader "Custom/Chapter"
{
     Properties{
        _MainTex("Main Texture",2D) = "white"{}
        _BaseColor("Base Color",Color) = (1.0,1.0,1.0,1.0)
        _AlphaScale("Alpha Threshold",Range(0,1)) = 1
    }

    SubShader{
        Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        //记住Transparent就完事了
        
        pass{
            ZWrite On
            ColorMask 0    // 控制该Pass不输出任何颜色
        }
        pass{
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            //关闭深度写入,同时开启混合。这里我们的混合因子选择了SrcAlpha 和OneMinueSrcAlpha
            //这两个计算因子最终可以得到半透明混合的效果。

            Tags{"LightMode"="ForwardBase"}
            //不变

            CGPROGRAM
            #pragma vertex Vertex
            #pragma fragment Pixel
            #include "Lighting.cginc"

            struct vertexInput{
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            struct vertexOutput{
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            sampler2D _MainTex;
            fixed4 _BaseColor;
            fixed _AlphaScale;

            vertexOutput Vertex(vertexInput v){
                
                vertexOutput o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                o.uv = v.texcoord;

                return o;
            }
            fixed4 Pixel(vertexOutput i):SV_TARGET{

                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed3 albedo = tex2D(_MainTex,i.uv).xyz * _BaseColor.xyz;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.xyz * albedo * saturate(dot(worldNormal,lightDir));

                return fixed4(diffuse + ambient,_AlphaScale);
            }

            ENDCG
            }
      }
}

希望我所写的对大家有所帮助
如果有问题可以联系我 主页有我的联系方式