shader 雪地积雪 雪落消融效果

准备一张雪地的贴图 以及一张正常的类似地面颜色环境贴图

在这里插入图片描述

步骤一:

创建一个shader:snowtracks
关键代码如下:
(1) 声明属性,定义Pass语句块
声明两张图片Snow (RGB)和Ground (RGB)分别是雪的材质和地面的材质
SplatMap用于决定我们调用塌陷测试时使用的判断条件

// An highlighted block
 Properties{
		_Tess("Tessellation", Range(1,32)) = 4
		_SnowColor("Snow Color", color) = (1,1,1,1)
		_SnowTex("Snow (RGB)", 2D) = "white" {}
			_GroundColor("Ground Color", color) = (1,1,1,1)
		_GroundTex("Ground (RGB)", 2D) = "white" {}
		_Splat("SplatMap", 2D) = "black" {}
		_Displacement("Displacement", Range(0, 1.0)) = 0.3
		_Glossiness("Smoothness",Range(0,1)) = 0.5
		_Metallic("Metallic",Range(0,1)) = 0.0
	}

(2)

// An highlighted block
 void surf(Input IN, inout SurfaceOutputStandard o) {
				half amount = tex2Dlod(_Splat, float4(IN.uv_Splat,0,0)).r;
				fixed4 c =lerp(tex2D(_SnowTex, IN.uv_SnowTex) * _SnowColor, tex2D(_GroundTex, IN.uv_GroundTex) * _GroundColor,amount);
				o.Albedo = c.rgb;
				o.Metallic = _Metallic;
				o.Smoothness = _Glossiness;
				o.Alpha =c.a;
			}

(3)创建一个材质:
在这里插入图片描述

步骤2:

创建一个shader:drawtracks shader
关键代码如下:

// An highlighted block
Shader "Unlit/DrawTracks"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_Coordinate("Coordinate",Vector) = (0,0,0,0)
		_Color("Draw Color", Color) = (1, 0, 0, 0)
		_Size("Size",Range(1,500))=1
		_Strength("Strength", Range(0,1))=1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			fixed4 _Coordinate, _Color;
			half _Size, _Strength;


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
			float draw = pow(saturate(1 - distance(i.uv, _Coordinate.xy)),500/_Size);
			fixed4 drawcol = _Color * (draw*_Strength);
			return saturate(col+ drawcol);
                return col;
            }
            ENDCG
        }
    }
}

用一张纹理图作为积雪溶解的过程,因为每个像素存储的数据不一样就像一个不平的地面,数值比较小的就想隐藏掉,数值比较大的就后隐藏。

步骤3:

创建一个脚本 drawwithmuse,功能是随着鼠标的点击,积雪会发生消融效果,并把脚本赋给plane:
代码如下:

// An highlighted block
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class drawwithmuse : MonoBehaviour
{
   // Start is called before the first frame update
   public Camera _camera;
   public Shader _drawShader;
   private RenderTexture _splatmap;
   private Material _snowMaterial, _drawMaterial;

   [Range(1,500)]
   public float _brushSize;
   [Range(0, 1)]
   public float _brushStrength;

   private RaycastHit _hit;
   void Start()
   {
       _drawMaterial = new Material(_drawShader);
       _drawMaterial.SetVector("_Color",Color.red);

       _snowMaterial = GetComponent<MeshRenderer>().material;
       _splatmap = new RenderTexture(1024,1024,0,RenderTextureFormat.ARGBFloat);
       _snowMaterial.SetTexture("_Splat",_splatmap);
   }

   // Update is called once per frame
   void Update()
   {
       if(Input.GetKey(KeyCode.Mouse0)|| Input.GetKey(KeyCode.Mouse1))
       {
           if(Physics.Raycast(_camera.ScreenPointToRay(Input.mousePosition),out _hit))
           {
               _drawMaterial.SetVector("_Coordinate", new Vector4(_hit.textureCoord.x, _hit.textureCoord.y, 0, 0));
               _drawMaterial.SetFloat("Strength", _brushStrength);
               _drawMaterial.SetFloat("Size", _brushSize);
               RenderTexture temp = RenderTexture.GetTemporary(_splatmap.width, _splatmap.height, 0, RenderTextureFormat.ARGBFloat);
               Graphics.Blit(_splatmap, temp);
               Graphics.Blit(temp,_splatmap,_drawMaterial);
               RenderTexture.ReleaseTemporary(temp);
           }
       }
   }
   private void OnGUI()
   {
       GUI.DrawTexture(new Rect(0,0,256,256),_splatmap,ScaleMode.ScaleToFit,false,1);
   }
}

步骤4:

导入汽车模型:
在这里插入图片描述
编写脚本 wheeltrack:

// An highlighted block
void Update()
   {
      
           for (int i = 0; i < _wheel.Length; i++)
           {
               if (Physics.Raycast(_wheel[i].position, -Vector3.up, out _groundHit, 1f, _layerMask))
               {
                   _drawMaterial.SetVector("_Coordinate", new Vector4(_groundHit.textureCoord.x, _groundHit.textureCoord.y, 0, 0));
                   _drawMaterial.SetFloat("Strength", _brushStrength);
                   _drawMaterial.SetFloat("Size", _brushSize);
                   RenderTexture temp = RenderTexture.GetTemporary(_splatmap.width, _splatmap.height, 0, RenderTextureFormat.ARGBFloat);
                   Graphics.Blit(_splatmap, temp);
                   Graphics.Blit(temp, _splatmap, _drawMaterial);
                   RenderTexture.ReleaseTemporary(temp);
               }
           }
   
   }

(本来是想做轮子划过地面留下划痕,但是没有成功,所以就只贴一部分代码)
把plane 层级改为GROUND

步骤5:在车顶制造积雪效果,创建一个shader:snowshader

因为要造成在z方向上的积雪,所以夹角小于73度的区域将全部填充为积雪颜色,在73度~90度之间(也就是积雪的边缘)有一积雪过渡效果,大于90度的将使用纹理原来颜色。
赋给车,这里代码不贴了,没写好
效果:
在这里插入图片描述

步骤6:添加一个粒子特效,营造下雪的效果:

在这里插入图片描述

步骤7:把 snowfall 赋给snownoise,让雪掉在地上会逐渐覆盖

(1) 创建 snowfall shader ,造出雪落在地面的效果:

// An highlighted block
Shader "Hidden/SnowFall"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };
			float rand(float3 co)
			{
				return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 45.5432)))*43758.5453);
			}

            sampler2D _MainTex;
            float4 _MainTex_ST;
			half _FlakeAmount, _FlakeOpacity;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
			    float rValue = ceil(rand(float3(i.uv.x, i.uv.y, 0)*_Time.x)-(1- _FlakeAmount));
		

                return saturate(col-(rValue*_FlakeOpacity));
            }
            ENDCG
        }
    }
}

(2)创建一个随机的数,让雪的塌陷深度和宽度随机

步骤8:创建一个snownoise脚本 赋给palne

在snow noise 脚本中 实现刚刚声明的snowFallshader

代码片.

// An highlighted block
public class SnowNoise : MonoBehaviour
{
    public Shader _snowFallShader;
    private Material _snowFallMat;
    private MeshRenderer _meshRenderer;
    [Range(0.001f, 0.1f)]
    public float _flakeAmount;
    [Range(0f, 1f)]
    public float _flakeOpacity;
    // Start is called before the first frame update
    void Start()
    {
        _meshRenderer = GetComponent<MeshRenderer>();
        _snowFallMat = new Material(_snowFallShader);
    }

    // Update is called once per frame
    void Update()
    {
        _snowFallMat.SetFloat("_FlakeAmount", _flakeAmount);
        _snowFallMat.SetFloat("_FlakeOpacity", _flakeOpacity);
        RenderTexture snow = (RenderTexture)_meshRenderer.material.GetTexture("_Splat");
        RenderTexture temp = RenderTexture.GetTemporary(snow.width, snow.height,0,RenderTextureFormat.ARGBFloat);
        Graphics.Blit(snow,temp,_snowFallMat);
        Graphics.Blit(temp,snow);
        _meshRenderer.material.SetTexture("_Splat", snow);
        RenderTexture.ReleaseTemporary(temp);
    }
}

步骤9:把 snowfall 赋给snownoise,让雪掉在地上会逐渐覆盖

运行结果:

步骤9:把 snowfall 赋给snownoise,让雪掉在地上会逐渐覆盖

实验效果: 当鼠标按下雪面会发生塌陷效果,鼠标松开后,随着雪落,地面又会慢慢恢复。

在这里插入图片描述

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值