UnityHDRP中雪地留下脚印的Shader

效果如视频中所示:https://www.bilibili.com/video/BV15i4y1E7ZZ/

参考教学视频:https://www.bilibili.com/video/BV1Mb411i7WQ

实现思路不复杂,依赖一个C#脚本和两个shader,一个隐式shader,一个显示shader。

思路:

1.用C#脚本,在玩家的两个脚底向平面打射线,得到射线碰撞点UV的位置。

2.得到了UV坐标,在隐式shader中,在该点绘制脚印,返回到C#脚本。

3.C#脚本,将绘制的贴图,给到显示shader的高度图,即可得到效果,显示shader是HDRP自带的曲面细分。

以下是C#脚本,隐式shader用来绘制脚印贴图,显示shader是HDRP自带的LitTessellation。

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

public class DrawWithMouse : MonoBehaviour
{
    //public Camera _camera;
    public Shader _drawShader;
    private RenderTexture _splatmap;
    private Material _snowMaterial, _drawMaterial;
    private RaycastHit _hit;
    public Transform footL;
    public Transform footR;
    public float footCheckDis = 0.1f;
    void Start()
    {
        _drawMaterial = new Material(_drawShader);
        _drawMaterial.SetVector("_Color", Color.white);
        _snowMaterial = GetComponent<Renderer>().material;
        _splatmap = new RenderTexture(1024, 1024, 0, RenderTextureFormat.ARGBFloat);
        _snowMaterial.SetTexture("_HeightMap", _splatmap);
        _snowMaterial.SetTexture("_BaseColorMap", _splatmap);
        SetWhite();
        //_snowMaterial.SetColor("_EmissionColor",Color.red);
    }
    void Update()
    {
        FootDrawSnowTrack();
    }
    void FootDrawSnowTrack()
    {
        Ray footLRay = new Ray(footL.position, -Vector3.up);
        Ray footRRay = new Ray(footR.position, -Vector3.up);
        if (Physics.Raycast(footLRay, out _hit, footCheckDis))
        {
            DrawAtHit(_hit);
        }
        if (Physics.Raycast(footRRay, out _hit, footCheckDis))
        {
            DrawAtHit(_hit);
        }
    }
    //使用摄像机绘制贴图的方案
    // void CameraDrawSnow()
    // {
    //     if (Input.GetKey(KeyCode.Mouse0))
    //     {
    //         if (Physics.Raycast(_camera.ScreenPointToRay(Input.mousePosition), out _hit))
    //         {
    //             //将射线检测的顶点坐标传递到shader的_Coordinate属性上面
    //             _drawMaterial.SetVector("_Coordinate", new Vector4(_hit.textureCoord.x, _hit.textureCoord.y, 0, 0));
    //             //新建一个临时的渲染纹理,尺寸格式和_splatmap一致
    //             RenderTexture temp = RenderTexture.GetTemporary(_splatmap.width, _splatmap.height, 0, RenderTextureFormat.ARGBFloat);
    //             //public static void Blit(Texturesource,RenderTexture dest,Material mat);
    //             //Source被设置为目标材质的_MainTex,处理之后绘制到dest
    //             //将_splatmap绘制temp上
    //             Graphics.Blit(_splatmap, temp);
    //             //再将temp纹理经过_drawMaterial隐藏材质的处理之后,绘制到_splatmap上
    //             //估计不能这样写Graphics.Blit(_splatmap,_splatmap, _drawMaterial);
    //             Graphics.Blit(temp, _splatmap, _drawMaterial, 0);
    //             //释放临时渲染纹理
    //             RenderTexture.ReleaseTemporary(temp);
    //         }
    //     }
    // }
    void DrawAtHit(RaycastHit _hit)
    {
        //将射线检测的顶点坐标传递到shader的_Coordinate属性上面
        _drawMaterial.SetVector("_Coordinate", new Vector4(_hit.textureCoord.x, _hit.textureCoord.y, 0, 0));
        //新建一个临时的渲染纹理,尺寸格式和_splatmap一致
        RenderTexture temp = RenderTexture.GetTemporary(_splatmap.width, _splatmap.height, 0, RenderTextureFormat.ARGBFloat);
        //public static void Blit(Texturesource,RenderTexture dest,Material mat);
        //Source被设置为目标材质的_MainTex,处理之后绘制到dest
        //将_splatmap绘制temp上
        Graphics.Blit(_splatmap, temp);
        //再将temp纹理经过_drawMaterial隐藏材质的处理之后,绘制到_splatmap上
        //估计不能这样写Graphics.Blit(_splatmap,_splatmap, _drawMaterial);
        Graphics.Blit(temp, _splatmap, _drawMaterial, 0);
        //释放临时渲染纹理
        RenderTexture.ReleaseTemporary(temp);
    }
    void SetWhite()
    {
        RenderTexture temp = RenderTexture.GetTemporary(_splatmap.width, _splatmap.height, 0, RenderTextureFormat.ARGBFloat);
        Graphics.Blit(_splatmap, temp);
        Graphics.Blit(temp, _splatmap, _drawMaterial, 1);
        RenderTexture.ReleaseTemporary(temp);
    }
    void OnGUI()
    {
        //GUI.DrawTexture(new Rect(0, 0, 256, 256), _splatmap, ScaleMode.ScaleToFit, false, 1);
    }
}
Shader "WLB/DrawTrack"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Coordinate("Coordinate", Vector) = (0,0,0,0)
        _Color("Draw Color", Color) = (1,1,1,1)

    }
    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;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Coordinate, _Color;

            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);
            //     //saturate控制变量在0~1之间,相当于Clamp01;
            //     // pow(x, y): x的y次方;
            //     //下面的式子可以理解为在UV坐标_Coordinate.xy处,绘制了一个小圆点,称尖峰形状
            //     float draw = pow(saturate(1 - distance(i.uv, _Coordinate.xy)),200);
            //     //尖峰处染成红色
            //     fixed4 drawcol = _Color * (draw * 0.1);
            //     //叠加原本的color和新绘制的红色尖峰
            //     fixed4 output = saturate(col + drawcol);
            //     return output;
            // }
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                //saturate控制变量在0~1之间,相当于Clamp01;
                // pow(x, y): x的y次方;
                //下面的式子可以理解为在UV坐标_Coordinate.xy处,绘制了一个小圆点,称尖峰形状
                float draw = pow(saturate((0.5 - distance(i.uv, _Coordinate.xy))*2),200);
                //尖峰处染成红色
                fixed4 drawcol = _Color * (draw * 0.5);
                //叠加原本的color和新绘制的红色尖峰
                fixed4 output = saturate(col - drawcol);
                return output;
            }
            ENDCG
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #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;

            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
            {
                fixed4 output = (1,1,1,1);
                return output;
            }
            ENDCG
        }
    }
}

 

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值