diff --git a/Other/Video-Scripts-18-09-2023/FollowSceneCamera.cs b/Other/Video-Scripts-18-09-2023/FollowSceneCamera.cs new file mode 100644 index 0000000..4a82021 --- /dev/null +++ b/Other/Video-Scripts-18-09-2023/FollowSceneCamera.cs @@ -0,0 +1,165 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using System.Linq; + +#if UNITY_EDITOR + +/// +/// Simple script to follow the scene camera, and allows for rendering only view frustum objects +/// +public class FollowSceneCamera : MonoBehaviour +{ + private Camera _gameCamera; + private bool _shouldUpdate = false; + private bool _viewFrustumVisible = true; + private List _renderers = new List(); + + private void Start() + { + _gameCamera = GetComponent(); + _renderers.AddRange(FindObjectsOfType()); + } + + private void Update() + { + FollowSceneCameraImpl(); + UpdateViewFrustumRendering(); + + // Move the camera using WSAD and mouse when right mouse button is pressed + float speed = 10; + if(Input.GetKey(KeyCode.LeftShift)) speed *= 10; + + float mouseSpeed = 100; + float dt = Time.deltaTime; + if (Input.GetKey(KeyCode.W)) transform.position += transform.forward * speed * dt; + if (Input.GetKey(KeyCode.S)) transform.position -= transform.forward * speed * dt; + if (Input.GetKey(KeyCode.A)) transform.position -= transform.right * speed * dt; + if (Input.GetKey(KeyCode.D)) transform.position += transform.right * speed * dt; + + if (Input.GetMouseButton(1)) + { + transform.Rotate(Vector3.up, Input.GetAxis("Mouse X") * mouseSpeed * dt, Space.World); + transform.Rotate(Vector3.right, -Input.GetAxis("Mouse Y") * mouseSpeed * dt, Space.Self); + } + } + + /// + /// Update the rendering of the view frustum + /// + private void UpdateViewFrustumRendering() + { + if(_viewFrustumVisible) + { + foreach (var renderer in _renderers) + { + renderer.GetComponent().enabled = true; + } + + return; + } + + // Read light direction so that we can calculate the shadow length, and use that (it's only an approximation) + var sun = FindObjectOfType(); + var sunDirection = sun.transform.forward; + var sunAngle = Vector3.Angle(sunDirection, transform.forward); + + + Plane[] planes = GeometryUtility.CalculateFrustumPlanes(_gameCamera); + // if renderer is not visible, disable it + foreach (var renderer in _renderers) + { + // using sun data, calculate new bounds of the renderer, to include it's shadow + // Calculate new bounds of the renderer, to include its shadow + var boundsWithShadow = renderer.bounds; + + // Calculate the shadow length based on the sun angle + float shadowLength = boundsWithShadow.extents.y / Mathf.Tan(sunAngle * Mathf.Deg2Rad); + + // Create a vector that represents the shadow + Vector3 shadowVector = sunDirection * shadowLength; + + // Add the shadow vector to the bounds + boundsWithShadow.Encapsulate(new Bounds(boundsWithShadow.center + shadowVector, boundsWithShadow.size)); + + renderer.GetComponent().enabled = GeometryUtility.TestPlanesAABB(planes, boundsWithShadow); + } + } + + /// + /// Follow the scene camera + /// + private void FollowSceneCameraImpl() + { + if (!_shouldUpdate) return; + + var sceneCameraTransform = SceneView.lastActiveSceneView.camera.transform; + transform.position = sceneCameraTransform.position; + transform.rotation = sceneCameraTransform.rotation; + } + + /// + /// Show a GUI to toggle the script on/off + /// + private void OnGUI() + { + // Show a button to toggle the script on/off + if (GUI.Button(new Rect(10, 10, 100, 20), _shouldUpdate + ? "Disable" + : "Enable")) _shouldUpdate = !_shouldUpdate; + // Show a button to toggle the view frustum on/off + if (GUI.Button(new Rect(10, 40, 100, 20), _viewFrustumVisible + ? "Hide Frustum" + : "Show Frustum")) _viewFrustumVisible = !_viewFrustumVisible; + + // Show number of enabled renderers in the scene + GUI.Label(new Rect(10, 70, 200, 20), "Enabled renderers: " + _renderers.Select(x => x.GetComponent()).Count(r => r.enabled)); + } + + /// + /// Draw the view frustum using Gizmos + /// + private void OnDrawGizmos() + { + if (!_viewFrustumVisible) return; + + // Draw the view frustum using Gizmos + DrawViewFrustum(); + } + + /// + /// Draw the view frustum using Handles and Gizmos + /// + private void DrawViewFrustum() + { + var cam = _gameCamera; + if (cam == null) return; + + Gizmos.color = Color.red; + + // Calculate the corners of the near clip plane + Vector3[] nearCorners = new Vector3[4]; + nearCorners[0] = cam.ViewportToWorldPoint(new Vector3(0, 0, cam.nearClipPlane)); + nearCorners[1] = cam.ViewportToWorldPoint(new Vector3(1, 0, cam.nearClipPlane)); + nearCorners[2] = cam.ViewportToWorldPoint(new Vector3(1, 1, cam.nearClipPlane)); + nearCorners[3] = cam.ViewportToWorldPoint(new Vector3(0, 1, cam.nearClipPlane)); + + // Draw rays from the camera's position to each corner of the near clip plane + foreach (Vector3 corner in nearCorners) + { + Ray ray = new Ray(cam.transform.position, corner - cam.transform.position); + RaycastHit hit; + if (Physics.Raycast(ray, out hit)) + { + // If the ray hit something, draw it to the point of contact + Gizmos.DrawLine(ray.origin, hit.point); + } + else + { + // Otherwise, draw it to the near clip plane + Gizmos.DrawLine(ray.origin, ray.origin + ray.direction * cam.farClipPlane); + } + } + } +} +#endif \ No newline at end of file diff --git a/Other/Video-Scripts-18-09-2023/ProfileStats.cs b/Other/Video-Scripts-18-09-2023/ProfileStats.cs new file mode 100644 index 0000000..eb0c687 --- /dev/null +++ b/Other/Video-Scripts-18-09-2023/ProfileStats.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using UnityEngine.Profiling; +using System.Linq; +using Unity.Profiling; + +/// +/// Script that would record the stats of the game +/// +public class ProfileStats : MonoBehaviour +{ + public const string TRIANGLES_COUNT = "Triangles Count"; + public const string VERTICES_COUNT = "Vertices Count"; + public const string BATCHES_COUNT = "Batches Count"; + public const string SETPASSCALLS_COUNT = "SetPass Calls Count"; + + private ProfilerRecorder _trianglesCount; + private ProfilerRecorder _verticesCount; + private ProfilerRecorder _batchesCount; + private ProfilerRecorder _setPassCallsCount; + + private bool _saved = false; + + private List Samples = new List(); + + private void Start() + { + Application.targetFrameRate = 30; + + _trianglesCount = ProfilerRecorder.StartNew(ProfilerCategory.Render, TRIANGLES_COUNT, 1850); + _verticesCount = ProfilerRecorder.StartNew(ProfilerCategory.Render, VERTICES_COUNT, 1850); + _batchesCount = ProfilerRecorder.StartNew(ProfilerCategory.Render, BATCHES_COUNT, 1850); + _setPassCallsCount = ProfilerRecorder.StartNew(ProfilerCategory.Render, SETPASSCALLS_COUNT, 1850); + } + + /// + /// Collect the stats of the game and save them to a csv file + /// + private void Update() + { + if(Mathf.Min(_trianglesCount.Count, _verticesCount.Count, _batchesCount.Count, _setPassCallsCount.Count) >= 1800) + { + if (!_saved) + { + for (int i = 0; i < Mathf.Min(_trianglesCount.Count, _verticesCount.Count, _batchesCount.Count, _setPassCallsCount.Count); i++) + { + Samples.Add(new Sample() + { + Frame = i, + TrianglesCount = _trianglesCount.GetSample(i).Value, + VerticesCount = _verticesCount.GetSample(i).Value, + BatchesCount = _batchesCount.GetSample(i).Value, + SetPassCallsCount = _setPassCallsCount.GetSample(i).Value + }); + } + + _saved = true; + // save to csv + var header = "Frame,Triangles Count,Vertices Count,Batches Count,SetPass Calls Count"; + var content = string.Join("\n", Samples.Select(s => $"{s.Frame},{s.TrianglesCount},{s.VerticesCount},{s.BatchesCount},{s.SetPassCallsCount}")); + var csv = $"{header}\n{content}"; + System.IO.File.WriteAllText("profile.csv", csv); + Debug.Log($"Saved {Samples.Count} samples to {Path.GetFullPath("profile.csv")}"); + } + return; + } + + } + + /// + /// Sample of the stats + /// + public class Sample + { + public int Frame; + public long TrianglesCount; + public long VerticesCount; + public long BatchesCount; + public long SetPassCallsCount; + } +} \ No newline at end of file