using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; [ExecuteInEditMode] public class PrecipitationManager : MonoBehaviour { [Serializable] public class EnvironmentParticlesSettings { [Range(0f, 1f)] public float amount = 1f; public Color color = Color.white; [Tooltip("Alpha = variation amount")] public Color colorVariation = Color.white; public float fallSpeed; public Vector2 cameraRange; public Vector2 flutterFrequency; public Vector2 flutterSpeed; public Vector2 flutterMagnitude; public Vector2 sizeRange; public EnvironmentParticlesSettings(Color color, Color colorVariation, float fallSpeed, Vector2 cameraRange, Vector2 flutterFrequency, Vector2 flutterSpeed, Vector2 flutterMagnitude, Vector2 sizeRange) { this.color = color; this.colorVariation = colorVariation; this.fallSpeed = fallSpeed; this.cameraRange = cameraRange; this.flutterFrequency = flutterFrequency; this.flutterSpeed = flutterSpeed; this.flutterMagnitude = flutterMagnitude; this.sizeRange = sizeRange; } } public Texture2D mainTexture; public Texture2D noiseTexture; [Range(0f, 1f)] public float windStrength; [Range(-180f, 180f)] public float windYRotation; [Range(2f, 256f)] public int meshSubdivisions = 200; public EnvironmentParticlesSettings rain = new EnvironmentParticlesSettings(Color.white, Color.white, 3f, new Vector2(0f, 15f), new Vector2(0.988f, 1.234f), new Vector2(0.01f, 0.01f), new Vector2(0.35f, 0.25f), new Vector2(0.5f, 1f)); public EnvironmentParticlesSettings snow = new EnvironmentParticlesSettings(Color.white, Color.white, 0.25f, new Vector2(0f, 10f), new Vector2(0.988f, 1.234f), new Vector2(1f, 0.5f), new Vector2(0.35f, 0.25f), new Vector2(0.05f, 0.025f)); private GridHandler gridHandler; private Matrix4x4[] renderMatrices = new Matrix4x4[27]; private Mesh meshToDraw; private Material rainMaterial; private Material snowMaterial; private static Material CreateMaterialIfNull(string shaderName, ref Material reference) { if (reference == null) { reference = new Material(Shader.Find(shaderName)); reference.hideFlags = HideFlags.HideAndDontSave; reference.renderQueue = 3000; reference.enableInstancing = true; } return reference; } private void OnEnable() { gridHandler = GetComponent(); gridHandler.onPlayerGridChange += OnPlayerGridChange; } private void OnDisable() { gridHandler.onPlayerGridChange -= OnPlayerGridChange; } private void OnPlayerGridChange(Vector3Int playerGrid) { int num = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { Vector3Int vector3Int = new Vector3Int(i, j, k); renderMatrices[num++].SetTRS(gridHandler.GetGridCenter(playerGrid + vector3Int), Quaternion.identity, Vector3.one); } } } } private void Update() { if (meshToDraw == null) { RebuildPrecipitationMesh(); } float num = Mathf.Lerp(0f, 45f, windStrength); Matrix4x4 windRotationMatrix = Matrix4x4.TRS(q: Quaternion.Euler(new Vector3(0f - num, windYRotation, 0f)), pos: Vector3.zero, s: Vector3.one); float maxTravelDistance = gridHandler.gridSize / Mathf.Cos(num * (MathF.PI / 180f)); RenderEnvironmentParticles(rain, CreateMaterialIfNull("Hidden/Environment/Rain", ref rainMaterial), maxTravelDistance, windRotationMatrix); RenderEnvironmentParticles(snow, CreateMaterialIfNull("Hidden/Environment/Snow", ref snowMaterial), maxTravelDistance, windRotationMatrix); } private void RenderEnvironmentParticles(EnvironmentParticlesSettings settings, Material material, float maxTravelDistance, Matrix4x4 windRotationMatrix) { if (!(settings.amount <= 0f)) { material.SetTexture("_MainTex", mainTexture); material.SetTexture("_NoiseTex", noiseTexture); material.SetFloat("_GridSize", gridHandler.gridSize); material.SetFloat("_Amount", settings.amount); material.SetColor("_Color", settings.color); material.SetColor("_ColorVariation", settings.colorVariation); material.SetFloat("_FallSpeed", settings.fallSpeed); material.SetVector("_FlutterFrequency", settings.flutterFrequency); material.SetVector("_FlutterSpeed", settings.flutterSpeed); material.SetVector("_FlutterMagnitude", settings.flutterMagnitude); material.SetVector("_CameraRange", settings.cameraRange); material.SetVector("_SizeRange", settings.sizeRange); material.SetFloat("_MaxTravelDistance", maxTravelDistance); material.SetMatrix("_WindRotationMatrix", windRotationMatrix); Graphics.DrawMeshInstanced(meshToDraw, 0, material, renderMatrices, renderMatrices.Length, null, ShadowCastingMode.Off, receiveShadows: true, 0, null, LightProbeUsage.Off); } } public void RebuildPrecipitationMesh() { Mesh mesh = new Mesh(); List list = new List(); List list2 = new List(); List list3 = new List(); float num = 100f / (float)meshSubdivisions; int num2 = 0; for (float num3 = 0f; num3 <= 100f; num3 += num) { for (float num4 = 0f; num4 <= 100f; num4 += num) { float num5 = num3 / 100f; float num6 = num4 / 100f; list2.Add(new Vector3(num5 - 0.5f, 0f, num6 - 0.5f)); float z = Mathf.Max(num3 / num % 4f / 4f, num4 / num % 4f / 4f); list3.Add(new Vector3(num5, num6, z)); list.Add(num2++); } } mesh.SetVertices(list2); mesh.SetUVs(0, list3); mesh.SetIndices(list.ToArray(), MeshTopology.Points, 0); mesh.bounds = new Bounds(Vector3.zero, new Vector3(500f, 500f, 500f)); mesh.hideFlags = HideFlags.HideAndDontSave; meshToDraw = mesh; } }