Unity大面积草地渲染——2、草地的动态交互

这篇具有很好参考价值的文章主要介绍了Unity大面积草地渲染——2、草地的动态交互。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
1、Shader控制一棵草的渲染
2、草地的动态交互
3、使用GPUInstancing渲染大面积的草
4、对大面积草地进行区域剔除和显示等级设置

大家好,我是阿赵。
这里继续讲大面积草地渲染的第二个部分,草地动态交互。这里主要有风吹效果和球体碰撞效果2种。

一、风吹效果

Unity使用shader控制草的渲染和动画


风吹动草的效果,主要还是使用顶点程序来控制顶点的偏移
回顾一下之前的基础草的shader的顶点程序
v2f vert (appdata v)
            {
                v2f o;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.centerPos = mul(unity_ObjectToWorld, float4(float3(0, 0, 0), 1)).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				float hVal = smoothstep(_hmin, _hmax, o.worldPos.y - o.centerPos.y);
				float vVal = smoothstep(_vmin, _vmax, distance(o.worldPos.xz, o.centerPos.xz));
				float hvVal = hVal * vVal;
				o.hvVal = float3(hVal, vVal, hvVal);
				float hVertexOffset = hvVal * _hOffset;
				float2 vVertexOffset = (o.worldPos.xz - o.centerPos.xz)*hvVal*_vOffset;

				o.pos = UnityObjectToClipPos(v.vertex+float3(vVertexOffset.x, hVertexOffset, vVertexOffset.y));
                return o;
            }

在这个顶点程序里面,已经使用顶点偏移来实现了草的受重力弯曲的形态,所以现在只需要对它进行一些小修改,加入一个风力的影响,就可以实现左右摇摆的效果了。
这里我添加一个风的方向,还有一个Sin曲线来模拟风的左右摇摆:

float2 wind = _windOffset * hVal*_SinTime.w;
float2 windPosXZOffset = vVertexOffset + wind;
o.pos = UnityObjectToClipPos(v.vertex + float3(windPosXZOffset.x, hVertexOffset, windPosXZOffset.y));

unity草地,Unity引擎Shader效果,unity,交互,游戏引擎,草地,碰撞
unity草地,Unity引擎Shader效果,unity,交互,游戏引擎,草地,碰撞

通过调节windOffset,可以让草摆动的幅度产生变化

修改之后的完整shader是这样的:

Shader "azhao/GrassWind"
{
    Properties
    {
		_MainTex("MainTex", 2D) = "white" {}
		_hmin("hmin", Range(0 , 1)) = 0
		_hmax("hmax", Range(0 , 1)) = 1
		_hOffset("hOffset", Range(-1 , 1)) = 0
		_vmin("vmin", Range(0 , 1)) = 0
		_vmax("vmax", Range(0 , 1)) = 1
		_vOffset("vOffset", Range(-5 , 5)) = 0
		_topCol("topCol", Color) = (0,1,0,0)
		_windOffset("windOffset", Vector) = (0,0,0,0)
		_bottomCol("bottomCol", Color) = (0,0,0,0)

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag


			#include "UnityShaderVariables.cginc"
			#pragma target 3.0
            #include "UnityCG.cginc"

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

            };

            struct v2f
            {                
                float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 centerPos : TEXCOORD1;
				float3 worldPos : TEXCOORD2;
				float3 hvVal : TEXCOORD3;
            };

			uniform float _hmin;
			uniform float _hmax;
			uniform float _vmin;
			uniform float _vmax;
			uniform float _vOffset;
			uniform float2 _windOffset;
			uniform float _hOffset;
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;
			uniform float4 _topCol;
			uniform float4 _bottomCol;

            v2f vert (appdata v)
            {
                v2f o;

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.centerPos = mul(unity_ObjectToWorld, float4(float3(0, 0, 0), 1)).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				float hVal = smoothstep(_hmin, _hmax, o.worldPos.y - o.centerPos.y);
				float vVal = smoothstep(_vmin, _vmax, distance(o.worldPos.xz, o.centerPos.xz));
				float hvVal = hVal * vVal;
				o.hvVal = float3(hVal, vVal, hvVal);
				float hVertexOffset = hvVal * _hOffset;
				float2 vVertexOffset = (o.worldPos.xz - o.centerPos.xz)*hvVal*_vOffset;
				float2 wind = _windOffset * hVal*_SinTime.w;


				float2 windPosXZOffset = vVertexOffset + wind;

				o.pos = UnityObjectToClipPos(v.vertex+float3(windPosXZOffset.x, hVertexOffset, windPosXZOffset.y));
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {

                // sample the texture
                half4 col = tex2D(_MainTex, i.uv);
				half3 finalCol = col.rgb * _topCol.rgb*i.hvVal.z + col.rgb;
				finalCol = clamp(finalCol*i.hvVal.x + _bottomCol * (1 - i.hvVal.x)*finalCol,  half3(0, 0, 0), half3(1, 1, 1));
				half alpha = col.a;
				clip(alpha - 0.5);
                return half4(finalCol,alpha);
            }
            ENDCG
        }
		
		//为了产生影子,加多一个pass
		Pass {
			Name "ShadowCaster"
			Tags { "LightMode" = "ShadowCaster" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 2.0
			#include "UnityCG.cginc"

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

			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 centerPos : TEXCOORD1;
				float3 worldPos : TEXCOORD2;
				float3 hvVal : TEXCOORD3;
			};

			uniform float _hmin;
			uniform float _hmax;
			uniform float _vmin;
			uniform float _vmax;
			uniform float _vOffset;
			uniform float2 _windOffset;
			uniform float _hOffset;
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;
			uniform float4 _topCol;
			uniform float4 _bottomCol;

			v2f vert(appdata v)
			{
				v2f o;

				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.centerPos = mul(unity_ObjectToWorld, float4(float3(0, 0, 0), 1)).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				float hVal = smoothstep(_hmin, _hmax, o.worldPos.y - o.centerPos.y);
				float vVal = smoothstep(_vmin, _vmax, distance(o.worldPos.xz, o.centerPos.xz));
				float hvVal = hVal * vVal;
				o.hvVal = float3(hVal, vVal, hvVal);
				float hVertexOffset = hvVal * _hOffset;
				float2 vVertexOffset = (o.worldPos.xz - o.centerPos.xz)*hvVal*_vOffset;
				float2 wind = _windOffset * hVal*_SinTime.w;
				float2 windPosXZOffset = vVertexOffset + wind;
				o.pos = UnityObjectToClipPos(v.vertex + float3(windPosXZOffset.x, hVertexOffset, windPosXZOffset.y));
				return o;
			}

			half4 frag(v2f i) : SV_Target
			{

				// sample the texture
				half4 col = tex2D(_MainTex, i.uv);
				clip(col.a - 0.5);
				return col;
			}
			ENDCG

		}

    }
}

二、和球的交互

unity草地互动


这里说的和球交互,是因为我不想花太多的时间去放一个角色模型进去并控制,所以我就简单的用一个球来代替。其实是模拟了一个人在草丛里面行走时,对草的交互。
既然是草被人挤开的动画,那么还是使用顶点动画来做了
unity草地,Unity引擎Shader效果,unity,交互,游戏引擎,草地,碰撞

这里需要定义一下球对草地的影响范围
unity草地,Unity引擎Shader效果,unity,交互,游戏引擎,草地,碰撞

假设球的坐标可以输入到shader里面,那么求出草的顶点和球坐标的距离,就可以过滤出离球比较近的一圈才会受到球的影响。
unity草地,Unity引擎Shader效果,unity,交互,游戏引擎,草地,碰撞

在刚才的顶点程序上面,再添加一点代码:

float roleDis = (1 - distance(o.worldPos.xz, rolePos.xz));
float2 roleNor = (o.worldPos.xz - rolePos.xz)*step(0, roleDis)*(roleDis*_roleMul);
float2 rolePosXZOffset = vVertexOffset + wind * (1 - roleNor) + roleNor * hVal;
float rolePosYOffset = hVertexOffset - saturate(roleDis*_roleHOffset);
o.pos = UnityObjectToClipPos(v.vertex+float3(rolePosXZOffset.x, rolePosYOffset, rolePosXZOffset.y));
return o;

需要注意:
1、rolePos不需要在shader的Properties里面声明,它是一个全局的变量,在C#代码里面,使用Shader.SetGlobalVector(“rolePos”, role.transform.position);来给它赋值
2、这里模拟的是一个角色的影响,如果是多个角色在草地里面移动,可以把rolePos全局变量变成数组,具体的实现可以自己试试。

这时候顶点的控制就受到了3个方面的影响:
1、重力
2、风力
3、球体的碰撞

完整的Shader:文章来源地址https://www.toymoban.com/news/detail-752206.html

Shader "azhao/GrassWindBall"
{
    Properties
    {
		_MainTex("MainTex", 2D) = "white" {}
		_hmin("hmin", Range(0 , 1)) = 0
		_hmax("hmax", Range(0 , 1)) = 1
		_hOffset("hOffset", Range(-1 , 1)) = 0
		_vmin("vmin", Range(0 , 1)) = 0
		_vmax("vmax", Range(0 , 1)) = 1
		_vOffset("vOffset", Range(-5 , 5)) = 0
		_topCol("topCol", Color) = (0,1,0,0)
		_windOffset("windOffset", Vector) = (0,0,0,0)
		_bottomCol("bottomCol", Color) = (0,0,0,0)
		_roleMul("roleMul", Range(0 , 10)) = 0
		_roleHOffset("roleHOffset", Range(0 , 10)) = 0
    }
    SubShader
    {
		Tags{"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" }
		Cull Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

			#pragma target 3.0
            #include "UnityCG.cginc"

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

            struct v2f
            {                
                float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 centerPos : TEXCOORD1;
				float3 worldPos : TEXCOORD2;
				float3 hvVal : TEXCOORD3;
            };

			uniform float _hmin;
			uniform float _hmax;
			uniform float _vmin;
			uniform float _vmax;
			uniform float _vOffset;
			uniform float2 _windOffset;
			uniform float3 rolePos;
			uniform float _roleMul;
			uniform float _hOffset;
			uniform float _roleHOffset;
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;
			uniform float4 _topCol;
			uniform float4 _bottomCol;
			SamplerState sampler_MainTex;

            v2f vert (appdata v)
            {
                v2f o;

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.centerPos = mul(unity_ObjectToWorld, float4(float3(0, 0, 0), 1)).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				float hVal = smoothstep(_hmin, _hmax, o.worldPos.y - o.centerPos.y);
				float vVal = smoothstep(_vmin, _vmax, distance(o.worldPos.xz, o.centerPos.xz));
				float hvVal = hVal * vVal;
				o.hvVal = float3(hVal, vVal, hvVal);
				float hVertexOffset = hvVal * _hOffset;
				float2 vVertexOffset = (o.worldPos.xz - o.centerPos.xz)*hvVal*_vOffset;
				float2 wind = _windOffset * hVal*_SinTime.w;
				float roleDis = (1 - distance(o.worldPos.xz, rolePos.xz));
				float2 roleNor = (o.worldPos.xz - rolePos.xz)*step(0, roleDis)*(roleDis*_roleMul);
				float2 rolePosXZOffset = vVertexOffset + wind * (1 - roleNor) + roleNor * hVal;
				float rolePosYOffset = hVertexOffset - saturate(roleDis*_roleHOffset);
				o.pos = UnityObjectToClipPos(v.vertex+float3(rolePosXZOffset.x, rolePosYOffset, rolePosXZOffset.y));
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
                // sample the texture
                half4 col = tex2D(_MainTex, i.uv);
				half3 finalCol = col.rgb * _topCol.rgb*i.hvVal.z + col.rgb;
				finalCol = clamp(finalCol*i.hvVal.x + _bottomCol * (1 - i.hvVal.x)*finalCol,  half3(0, 0, 0), half3(1, 1, 1));
				half alpha = col.a;
				clip(alpha - 0.5);
                return half4(finalCol,alpha);
            }
            ENDCG
        }
		
		//为了产生影子,加多一个pass
		Pass {
			Name "ShadowCaster"
			Tags { "LightMode" = "ShadowCaster" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 2.0
			#include "UnityCG.cginc"

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

			struct v2f
			{
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 centerPos : TEXCOORD1;
				float3 worldPos : TEXCOORD2;
				float3 hvVal : TEXCOORD3;
			};

			uniform float _hmin;
			uniform float _hmax;
			uniform float _vmin;
			uniform float _vmax;
			uniform float _vOffset;
			uniform float2 _windOffset;
			uniform float3 rolePos;
			uniform float _roleMul;
			uniform float _hOffset;
			uniform float _roleHOffset;
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;
			uniform float4 _topCol;
			uniform float4 _bottomCol;
			SamplerState sampler_MainTex;

			v2f vert(appdata v)
			{
				v2f o;

				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.centerPos = mul(unity_ObjectToWorld, float4(float3(0, 0, 0), 1)).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				float hVal = smoothstep(_hmin, _hmax, o.worldPos.y - o.centerPos.y);
				float vVal = smoothstep(_vmin, _vmax, distance(o.worldPos.xz, o.centerPos.xz));
				float hvVal = hVal * vVal;
				o.hvVal = float3(hVal, vVal, hvVal);
				float hVertexOffset = hvVal * _hOffset;
				float2 vVertexOffset = (o.worldPos.xz - o.centerPos.xz)*hvVal*_vOffset;
				float2 wind = _windOffset * hVal*_SinTime.w;
				float roleDis = (1 - distance(o.worldPos.xz, rolePos.xz));
				float2 roleNor = (o.worldPos.xz - rolePos.xz)*step(0, roleDis)*(roleDis*_roleMul);
				float2 rolePosXZOffset = vVertexOffset + wind * (1 - roleNor) + roleNor * hVal;
				float rolePosYOffset = hVertexOffset - saturate(roleDis*_roleHOffset);
				o.pos = UnityObjectToClipPos(v.vertex + float3(rolePosXZOffset.x, rolePosYOffset, rolePosXZOffset.y));
				return o;
			}

			half4 frag(v2f i) : SV_Target
			{
				// sample the texture
				half4 col = tex2D(_MainTex, i.uv);

				clip(col.a - 0.5);
				return col;
			}
			ENDCG

		}

    }
}

到了这里,关于Unity大面积草地渲染——2、草地的动态交互的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ChatGPT扩展系列之解决ChatGPT 被大面积封号的终极方案

    本节介绍了一个解决ChatGPT在中国大陆无法使用和担心被封号的问题的方法。近期有很多亚洲用户被封号,原因是有人滥用API接口或者批量注册账号,不符合官方规定。对于这个问题,提出了一个解决方法,可以在中国大陆无需翻墙使用ChatGPT,并且不用担心被封号。 最近两天

    2024年02月03日
    浏览(49)
  • 技术旋风!快速采集建模装备、重建大师6.1版、大面积实景三维轻量化技术...

    实景三维模型应用广度和深度日益扩大,传统测绘技术体系和生产体系正经历数字化变革。 传统激光点云数据量大、空间点离散、缺少语义信息、直接应用困难 ;而 传统倾斜摄影采集与建模周期长、生产效率低下 。二者均已无法满足各细分行业 更快速、高效、精细化的建

    2024年02月09日
    浏览(38)
  • 关于4月2号OpenAI大面积封停亚洲(中国大陆)帐号的问题和应对策略

            此次OpenAI封的全部都是批量注册的号,这些一般都是具有一定编程能力的人,使用脚本注册的账号,目的是为了耗ChatGPT-API的5美元羊毛.         少部分受害者是刚出墙不久,没有自己的谷歌,微软账号,出墙时间太短,账号行为为高风险导致.         总的来说,此次封禁针对

    2024年02月02日
    浏览(56)
  • 【Unity URP】风格化草地01:实现方法概述

    写在前面 最近本专业开始多很多事情了,要开始建模写论文了(不然研究生毕不了业),TA方面的学习进度更慢了,,so sad。 废话不多说,这篇文章其实是个小总结,毕竟学习新东西就是先要当一只copy cat(不是)。 至于草地交互,把草地做出来再说! 2021.5 【Unity】ShaderG

    2023年04月21日
    浏览(58)
  • Unity地面交互效果——2、动态法线贴图实现轨迹效果

    回到目录 Unity引擎动态法线贴图制作球滚动轨迹   大家好,我是阿赵。   之前说了一个使用局部UV采样来实现轨迹的方法。这一篇在之前的基础上,使用法线贴图进行凹凸轨迹的绘制。   先来回顾一下,上一篇最终我们已经绘制了一个轨迹的贴图   可以思考一下,

    2024年02月06日
    浏览(73)
  • 【Unity】 基础交互入门(C#脚本互相调用的方法,含动态绑定脚本)

    脚本A: 在需要被调用的类里这样写: 脚本B: 在其他类里调用: 如果出现无法识别上下文的提示,检查一下以下问题: 1、两个脚本的命名空间是否一致,如果不需要的命名空间可以直接删除。 2、类名是否大写开头,且命名合法,且和文件名一致。 3、更新编译一下保存一

    2024年02月15日
    浏览(53)
  • 【Unity Shader】Unity前向渲染

    ForwardBase Pass(优先渲染),渲染一个逐像素平行光和所有的顶点/球面调和光,阴影只和平行光有关系,那阴影应该是这个Pass中实现的 ForwardAdd Pass(需要和Base配合使用,否则不生效),渲染剩余全部逐像素灯光 Unity会根据场景中各个光源的设置以及这些光源对物体的影响程

    2024年02月08日
    浏览(59)
  • 【sketchup 2021】草图大师图像输出与渲染之Enscape渲染(优秀的实时渲染软件)的基本使用【渲染实时更新与同步、在线资源库、渲染和常规设置(图标背景、草地渲染)、导出为图像和独立文件】

    前面上一篇安装中已经我们已经说过了enscape工具的调出,我这把工具栏放到了最底下,并且安装正确的话,顶上的扩展程序中也能看到enscape。 启动的话直接点击工具栏中的这个图标即可【顶上的扩展程序中也可以启动】 启动过程如果性能不好,会很慢,此时不要动键盘鼠标

    2024年02月08日
    浏览(71)
  • 【Unity 渲染】烘焙渲染出现白色光斑的问题

    Unity场景烘焙后有时会遇到某些物体泛白光,产生白色光斑的问题,例如笔者最近在开发一个三维场景,白光如下:  可以看到在门的背后有白色光斑泛起,内部是这样的: 那么,这个的原因是什么呢? 笔者按以下步骤考虑了这些方面: 一、Lightmap UV是否正确? Lightmap UV如果

    2024年02月02日
    浏览(41)
  • Unity Shdaer 前向渲染与延时渲染

    目录 1.前向渲染Forward 1.1 渲染设置 1.2 两个pass块 1.3 Unity如何判断光源类型 1.4 性能影响 2.延时渲染Deffered 2.1 原理 2.2 两部分Shdaer 2.3 性能影响 2.4 不足 Unity中的渲染路径有多种,可以在Editor/ProjectSetting中的Graphics中进行调整。当取消掉Use Defaults时,可以在Rendering Path中进行切换

    2024年01月19日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包