Skip to content

Commit

Permalink
Added companion scripts that were used for Precomputed Culling video …
Browse files Browse the repository at this point in the history
…released on 18.09.2023
  • Loading branch information
Tomasz Juszczak committed Sep 18, 2023
1 parent 2f626e2 commit d6970cd
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 0 deletions.
165 changes: 165 additions & 0 deletions Other/Video-Scripts-18-09-2023/FollowSceneCamera.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.Linq;

#if UNITY_EDITOR

/// <summary>
/// Simple script to follow the scene camera, and allows for rendering only view frustum objects
/// </summary>
public class FollowSceneCamera : MonoBehaviour
{
private Camera _gameCamera;
private bool _shouldUpdate = false;
private bool _viewFrustumVisible = true;
private List<MeshCollider> _renderers = new List<MeshCollider>();

private void Start()
{
_gameCamera = GetComponent<Camera>();
_renderers.AddRange(FindObjectsOfType<MeshCollider>());
}

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);
}
}

/// <summary>
/// Update the rendering of the view frustum
/// </summary>
private void UpdateViewFrustumRendering()
{
if(_viewFrustumVisible)
{
foreach (var renderer in _renderers)
{
renderer.GetComponent<Renderer>().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<Light>();
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<Renderer>().enabled = GeometryUtility.TestPlanesAABB(planes, boundsWithShadow);
}
}

/// <summary>
/// Follow the scene camera
/// </summary>
private void FollowSceneCameraImpl()
{
if (!_shouldUpdate) return;

var sceneCameraTransform = SceneView.lastActiveSceneView.camera.transform;
transform.position = sceneCameraTransform.position;
transform.rotation = sceneCameraTransform.rotation;
}

/// <summary>
/// Show a GUI to toggle the script on/off
/// </summary>
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<Renderer>()).Count(r => r.enabled));
}

/// <summary>
/// Draw the view frustum using Gizmos
/// </summary>
private void OnDrawGizmos()
{
if (!_viewFrustumVisible) return;

// Draw the view frustum using Gizmos
DrawViewFrustum();
}

/// <summary>
/// Draw the view frustum using Handles and Gizmos
/// </summary>
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
83 changes: 83 additions & 0 deletions Other/Video-Scripts-18-09-2023/ProfileStats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Profiling;
using System.Linq;
using Unity.Profiling;

/// <summary>
/// Script that would record the stats of the game
/// </summary>
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<Sample> Samples = new List<Sample>();

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);
}

/// <summary>
/// Collect the stats of the game and save them to a csv file
/// </summary>
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;
}

}

/// <summary>
/// Sample of the stats
/// </summary>
public class Sample
{
public int Frame;
public long TrianglesCount;
public long VerticesCount;
public long BatchesCount;
public long SetPassCallsCount;
}
}

0 comments on commit d6970cd

Please sign in to comment.