Unity 大面积花草风吹动效果以及编辑


声明:本文转载自https://my.oschina.net/u/3700246/blog/1800428,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

项目场景需求一个遍布鲜花的小岛,由于运行在手机上,所以对效率有一定的要求。

环境unity2017.3.f1,使用simpleLOD这个插件,方便做mesh合并,以及LOD处理

先放1张最终的效果图。

1.shader编写

    先找来一个花的模型,贴图模型大致如下:

shader采用双面渲染,VS阶段做一个顶点运动。大致思路是花越靠近地面的,摇晃幅度越小,反之幅度越大。这个高度可以用定点坐标来做,不过要兼容静态烘焙,或者地面不平等情况,无法获取准确高度。我这里采用UV的思路(美术保证草的根在贴图底部)。

代码如下

Shader "custom/2-sided_grass" {     Properties      {         _Color ("Main Color", Color) = (1,1,1,1)         _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 0)         _Shininess ("Shininess", Range (0.01, 10)) = 0.078125         _MainTex ("Base (RGB) TransGloss (A)", 2D) = "white" {}         _BumpMap ("Normalmap", 2D) = "bump" {}         _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5          _Direction("Direction",Vector) =(0,0,0,0) //运动的方向         _TimeScale("TimeScale",float) = 1        //时间         _TimeDelay("TimeDelay",float) = 1     //延迟     }      SubShader      {         Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}         LOD 400              Cull Back              CGPROGRAM         #pragma surface surf BlinnPhong alphatest:_Cutoff vertex:vert         #pragma target 3.0              sampler2D _MainTex;         sampler2D _BumpMap;         fixed4 _Color;         half _Shininess;         fixed4 _Direction;         half _TimeScale;         half _TimeDelay;          struct Input          {             float2 uv_MainTex;             float2 uv_BumpMap;         };              void vert(inout appdata_full v)          {             fixed4 worldPos =  mul(unity_ObjectToWorld,v.vertex);             half dis =  v.texcoord.y; //这里采用UV的高度来做。也可以用v.vertext.y             half time = (_Time.y + _TimeDelay) * _TimeScale;             v.vertex.xyz += dis * (sin(time + worldPos.x) * cos(time * 2 / 3) + 0.3)* _Direction.xyz;    //核心,动态顶点变换         }           void surf (Input IN, inout SurfaceOutput o)          {             fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);             o.Albedo = tex.rgb * _Color.rgb;             o.Gloss = tex.rgb * _Color.rgb;             o.Alpha = tex.a * _Color.a;             o.Specular = _Shininess;             o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));         }         ENDCG         Cull Front          CGPROGRAM         #pragma surface surf BlinnPhong alphatest:_Cutoff vertex:vert         #pragma target 3.0          sampler2D _MainTex;         sampler2D _BumpMap;         fixed4 _Color;         half _Shininess;         fixed4 _Direction;         half _TimeScale;         half _TimeDelay;          struct Input          {             float2 uv_MainTex;             float2 uv_BumpMap;         };         void vert(inout appdata_full v)          {                     fixed4 worldPos =  mul(unity_ObjectToWorld,v.vertex);             half dis = v.texcoord.y;             half time = (_Time.y + _TimeDelay) * _TimeScale;             v.vertex.xyz += dis * (sin(time + worldPos.x) * cos(time * 2 / 3) + 0.3) * _Direction.xyz ;    //核心,动态顶点变换         }           void surf (Input IN, inout SurfaceOutput o)          {             fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);             o.Albedo = tex.rgb * _Color.rgb;             o.Gloss = tex.rgb * _Color.rgb;             o.Alpha = tex.a * _Color.a;             o.Specular = _Shininess;             o.Normal = -UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));         }             ENDCG         }          FallBack "Transparent/Cutout/VertexLit" }

 

2.简单的笔刷

 能够在场景里面编辑。能够调整大小,草密度,随机大小,绕Y轴旋转等,我们写一个简单的管理脚本,也方便做Mesh合并以及LOD。GrassGroup代码如下

using System.Collections; using System.Collections.Generic; using UnityEngine; public class GrassGroup : MonoBehaviour {     [Tooltip("是否打开编辑")]     public bool editorMode = false;     [Tooltip("预制体")]     public GameObject grassPrefab = null;     [Tooltip("地形")]     public Terrain terrain = null;     [Tooltip("随机朝向")]     public bool roodomRotationY = true;     [Tooltip("随时缩放最小值")]     public float minScale = 1;     [Tooltip("随时缩放最小值")]     public float maxScale = 1;     [Tooltip("半径")]     [HideInInspector]     public float radius = 1;     [Tooltip("数量")]     [HideInInspector]     public int count = 1;      // Use this for initialization     void Start ()     {         editorMode = false;     }     /// <summary>     /// 生成子草     /// </summary>     /// <param name="postion"></param>     public void AddGrassNode(Vector3 postion)     {         if (grassPrefab == null)         {             Debug.LogError("草预制件不能为空!!!!!");             return;         }          if (terrain == null)         {             Debug.LogError("地形不能为空!!!!!");             return;         }          for (int i = 0;i<count; i++)         {             GameObject go = GameObject.Instantiate(grassPrefab);             go.transform.SetParent(transform);             Vector2 p = Random.insideUnitCircle * radius;//将位置设置为一个半径为radius中心点在原点的圆圈内的某个点X.               Vector2 pos2 = p.normalized * (p.magnitude);             Vector3 pos3 = new Vector3(pos2.x, 0, pos2.y) + postion;             float y = terrain.SampleHeight(pos3);             Vector3 pos = new Vector3(pos3.x ,y, pos3.z);             go.transform.position = pos;             if (roodomRotationY)                 go.transform.Rotate(new Vector3(0, 0, 1),Random.Range(0,360) );             float scale = Random.Range(minScale, maxScale);             go.transform.localScale = new Vector3(scale, scale, scale);             go.name = "grass_" + transform.childCount.ToString();         }     } }

Editor代码,简单写了下(注:HeGizmosCircle 是一个画圆的代码,稍微修改了下,网上找的https://www.cnblogs.com/TravelingLight/archive/2013/08/27/3286242.html

using UnityEngine; using UnityEditor;  [CustomEditor(typeof(GrassGroup))] public class GrassGroup_Inspector : Editor {     private GrassGroup grassGroup = null;     private float m_Theta = 0.1f; // 值越低圆环越平滑       private Color m_Color = Color.blue; // 线框颜色       private HeGizmosCircle heGizmosCircle = null;     void OnEnable()     {         grassGroup = target as GrassGroup;         if (heGizmosCircle == null)             heGizmosCircle = GameObject.FindWithTag("HeGizmosCircle").GetComponent<HeGizmosCircle>();     }     void OnDisable()     {         if (heGizmosCircle != null)         {             heGizmosCircle.SetEnable(grassGroup.editorMode);         }              }     public override void OnInspectorGUI()     {          base.OnInspectorGUI();         GUILayout.BeginHorizontal();         GUILayout.Label("radius(半径):" + grassGroup.radius.ToString());         grassGroup.radius = GUILayout.HorizontalSlider(grassGroup.radius, 0, 10, null);         if (heGizmosCircle != null)             heGizmosCircle.m_Radius = grassGroup.radius;         GUILayout.EndHorizontal();         GUILayout.BeginHorizontal();         GUILayout.Label("count(数量):" + grassGroup.count.ToString());         grassGroup.count = System.Convert.ToInt32(GUILayout.HorizontalSlider(grassGroup.count, 1, 100, null));         GUILayout.EndHorizontal();     }      [MenuItem("地图编辑/创建GrassGroup")]     static void CreateGrassGroup()     {         GameObject go = new GameObject("GrassGroup");         GrassGroup group = go.AddComponent<GrassGroup>();         go.transform.position = Vector3.zero;     }      public void OnSceneGUI()     {         if (grassGroup ==null || !grassGroup.editorMode)             return;          if (grassGroup.editorMode)         {             Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);             RaycastHit hitInfo;             if (Physics.Raycast(ray, out hitInfo, 1 << 8))             {                 heGizmosCircle.transform.position = hitInfo.point + new Vector3(0,0.2f,0);                 if (Event.current.type == EventType.MouseDown)                 {                     grassGroup.AddGrassNode(hitInfo.point);                 }                        }         }     } }

3.地图编辑以及合并mesh.

代码基本写完了,大致如下

勾上EditorMode即可在场景中编辑

使用SimpleLOD合并mesh,分组做LOD(我这里没做LOD,面有点多)。

看看最后shader参数,以及DrawCall等效率

这张去掉地形,只有天空盒子,花

面有点高,可以分组做LOD

 

本文发表于2018年04月24日 22:38
(c)注:本文转载自https://my.oschina.net/u/3700246/blog/1800428,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 4638 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1