Unity Shader - 板砖日志 - 简单的树、草 等植物的 随风飘扬 动画

141 篇文章 33 订阅
50 篇文章 2 订阅


目的

便于后续自己的 CTRL+C,V的面向复制、粘贴编程


思路

非常简单:可以使用 perlin noise,simple noise 或是其他的 noise 函数,又或是 noise tex 来提取顶点 xyz 的偏移

然后 vs 里便宜就好了,需要阴影跟随飘动的投影就加上 “LightMode”=“ShadowCaster” 的 pass


Script


include cginc

#ifndef __WIND_COMMON_H__
#define __WIND_COMMON_H__

// jave.lin 2021/04/13

#include "UnityCG.cginc"

#if defined(_WIND_ON)

half	_WindSpeed;
half	_WindWavesScale;
half	_WindForce;
half4	_WindDir;
half	_MoveHeight;
half	_MoveHeightPow;

float3 mod3D289(float3 x) { return x - floor(x / 289.0) * 289.0; }

float4 mod3D289(float4 x) { return x - floor(x / 289.0) * 289.0; }

float4 permute(float4 x) { return mod3D289((x * 34.0 + 1.0) * x); }

float4 taylorInvSqrt(float4 r) { return 1.79284291400159 - r * 0.85373472095314; }

float snoise(float3 v)
{
	const float2 C = float2(1.0 / 6.0, 1.0 / 3.0);
	float3 i = floor(v + dot(v, C.yyy));
	float3 x0 = v - i + dot(i, C.xxx);
	float3 g = step(x0.yzx, x0.xyz);
	float3 l = 1.0 - g;
	float3 i1 = min(g.xyz, l.zxy);
	float3 i2 = max(g.xyz, l.zxy);
	float3 x1 = x0 - i1 + C.xxx;
	float3 x2 = x0 - i2 + C.yyy;
	float3 x3 = x0 - 0.5;
	i = mod3D289(i);
	float4 p = permute(permute(permute(i.z + float4(0.0, i1.z, i2.z, 1.0)) + i.y + float4(0.0, i1.y, i2.y, 1.0)) + i.x + float4(0.0, i1.x, i2.x, 1.0));
	float4 j = p - 49.0 * floor(p / 49.0);  // mod(p,7*7)
	float4 x_ = floor(j / 7.0);
	float4 y_ = floor(j - 7.0 * x_);  // mod(j,N)
	float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0;
	float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0;
	float4 h = 1.0 - abs(x) - abs(y);
	float4 b0 = float4(x.xy, y.xy);
	float4 b1 = float4(x.zw, y.zw);
	float4 s0 = floor(b0) * 2.0 + 1.0;
	float4 s1 = floor(b1) * 2.0 + 1.0;
	float4 sh = -step(h, 0.0);
	float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
	float4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
	float3 g0 = float3(a0.xy, h.x);
	float3 g1 = float3(a0.zw, h.y);
	float3 g2 = float3(a1.xy, h.z);
	float3 g3 = float3(a1.zw, h.w);
	float4 norm = taylorInvSqrt(float4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3)));
	g0 *= norm.x;
	g1 *= norm.y;
	g2 *= norm.z;
	g3 *= norm.w;
	float4 m = max(0.6 - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
	m = m * m;
	m = m * m;
	float4 px = float4(dot(x0, g0), dot(x1, g1), dot(x2, g2), dot(x3, g3));
	return 42.0 * dot(m, px);
}

void windNoiseHandle(inout float4 posOS, float modelY, float uv_v)
{
	if (_MoveHeight <= 0) return;

	 jave.lin 2021/12/13 : 新版本的方式,目前暂时没用上 uv
	//float hT = modelY / _MoveHeight;

	//float3 positionOS = posOS;
	//float windSpeed = _Time.y * (_WindSpeed * 5);
	//float3 noisePos = (positionOS + windSpeed) * _WindWavesScale;
	//float windNoise = snoise(noisePos) * (_WindForce * 30);
	//windNoise *= hT;
	//windNoise *= pow(hT, _MoveHeightPow);
	//posOS.xyz = positionOS + _WindDir.xyz * windNoise;

	// jave.lin : 旧版本的方式
	float3 positionOS = posOS;
	float windSpeed = _Time.y * (_WindSpeed * 5);
	float windNoise = snoise((mul(unity_ObjectToWorld, posOS) + windSpeed) * _WindWavesScale);
	windNoise = (windNoise * 0.01);
	//#ifdef _FIXTHEBASEOFFOLIAGE_ON
	//	windNoise = (windNoise * pow(uv_v, 2.0));
	//#endif
	//windNoise = (windNoise * pow(uv_v, 2.0));
	windNoise = (windNoise * pow(modelY / _MoveHeight, _MoveHeightPow));
	windNoise = (windNoise * (_WindForce * 30));
	posOS.xyz += (_WindDir.xyz * windNoise) * (1 + (sin(_Time.y * 0.5) * 0.5 + 0.5));
}

#define VERT_WIND(wpos, modelY, uv_v) windNoiseHandle(wpos, modelY, uv_v);

#else
#define VERT_WIND(wpos, modelY, uv_v)
#endif


#endif


appled shader

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "OnePiece/Legacy Shaders/Transparent/Cutout/Diffuse_DoubleSide_Wind" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}

SubShader {
    Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    LOD 200
	Cull Off



CGPROGRAM
#define _WIND_ON
#pragma surface surf Lambert fullforwardshadows addshadow alphatest:_Cutoff vertex:vert

// include 引入
#include "Includes/CG/WindCommon.cginc"

sampler2D _MainTex;
fixed4 _Color;

struct Input {
    float2 uv_MainTex;
};

void vert(inout appdata_full v)
{
	// 应用
	VERT_WIND(v.vertex, v.vertex.y, v.texcoord.y)
}

void surf (Input IN, inout SurfaceOutput o) {
    fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    o.Albedo = c.rgb;
    o.Alpha = c.a;
}
ENDCG
}

Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"
}


csharp

// jave.lin 2021/04/13

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteInEditMode]
public class WindArgsController : MonoBehaviour
{
    private static int _WindForce = Shader.PropertyToID("_WindForce");
    private static int _WindWavesScale = Shader.PropertyToID("_WindWavesScale");
    private static int _WindSpeed = Shader.PropertyToID("_WindSpeed");
    private static int _WindStrengthen = Shader.PropertyToID("_WindStrengthen");
    private static int _WindDir = Shader.PropertyToID("_WindDir");
    private static int _MoveHeight = Shader.PropertyToID("_MoveHeight");
    private static int _MoveHeightPow = Shader.PropertyToID("_MoveHeightPow");

    public bool windToggle = true;
    private bool lastWindToggle = false;

    [Range(0.0f, 1.0f)]
    public float WindSpeed = 0.3f;
    private float lastWindSpeed;

    [Range(0.0f, 1.0f)]
    public float WindStrengthen = 1;
    private float lastWindStrengthen = 1;

    [Range(0.0f, 1.0f)]
    public float WindWavesScale = 0.25f;
    private float lastWindWavesScale;

    [Range(0.0f, 1.0f)]
    public float WindForce = 0.5f;
    private float lastWindForce;

    public bool DirFromForward = true;
    public Vector4 WindDir = new Vector4(1, 0, 0, 0);
    private Vector4 lastWindDir;

    public float MoveHeight = 5.0f;
    private float lastMoveHeight;

    [Range(0.001f, 5.0f)]
    public float MoveHeightPow = 1.0f;
    private float lastMoveHeightPow;

#if UNITY_EDITOR
    public float GizmosDirLineSize = 8.0f;
    public Color GizmosDirLineColor = Color.green;
    public Color GizmosCircleColor = Color.red;
    public int GizmosDirHeadCircleLineSegmentNum = 12;
    public int GizmosDirHeadCircleLineRadius = 2;
#endif

    private void Start()
    {
        WindDir = transform.forward;

        if (windToggle)
            Shader.EnableKeyword("_WIND_ON");
        else
            Shader.DisableKeyword("_WIND_ON");

        Shader.SetGlobalFloat(_WindSpeed, WindSpeed);
        Shader.SetGlobalFloat(_WindWavesScale, WindWavesScale);
        Shader.SetGlobalFloat(_WindForce, WindForce);
        Shader.SetGlobalVector(_WindDir, WindDir);
        Shader.SetGlobalFloat(_MoveHeight, MoveHeight);
        Shader.SetGlobalFloat(_MoveHeightPow, MoveHeightPow);
    }

    private void Update()
    {
        if (lastWindToggle != windToggle)
        {
            lastWindToggle = windToggle;
            if (windToggle)
                Shader.EnableKeyword("_WIND_ON");
            else
                Shader.DisableKeyword("_WIND_ON");
        }

        if (lastWindSpeed != WindSpeed)
        {
            lastWindSpeed = WindSpeed;
            Shader.SetGlobalFloat(_WindSpeed, WindSpeed);
        }

        if (lastWindStrengthen != WindStrengthen)
        {
            lastWindStrengthen = WindStrengthen;
            Shader.SetGlobalFloat(_WindStrengthen, WindStrengthen);
        }

        if (lastWindWavesScale != WindWavesScale)
        {
            lastWindWavesScale = WindWavesScale;
            Shader.SetGlobalFloat(_WindWavesScale, WindWavesScale);
        }

        if (lastWindForce != WindForce)
        {
            lastWindForce = WindForce;
            Shader.SetGlobalFloat(_WindForce, WindForce);
        }

        if (DirFromForward)
        {
            WindDir = transform.forward;
        }
        if (!lastWindDir.Equals(WindDir))
        {
            lastWindDir = WindDir;
            Shader.SetGlobalVector(_WindDir, WindDir);
        }

        if (lastMoveHeight != MoveHeight)
        {
            lastMoveHeight = MoveHeight;
            Shader.SetGlobalFloat(_MoveHeight, MoveHeight);
        }

        if (lastMoveHeightPow != MoveHeightPow)
        {
            lastMoveHeightPow = MoveHeightPow;
            Shader.SetGlobalFloat(_MoveHeightPow, MoveHeightPow);
        }
    }

#if UNITY_EDITOR
    private void OnDrawGizmos()
    {
        // jave.lin 2021/12/13 - 添加实现 风向 显示的 Gizmos
        var transWPos = transform.position;
        Vector3 transForward;

        if (DirFromForward)
        {
            transForward = transform.forward;
        }
        else
        {
            transForward = WindDir;
        }

        // back up gizmos col
        var srcCol = Gizmos.color;
        int count = GizmosDirHeadCircleLineSegmentNum;
        float curAngle = 0;
        float perIterateAngle = (2.0f * Mathf.PI) / count;

        // center line
        Gizmos.color = GizmosCircleColor;
        Gizmos.DrawLine(transWPos, transWPos + transForward * GizmosDirLineSize);

        // local to world mat
        var L2WMat = transform.localToWorldMatrix;

        for (int i = 0; i < count; i++)
        {
            // draw circle
            Gizmos.color = GizmosCircleColor;

            var cx = Mathf.Cos(curAngle);
            var cy = Mathf.Sin(curAngle);
            var cv = new Vector3(cx, cy, 0) * GizmosDirHeadCircleLineRadius;
            cv = L2WMat.MultiplyVector(cv);

            curAngle += perIterateAngle;
            var nx = Mathf.Cos(curAngle);
            var ny = Mathf.Sin(curAngle);
            var nv = new Vector3(nx, ny, 0) * GizmosDirHeadCircleLineRadius;
            nv = L2WMat.MultiplyVector(nv);

            Gizmos.DrawLine(transWPos + cv, transWPos + nv);

            // draw dir line
            Gizmos.color = GizmosDirLineColor;
            Gizmos.DrawLine(transWPos + cv, transWPos + cv + transForward * GizmosDirLineSize);
        }

        // recovery gizmos color
        Gizmos.color = srcCol;
    }
#endif
}


效果

在这里插入图片描述

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值