I explain how to create rain with Unity and upload it to STYLY.
※You can access the sample project from https://github.com/styly-dev/STYLY-Unity-Examples/tree/master/Assets/STYLY_Examples/Rain
How to create rain
Before creating rain, I give an overview of how to create it.
It requires 3 STEPS as shown below.
- Create a lot of triangular meshes.
- Shake the triangular meshes arranged at high speed.
- Adjust the colour to make them look like rain (Completion).
Create a lot of triangular meshes
I arranged a lot of fine triangular meshes so that they fill a cube.
Shake the triangular meshes at high speed
Shake the vertices by Vertex Shader
Adjust the colour to make them look like rain (completion)
Colour the meshes in translucent light blue to make them look like rain. It completes modelling rain.
Create meshes
From now, I explain the actual steps to model rain.
Firstly, we create meshes.
Preparations
This time, we use two C# scripts to create triangular meshes.
I explain how to add two C# scripts here.
Script 1: Create RandomMesh.cs
Firstly, right-click in the Project window to create a C# script.
Rename it RandomMesh.
Open the script, RandomMesh, and edit it as shown below.
using UnityEngine; using System.Collections.Generic; [RequireComponent(typeof(MeshRenderer))] [RequireComponent(typeof(MeshFilter))] public class RandomMesh : MonoBehaviour { const string k_MeshName = "[Generated]RainMesh"; // Mesh Name [SerializeField, Header("The number of raindrops")] int m_TriangleCount = 1500; // The number of triangular meshes [SerializeField, Header("The size of raindrop")] float m_TriangleScale = 0.3f; // The size of triangular meshes [SerializeField, Header("The randomness of rain")] Vector3 m_TriangleRange = new Vector3(4f, 4f, 4f); // The randomness of rain [SerializeField, HideInInspector] string m_OnCreateText = "No mesh information\n Update Mesh"; public int TriangleCount { get { return m_TriangleCount; } } public float TriangleScale { get { return m_TriangleScale; } } public Vector3 TriangleRange { get { return m_TriangleRange; } } public string OnCreateText { get { return m_OnCreateText; } set { m_OnCreateText = value; } } /// <summary> /// Craete a new mesh /// </summary> public Mesh CreateNewMesh() { Vector3[] vertices = new Vector3[m_TriangleCount * 3]; // The coordinates of vertex int[] triangles = new int[m_TriangleCount * 3]; // The index of vertex Vector3[] normals = new Vector3[vertices.Length]; int pos = 0; for (int i = 0; i < m_TriangleCount; i++) { var v1 = Vector3.Scale(new Vector3(Random.value, Random.value, Random.value) - Vector3.one * 0.5f, m_TriangleRange); var v2 = v1 + new Vector3(Random.value - 0.5f, 0f, Random.value - 0.5f) * m_TriangleScale; var v3 = v1 + new Vector3(Random.value - 0.5f, 0f, Random.value - 0.5f) * m_TriangleScale; vertices[pos + 0] = v1; vertices[pos + 1] = v2; vertices[pos + 2] = v3; pos += 3; } for (int i = 0; i < triangles.Length; i++) { triangles[i] = i; } for (int i = 0; i < normals.Length; i++) { normals[i] = new Vector3(0f, 1f, 0f); } //Create a mesh var mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; mesh.normals = normals; return mesh; } }
It completes the RandomMesh script.
Script2: Create RandomMeshInspector.cs
In the same way, create a script, RandomMeshInspector, as well.
Edit the content of the RandomMeshInspector script as shown below.
using UnityEngine; using UnityEditor; using UnityEditor.SceneManagement; using System.IO; // Customize Editor [CustomEditor(typeof(RandomMesh))] public class RandomMeshInspector : Editor { const string k_ExportMeshName = "[Generated]RainMesh"; // The name of the mesh to save static readonly Color k_ButtonColor = Color.yellow; static readonly Color k_ButtonTextColor = Color.white; /// <summary> /// Drawing the Inspector /// </summary> public override void OnInspectorGUI() { if (PrefabUtility.GetPrefabType(target) != PrefabType.Prefab) { EditorGUILayout.HelpBox("You must edit settings via Prefab.", MessageType.Info); return; } var defaultColor = GUI.color; var defaultContentColor = GUI.contentColor; var randomMesh = target as RandomMesh; // Display mesh inforamtion EditorGUILayout.BeginVertical("Box"); EditorGUILayout.LabelField(randomMesh.OnCreateText, GUILayout.Height(54f)); EditorGUILayout.EndVertical(); // Change colour GUI.color = k_ButtonColor; GUI.contentColor = k_ButtonTextColor; if (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab) { if (GUILayout.Button("Update Mesh")) { EditorCreateMesh(); } } // Undo GUI.color = defaultColor; GUI.contentColor = defaultContentColor; base.DrawDefaultInspector(); } /// <summary> /// Create and save mesh /// </summary> [ContextMenu("Create Mesh")] void EditorCreateMesh() { var randomMesh = target as RandomMesh; var meshFilter = randomMesh.GetComponent<MeshFilter>(); // Delete the old mesh installed var meshAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(randomMesh)); foreach (var meshAsset in meshAssets) { if (meshAsset is Mesh) { Object.DestroyImmediate(meshAsset, true); } } // Create mesh var newMesh = randomMesh.CreateNewMesh(); newMesh.name = k_ExportMeshName; meshFilter.sharedMesh = newMesh; // Install new mesh AssetDatabase.AddObjectToAsset(newMesh, randomMesh); randomMesh.OnCreateText = string.Format( "Mesh Information\n・The number of raindrops:{0}\n・The size of raindrops:{1}\n・The size of whole rain: {2}", randomMesh.TriangleCount, randomMesh.TriangleScale, randomMesh.TriangleRange ); // Save AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } /// <summary> /// Generate the path to save mesh(at the same level as Prefab) /// </summary> string GenerateMeshPath() { var path = AssetDatabase.GetAssetPath(target); var parentFullPath = Directory.GetParent(path).FullName; var parentPath = "Assets" + parentFullPath.Substring(Application.dataPath.Length); var assetPath = parentPath + Path.DirectorySeparatorChar + k_ExportMeshName; // The path to save the asset return assetPath; } }
The two C# scripts required are ready now.
Create Meshes
Next, we actually create triangular meshes.
Create a Rain object
Create a GameObject on the Hierarchy window.
Rename the object ‘Rain‘.
Add the RandomMesh component
Add the RandomMesh component to the Rain object.
The Inspector looks the shown below after adding the component.
Convert the Rain object into Prefab
Next, convert the Rain object into a Prefab.
Drag the Rain object in the Hierarchy window onto the Project window.
A Prefab has been created.
Create meshes
With the Rain prefab selected, click the ‘Update Mesh’ button on the Inspector window.
A lot of triangular meshes are displayed.
Why are the meshes coloured in pink?
You can see meshes coloured in pink. That is because no material has been assigned to the MeshRenderer of the Rain object.
Once a material is assigned, you can adjust the colour.
Assign a material to MeshRender
I will show how to assign a material to the MeshRenderer.
Expand the Materials section of the MeshRenderer.
Click the circular button on the Materials section to bring up the material-list window. Select the material you want to assign.
Select ‘Default-Diffuse’ to assign the Default-Diffuse material to the MeshRenderer.
If assigned the Default-Diffuse material, they would be coloured in white.
Add motion to triangular meshes
Next, we add motion to the meshes to make them look like rain.
I explain how to add motion to the triangular meshes here.
Create a motion by Custom Shader
This time, we use ‘Custom Shader’ to move vertices like rain.
Create Custom Shader
I explain how to create a custom shader here.
Firstly, click ‘Create’ on the Project window (Alternatively, right-click on the Project window).
Select ‘Shader/Standard Surface Shader‘.
A shader is created. Rename it ‘Rain‘.
Edit the shader file
Open the Rain shader.
Edit Rain.shader as shown below.
Shader "Custom/Rain" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _Speed ("[VS]Rain Speed", Float) = 6.0 _Scale ("[VS]Rain Height", Float) = 4.0 _Remap("[VS]Remap", Range(0.0, 1.0)) = 0.7 [Space] _Albedo ("[FS]Rain Colour", Color) = (1.0, 1.0, 1.0, 0.5) _Emission ("[FS]Rain Emission Colour", Color) = (0.0, 0.0, 0.0, 0.0) _Specular ("[FS]Rain Specular Power", Range(0.0, 1.0)) = 0.5 _Gloss ("[FS]Rain Specular Intensity", Range(0.0, 1.0)) = 0.5 } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } CGPROGRAM #pragma surface surf Lambert alpha #pragma vertex vert sampler2D _MainTex; // Function to generate random value from [0;1] float nhash11(float n){ return frac(sin(n) * 43758.5453); } // Convert the range [a;b] into [0;1] float remap(float t, float a, float b){ return clamp((t-a)/(b-a), 0, 1); } // Vertex Shader half _Speed; half _Scale; half _Range; fixed _Remap; // Colour half4 _Albedo; half4 _Emission; fixed _Specular; fixed _Gloss; // Vertex Shader Function void vert(inout appdata_full v) { fixed rnd = nhash11(fmod(v.vertex.z, 512.0)); // Random value //float timer = _Time.w * _Speed * remap(0.7, 1.0, rnd); float timer = _Time.w * _Speed * remap(_Remap, 1.0, rnd); // Convert the range [_Remap, 1.0] -> [0;1] v.vertex.y -= fmod(-v.vertex.y + timer, _Scale) + v.vertex.y - _Scale * 0.5; // v.vertex.y -= fmod(-v.vertex.y + timer, 4.0 / _Range) + v.vertex.y - _Scale * 0.5; } struct Input { float2 uv_MainTex; }; // Surface Shader Function void surf(Input IN, inout SurfaceOutput o) { half4 c = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = c.rgb * _Albedo.rgb; o.Emission = _Emission; o.Specular = _Specular; o.Gloss = _Gloss; o.Alpha = _Albedo.a; } ENDCG } }
It completes editing the shader.
Additional Note: About the filename of Shader
The shader name is ‘Rain‘ on Unity, but the actual filename is ‘Rain.shader‘.
You can check the filename at the bottom of the Project window.
Create Material
Next, I explain how to create a material.
Right-click the Rain shader and select ‘Create/Material‘.
A material, ‘Custom_Rain’, has been created.
It finishes creating a material to shake the vertices.
Test the material
Assign the Custom_Rain material created to a 3D model in the Scene.
When you assign the material to a 3D model, the model moves as shown below.
The Custom_Rain material moves the vertices of the model so that it gives a wavy motion like this.
Check the setting of the material
Click the material to show the setting in the Inspector window.
By adjusting those values, you can change the behaviour of the material.
Add motion to rain
By combining the Custom_Rain material with the Rain object, you can make a rain-like motion.
I explain how to add motion to triangular meshes by assigning the material to it.
Firstly, select the Rain prefab and click the circular button on the right side of the Materials section.
Select the Custom_Rain material created earlier from the material list.
Once the Custom_Rain material is set, the motion is added then the objects move like rain.
Adjust the appearance of the rain
Adjust the size and colour of the rain to make it look like realistic rain more.
Firstly, select the Custom_Rain material and click the clour-property box.
It brings up the Color Picker window.
Set it to translucent blue-ish colour as shown below.
When you set the colour, the rain object looks as shown below.
Modify the shape (The size and number of raindrops)
By adjusting the setting of the Rain prefab, you can change the size and the number of the raindrops.
Reduce the size of raindrops
By changing the ‘Raindrop Size’ value, you can change the size of the raindrops.
If you set the size to 0.1, the rain will look as shown below.
Increase the number of raindrops
You can render heavy rain by increasing the number of raindrops.
By setting the number of raindrops to 6000, the rain looks as shown below.
Add some randomness to the rain
You can add some randomness to the rain by increasing ‘the randomness of rain’ value.
The shown below is the rain with the randomness set to (16,4,16).
Upload to STYLY
Right-click the Rain prefab and select ‘Upload prefab to STYLY’.
It starts uploading. Wait patiently.
When you see the ‘Upload Succeeded’ window, the upload is completed.
See ‘My Models’ in STYLY. You will find the Rain asset uploaded there.
Now it’s time to make it rain on STYLY.
※You can access the sample project from https://github.com/styly-dev/STYLY-Unity-Examples/tree/master/Assets/STYLY_Examples/Rain