using System.Collections; using System.Collections.Generic; using UnityEngine; namespace JBooth.MicroSplat { public class SnowUtilities { static float SnowFade(float worldHeight, float snowMin, float snowMax, float snowDot, float snowDotVertex, float snowLevel, float angleRangeZ, float angleRangeW) { float snowHeightFade = Mathf.Clamp01((worldHeight - snowMin) / Mathf.Max(snowMax, 0.001f)); float snowAngleFade = Mathf.Max(0, (snowDotVertex - angleRangeZ) * 6); snowAngleFade = Mathf.Clamp01(snowAngleFade * (1 - Mathf.Max(0, (snowDotVertex - angleRangeW) * 6))); return Mathf.Clamp01((snowLevel * snowHeightFade * snowAngleFade)); } public static float GetSnowCoverage(Terrain t, Vector3 worldPos, int maxDistance = 2) { MicroSplatObject mso = t.GetComponent(); if (mso != null) { if (mso.keywordSO.IsKeywordEnabled("_SNOW")) { var terrainLocalPos = worldPos - t.transform.position; var normalizedPos = new Vector2(Mathf.InverseLerp(0.0f, t.terrainData.size.x, terrainLocalPos.x), Mathf.InverseLerp(0.0f, t.terrainData.size.z, terrainLocalPos.z)); Vector3 worldNormal = t.terrainData.GetInterpolatedNormal(normalizedPos.x, normalizedPos.y); float worldheight = t.terrainData.GetInterpolatedHeight(normalizedPos.x, normalizedPos.y); float snowLevel; var mat = mso.templateMaterial; float snowMin; float snowMax; float angleRangeW; float angleRangeZ; if (mso.keywordSO.IsKeywordEnabled("_USEGLOBALSNOWLEVEL")) { snowLevel = Shader.GetGlobalFloat("_Global_SnowLevel"); } else { snowLevel = mat.GetFloat("_SnowAmount"); } if (mso.keywordSO.IsKeywordEnabled("_USEGLOBALSNOWHEIGHT")) { var g = Shader.GetGlobalVector("_Global_SnowMinMaxHeight"); snowMin = g.x; snowMax = g.y; angleRangeZ = g.z; angleRangeW = g.w; } else { var g = mat.GetVector("_SnowHeightAngleRange"); snowMin = g.x; snowMax = g.y; angleRangeZ = g.z; angleRangeW = g.w; } Vector4 _SnowParams = mat.GetVector("_SnowParams"); Vector3 snowUpVector = mat.GetVector("_SnowUpVector"); float snowDot = Mathf.Max(snowLevel / 2, Vector3.Dot(worldNormal, snowUpVector)); float snowDotVertex = snowDot; float ao = 1; float oheight = 0; float snowFade = SnowFade(worldheight, snowMin, snowMax, snowDot, snowDotVertex, snowLevel, angleRangeZ, angleRangeW); float height = Mathf.Clamp01(oheight - (1.0f - _SnowParams.x)); float erosion = Mathf.Clamp01(ao * _SnowParams.y); erosion *= erosion; float snowMask = Mathf.Clamp01(snowFade - erosion - height); snowMask = snowMask * snowMask * snowMask; float snowAmount = snowMask * Mathf.Clamp01(snowDot - (height + erosion) * 0.5f); // up snowAmount = Mathf.Clamp01(snowAmount * 8); if (mso.keywordSO.IsKeywordEnabled("_SNOWMASK")) { Texture2D tex = t.materialTemplate.GetTexture("_SnowMask") as Texture2D; if (t != null) { Color c = tex.GetPixelBilinear(normalizedPos.x, normalizedPos.y); snowAmount = Mathf.Min(c.r, snowAmount); snowAmount = Mathf.Max(c.g, snowAmount); } } return snowAmount; } } return 0; } public static float GetSnowCoverage(Vector3 worldPos, int maxDistance = 2) { Terrain t = null; RaycastHit[] hits = Physics.RaycastAll(worldPos + Vector3.up * 1, Vector3.down, maxDistance + 1); for (int i = 0; i < hits.Length; ++i) { var h = hits[i]; t = h.collider.GetComponent(); if (t != null) { var nt = t.GetComponent(); if (nt != null) { return GetSnowCoverage(t, worldPos, maxDistance); } } } return 0; } } }