using System; using System.Collections.Generic; using UnityEngine; namespace Toria.Game { [RequireComponent(typeof(CapsuleCollider))] public class LeavesHidingDither : MonoBehaviour { [NonSerialized] List treeMaterials; static RPGController player = null; static new Camera camera = null; [NonSerialized] bool shouldHide = false; void Start() { treeMaterials = new List(); foreach (Renderer renderer in GetComponentsInChildren()) { MakeShadowClone(renderer); Material mat = Instantiate(renderer.sharedMaterial); renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; renderer.sharedMaterial = mat; treeMaterials.Add(mat); } } void MakeShadowClone(Renderer renderer) { GameObject shadowClone = Instantiate(renderer.gameObject); for (int i = shadowClone.transform.childCount - 1; i >= 0; i--) Destroy(shadowClone.transform.GetChild(i).gameObject); shadowClone.name = "Shadow clone"; shadowClone.transform.SetParent(renderer.transform); shadowClone.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); shadowClone.transform.localScale = Vector3.one; foreach (Component comp in shadowClone.GetComponents()) { if (comp is not MeshRenderer && comp is not MeshFilter && comp is not Transform) Destroy(comp); } shadowClone.GetComponent().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly; } void Update() { if (!player) player = FindAnyObjectByType(); if (shouldHide) { Vector2 viewPortPoint = camera.WorldToViewportPoint(player.transform.position); foreach (Material mat in treeMaterials) mat.SetVector("_PlayerPosition", viewPortPoint); } if (!camera) camera = Camera.main; if (!player || !camera) return; Vector3 playerPos = player.transform.position + Vector3.up; Vector3 cameraPos = camera.transform.position; Vector3 rayDir = (playerPos - cameraPos).normalized; //move back the origin point so the raycast doesn't start from within a tree collider RaycastHit[] hits = Physics.RaycastAll(cameraPos + rayDir * -100f, rayDir, float.PositiveInfinity, 1 << gameObject.layer, QueryTriggerInteraction.Collide); for (int i = 0; i < hits.Length; i++) { if (hits[i].collider.gameObject == gameObject) { SetCutoutEnabled(true); return; } } SetCutoutEnabled(false); } void SetCutoutEnabled(bool enabled) { if (shouldHide == enabled) return; shouldHide = enabled; foreach (Material mat in treeMaterials) mat.SetFloat("_ShouldHide", enabled ? 1 : 0); } } }