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