文章目錄
- 一、前言
- 二、效果演示
- 三、常春藤生成器工具下載
- 四、 工具使用
- 1、創建根節點:lvy GameObject
- 2、創建組態檔:lvy Profile Asset
- 3、貼圖與材質球
- 4、繪制常春藤
- 5、修改葉子顏色
- 6、修改葉子大小
- 7、修改葉子密度
- 8、修改根莖粗細
- 9、修改生長長度
- 10、修改分支概率
- 11、洗掉已繪制的常春藤
- 五、拓展知識解答
- 1、常春藤的Mesh資源存放在哪里
- 2、如何洗掉無用的Mesh
- 3、如何獲取滑鼠投射到物體表面的位置
- 4、場景中的水面是怎么做的(半透明和反射效果)
- 5、場景中的天空是怎么做的
- 6、場景中的草是怎么做的,為什么它會搖啊搖
- 六、結束語
一、前言
嗨,大家好,我是新發,
記得初中的時候幼ò肝本里有一篇名字叫《最后一片葉子》的文章,作者是著名的短篇小說家歐·亨利,
《最后一片葉子》又叫《最后一片常春藤葉》,文中講述了老畫家貝爾曼為了鼓勵貧病交加的青年畫家頑強地活下去,在風雨之夜掙扎著往墻上畫了一片永不凋零的常春藤葉,他為此用生命繪制的杰作付出了生命的代價,但青年畫家卻因此獲得勇氣而活了下來的故事,
常春藤寓意著希望、朝氣蓬勃,也象征著忠誠,還代表著和不朽的青春,因為它一年四季都是常綠的,所以很多人喜歡在陽臺上種常春藤,顯得格外有生氣,本文,我就來證明一下常春藤的魔力,我將在Unity中演示制作常春藤的程序,并講解其中涉及到的一些技術知識點,
二、效果演示
場景,我希望是在一個優美的島嶼城堡,我找到了一個不錯的場景,如下:
注:喜歡這個城堡場景資源的同學,可以自行從這里下載:https://assetstore.unity.com/packages/3d/props/exterior/low-poly-brick-houses-131899

在窗戶上繪制生成常春藤,如下:

對比下前后效果,是不是有了常春藤之后,瞬間生機盎然了~

三、常春藤生成器工具下載
我使用的是Github的這個工具:hedera,這個工具可以很方便地在場景中制作并生成常春藤一樣的植物,感興趣的同學可以下載從GitHub上下載來學習,
GitHub地址:https://github.com/radiatoryang/hedera

四、 工具使用
1、創建根節點:lvy GameObject
點擊選單Hedera / Create / Create New lvy GameObject,

此時會生成一個lvy Group節點,它身上會帶一個lvyBehavior組件,我們下面生成的常春藤就是在這個節點之下生成的,

2、創建組態檔:lvy Profile Asset
上面我們可以看到,lvyBehavior組件需要指定一個組態檔,這個組態檔用于配置常春藤生成的規則與相關引數,
工具已經幫我們做好了幾個配置,在Runtime/lvyProfiles目錄中,

為了演示,我創建一個新的,點擊Create new lvy Profile Asset...按鈕,

將其保存到Runtime/lvyProfiles目錄中,

生成后選中它,可以在Inspector視圖中看到配置的引數,

引數說明:
| 引數 | 說明 |
|---|---|
| Length | 生成長度,可以設定上下限,從這個范圍內進行隨機 |
| Branch Chance % | 生成分支的概率 |
| Random Spread % | 隨機分布率 |
| Branch Thickness | 根莖的粗度 |
| Leaf Size Radius | 葉子大小 |
| Leaf Density % | 葉子密度 |
| Leaf Colors | 葉子顏色 |
| Brahcn Material | 根莖的材質 |
| Leaf Material | 葉子的材質 |
3、貼圖與材質球
我們需要先準備常春藤的貼圖(包括根莖+葉子),例:

制作根莖和葉子的材質球:

材質球設定如下(根莖+葉子):

給lvy Profile Asset設定根莖和葉子的材質球,

4、繪制常春藤
選中lvy Group,點擊Start Painting lvy按鈕,

然后把滑鼠移到Scene視圖中,即可看到有個藍紫色的圈圈投射在物體表面上,

此時按住滑鼠滑動即可生成常春藤,

5、修改葉子顏色
我們看到繪制出來的葉子顏色是 白/綠/黃 的,

這是因為在lvy Profile Asset中設定的葉子顏色是這樣的:

我們可以將其修改成我們想要的其他顏色,比如改成這樣:

重新繪制出來的葉子顏色如下:

6、修改葉子大小
調整Leaf Size Radius可以修改葉子的大小,

我們把葉子大小調小,調整引數后可以點擊Re-mesh Visible按鈕,就會根據調整后的引數重新運算~

調整前是這樣:

調整后是這樣:

7、修改葉子密度
調整Leaf Density %可以修改葉子密度,

我們把葉子密度調大,如下:

8、修改根莖粗細
我們覺得根莖有點粗,

想調細一點,調整Branch Thickness,把根莖調細,

如下:

9、修改生長長度
調整Length可以修改生長長度,

我們測驗下最小值和最大值的效果,調整為最小值,此時繪制常春藤不會自動繼續生長,

效果如下:

現在,我們把Lehgth調為最大值,

因為它生長力太強了,所以我在地面上演示,感受一下,

10、修改分支概率
我們看到生長程序中的分支概率比較低,我們可以調整Branch Chance %來修改分支概率,

我們把分支概率調到最大值,感受一下,

11、洗掉已繪制的常春藤
假設我們要洗掉這條常春藤,并不是直接delete它的GameObject,

而是先選中它所在的Group,

然后點擊對應的垃圾桶按鈕,

如果一個Group下有多條常春藤,則會會顯示多個item,

五、拓展知識解答
1、常春藤的Mesh資源存放在哪里
我們點開常春藤的節點,可以看到一個根莖節點和一個葉子節點,

工具幫我們生成了根莖和葉子的Mesh,這些Mesh檔案會自動存放在場景所在目錄的同名目錄中,

它是序列化在一個.assset檔案中的,

根莖的Mesh,

葉子的Mesh,

思考:它是如何將網格資源序列化到asset檔案中的?
解答:
需要序列化的類繼承ScriptableObject,例:
public class IvyDataAsset : ScriptableObject
{
//...
}
通過ScriptableObject.CreateInstance創建序列化檔案,例:
public static IvyDataAsset CreateNewDataAsset(string mainFolder, string sceneName, string path)
{
if ( !AssetDatabase.IsValidFolder(path) ) {
var folderGUID = AssetDatabase.CreateFolder( mainFolder, sceneName );
path = AssetDatabase.GUIDToAssetPath(folderGUID);
}
IvyDataAsset asset = ScriptableObject.CreateInstance<IvyDataAsset>();
AssetDatabase.CreateAsset(asset, path + "/HederaData.asset");
AssetDatabase.SaveAssets();
return asset;
}
然后在IvyDataAsset中定義需要序列化的內容,
// IvyDataAsset.cs
public class IvyDataAsset : ScriptableObject
{
public IvyDictionary meshList = new IvyDictionary();
[System.Serializable]
public class IvyDictionary : SerializableDictionary<long, Mesh> { }
[System.Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField]
private List<TKey> keys = new List<TKey>();
[SerializeField]
private List<TValue> values = new List<TValue>();
// ...
}
}
關于Unity的類的序列化,還可以參見我早先寫的這篇文章:《unity 類的序列化》
如果我們想要自定義Inspector界面的內容,我們還可以寫對應的Editor類,重寫OnInspectorGUI函式,例:
// IvyDataAssetEditor.cs
[CustomEditor( typeof(IvyDataAsset))]
public class IvyDataAssetEditor : Editor
{
public override void OnInspectorGUI()
{
var data = (IvyDataAsset)target;
// ...
}
}
2、如何洗掉無用的Mesh
選中HederaData檔案,點擊Cleanup Unreferenced Meshes按鈕,介面自動清理無用的Mesh資源,

對應的邏輯:
// IvyDataAssetEditor.cs
if ( GUILayout.Button(content) ) {
var allReferencedMeshes = data.meshList.Values.ToList();
for ( int i=0; i<allSubassets.Length; i++ ) {
if (!allReferencedMeshes.Contains((Mesh)allSubassets[i])) {
Object.DestroyImmediate(allSubassets[i], true);
}
}
EditorUtility.SetDirty(data);
AssetDatabase.SaveAssets();
}
3、如何獲取滑鼠投射到物體表面的位置
上面我們看到,滑鼠移到Scene視圖中,可以看到有個藍紫色的圈圈投射在物體表面上,這個是如何實作的呢~

用的是射線檢測介面:
public static bool Raycast(
Vector3 origin,
Vector3 direction,
out RaycastHit hitInfo,
float maxDistance,
int layerMask,
QueryTriggerInteraction queryTriggerInteraction);
例:
// IvyEditor.cs
public void MousePosition ()
{
// 射線
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
RaycastHit hit;
// 射線檢測
if (Physics.Raycast(ray.origin,
ray.direction,
out hit,
Mathf.Infinity,
ivyBehavior.profileAsset.ivyProfile.collisionMask,
QueryTriggerInteraction.Ignore))
{
mousePos = hit.point + hit.normal * 0.05f;
mouseNormal = hit.normal;
Handles.color = Color.blue;
// 繪制線圈
DrawThiccDisc(mousePos, hit.normal, Mathf.Max(0.1f, ivyBehavior.profileAsset.ivyProfile.ivyStepDistance));
// 繪制法線
Handles.DrawLine(mousePos, mousePos + hit.normal * 0.25f);
}
}
// 繪制線圈
void DrawThiccDisc(Vector3 mousePos, Vector3 normal, float radius)
{
var originalColor = Handles.color;
Handles.color = new Color( originalColor.r, originalColor.g, originalColor.b, 0.4f);
Handles.DrawSolidDisc( mousePos, normal, radius);
Handles.color = originalColor;
Handles.DrawWireDisc(mousePos, normal, radius - 0.01f );
Handles.DrawWireDisc(mousePos, normal, radius );
Handles.DrawWireDisc(mousePos, normal, radius + 0.01f );
}
注:我之前寫了一篇文章,《使用Unity ShaderGraph實作在模型上涂鴉的效果,那么,紋個手吧》,里面也用到了射線檢測,感興趣的同學可以打開閱讀以下~
4、場景中的水面是怎么做的(半透明和反射效果)

先創建一個空白的平面(Plane)作為水底,

再創建一個平面作為水面,

為水面創建一個材質球,

材質球設定為半透明模式(Transparent),設定一下顏色,提高光滑度(Smoothness),

這樣,水面就具有半透明效果,同時也可以反射天空的影像,我們創建個Cube測驗一下,

5、場景中的天空是怎么做的

場景中的天空是用天空盒做的,我們需要先準備720度天空全景圖,可以把自己想象成坐在一個正方體的內部,這六張圖就是對應正方體里面的6個面(前后左右上下),

創建一個材質球,shader使用Skybox/6 Sided,然后設定前后左右上下6個面的貼圖,

最后,把材質球拖到Scene視圖空白處即可,或者點擊選單Window / Rendering / Lighting,

點擊Environment標簽頁,設定天空盒材質球即可,

我上一篇文章《[原創] 用Unity等比例制作廣州地鐵,廣州加油,早日戰勝疫情(Unity | 地鐵地圖 | 第三人稱視角)》里面也用到了天空盒:

更多免費天空盒資源下載:
https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353
https://assetstore.unity.com/packages/2d/textures-materials/sky/8k-skybox-pack-free-150926
https://assetstore.unity.com/packages/2d/textures-materials/sky/customizable-skybox-174576
https://assetstore.unity.com/packages/vfx/shaders/free-skybox-extended-shader-107400
https://assetstore.unity.com/packages/2d/textures-materials/sky/farland-skies-cloudy-crown-60004
6、場景中的草是怎么做的,為什么它會搖啊搖

場景中的草一搖一搖的,這是怎么做的呢~
這里用到了Unity的地形編輯器Terrain,草是地形的一部分,我們把環境中其他物體隱藏起來,只留下地形,如下:

所以我們需要先創建一個地形,在Hierarchy視圖空白處右鍵滑鼠,點擊選單3D Object / Terrain,

此時就可以創建一個地形物體,

它身上會帶一個Terrain組件,我們點擊Place Details按鈕(第四個按鈕,我圈出來那個),我們就可以在地形上刷出細節物體,通常用來做草,

不過這個時候我們什么也刷不出來,這是因為我們還沒有設定筆刷圖片,

我們先準備一張草的圖片,如下:

點擊Edit Details...按鈕,

點擊Add Grass Texture按鈕,

設定Detail Texture````為剛剛的草的圖片,點擊Add```按鈕,

其他引數說明:
| 引數 | 說明 |
|---|---|
| Detail Texture | 選擇一張花或者草的貼圖 |
| Min Width、Max Width、Min Height、Max Height | 單個草物體的最大最小的寬高值 |
| Noise Spread | 添加一點分布隨機度 |
| Healthy Color | 草的健康顏色(會被tint到貼圖的上部) |
| Dry Color | 草的干枯顏色(會被tint到貼圖的底部) |
| Billboard | 是否以永遠面向攝像機的單面形式生成單個草物體,如果選否的話就會以十字交叉雙平面方式來生成單個草物體 |
這樣草的筆刷圖片就制作好了,

這樣就可以刷出草地啦~

如果想要洗掉草地,只需要按住Ctrl鍵不放,滑鼠一刷,就可以把對應的草地洗掉了~

這些草之所以會搖啊搖,是因為有風,Terrain組件的設定里可以設定風的大小等引數,如下:

細心的朋友應該注意到了,這個草堆并不是地形刷出來的,為什么它也會搖啊搖,

這個是通過shader的頂點著色器來控制的,例:
// FoliageShader.shader
float random(float3 p)
{
return frac(43758.5453 * sin(dot(p, float3(12.9898, 78.233, 45.5432)) % 3.14159));
}
// 頂點著色器
void vert(inout appdata_full v)
{
// 隨機偏移
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 offset = _Intensity * (sin(worldPos.xyz + _Time.y * _WindSpeed) + _Randomness * random(worldPos));
// 設定頂點坐標偏移
v.vertex.xyz += offset;
}
六、結束語
好了,就先寫這么多吧,如果有什么疑問,歡迎留言或私信~
最后,曬下我小屋的常春藤~

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286912.html
標籤:其他
上一篇:Microsoft Edge 瀏覽器開發控制元件WebView2 嘗鮮
下一篇:十年自學編程成才(編程小白必看)

