I have a little Scene setup with 100 Capsule’s that Physics.Raycast 16 times each other until one hits the current target then follows Physics.SphereCast to check if there is also space (for example a bullet, rocket, etc) in between - if SphereCast hits the target then break… …it does a little bit more, see bellow…
I think there can be done some optimizations to half them maybe…
Depending on the situation of the Unit it take from 50ms up to 11.000ms for each Unit to find a proper target…
If the unit starts to scan the 2 HugeSpaceShips without success then 11secs is the result.
As far as i know for example the light calculations never wont take this time and they are pixel-perfect.
Do i understand right that, for example Material.GetMatrix(), is expensive or changing the variable in the Shader?
Can u help me Setting up a scene for testing?
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class RayCastBenchmark : MonoBehaviour
{
//For the Capsuls in scene
public int CapsulsX = 20, CapsulsZ = 20;
internal int currentCapsulX = 1, currentCapsulZ = 1;
//For Raycast performance
public float minimumFPS = 60f, raycastDistance = 100f;
public bool showStats = true, debugLines = true;
public float precision = 0.5f;
internal string raycastDistanceString, precisionString;
internal int currentCapsule;
internal bool instanciated = false, calculateRaycastsPerObject = true;
internal string debugOut;
internal GameObject template;
internal List<GameObject> capsules = new List<GameObject>();
internal Collider[] nearColliders;
internal float minRaycastsPerObject = Mathf.Infinity, maxRaycastsPerObject;
internal bool showMenu;
internal Rect menuWindow = new Rect(10, 10, 300, 200);
void Start()
{
template = GameObject.CreatePrimitive(PrimitiveType.Capsule);
template.tag = "Respawn";
GameObject aHugeSpaceShip = GameObject.CreatePrimitive(PrimitiveType.Cube);
aHugeSpaceShip.tag = "Respawn";
aHugeSpaceShip.transform.position = new Vector3(50f, 30f, 50f);
aHugeSpaceShip.transform.localScale = new Vector3(10f, 10f, 10f);
aHugeSpaceShip = GameObject.CreatePrimitive(PrimitiveType.Cube);
aHugeSpaceShip.tag = "Respawn";
aHugeSpaceShip.transform.position = new Vector3(37f, 30f, 31f);
aHugeSpaceShip.transform.localScale = new Vector3(10f, 10f, 10f);
currentCapsule = 0;
raycastDistanceString = raycastDistance.ToString();
precisionString = precision.ToString();
}
void Update()
{
if (showMenu)
return;
if (showStats)
debugOut = "";
float time = Time.realtimeSinceStartup + (1f / minimumFPS);
if (!instanciated)
{
while (time >= Time.realtimeSinceStartup)
{
RaycastHit hit;
if (Physics.Raycast(new Vector3(currentCapsulX * 10f, 100, currentCapsulZ * 10f), Vector3.down, out hit, 200))
{
GameObject capsule = Instantiate(template, new Vector3(hit.point.x, hit.point.y + 1, hit.point.z), Quaternion.identity) as GameObject;
capsule.name = "Capsule" + (((currentCapsulZ - 1) * CapsulsX) + currentCapsulX);
capsules.Add(capsule);
}
if (currentCapsulX == CapsulsX currentCapsulZ == CapsulsZ)
{
instanciated = true;
currentCapsulX = 1;
currentCapsulZ = 1;
break;
}
if (currentCapsulX == CapsulsX)
{
currentCapsulZ++;
currentCapsulX = 0;
}
currentCapsulX++;
}
debugOut = "Instanciating... " + Mathf.Round(100f / (CapsulsX * CapsulsZ) * (((currentCapsulZ - 1) * CapsulsX) + currentCapsulX)) + " %";
}
else if (!showMenu)
{
int raycastsPerUpdate = 0;
while (time >= Time.realtimeSinceStartup)
{
if (currentCapsule >= capsules.Count)
{
calculateRaycastsPerObject = false;
currentCapsule = 0;
}
Vector3 pos = capsules[currentCapsule].transform.position;
pos.y += 0.5f;
Collider[] colliders = Physics.OverlapSphere(pos, raycastDistance);
Bounds boundToCheck;
foreach (Collider col in colliders)
{
bool hasTarget = false;
if (col.transform.tag == "Respawn" col.gameObject != capsules[currentCapsule])
{
//TODO Some optimizations
boundToCheck = col.renderer.bounds;
float x_min = Mathf.Min(boundToCheck.min.x, boundToCheck.max.x);
float x_max = Mathf.Max(boundToCheck.min.x, boundToCheck.max.x);
float y_min = Mathf.Min(boundToCheck.min.y, boundToCheck.max.y);
float y_max = Mathf.Max(boundToCheck.min.y, boundToCheck.max.y);
float z_min = Mathf.Min(boundToCheck.min.z, boundToCheck.max.z);
float z_max = Mathf.Max(boundToCheck.min.z, boundToCheck.max.z);
if (calculateRaycastsPerObject)
{
int currentRayCastsPerObject = Mathf.RoundToInt(((x_max - x_min) / precision) * ((y_max - y_min) / precision) * ((z_max - z_min) / precision));
if (currentRayCastsPerObject > 1)
{
minRaycastsPerObject = Mathf.Min(currentRayCastsPerObject, minRaycastsPerObject);
maxRaycastsPerObject = Mathf.Max(currentRayCastsPerObject, maxRaycastsPerObject);
}
}
debugOut = minRaycastsPerObject + "-" + maxRaycastsPerObject + " raycasts are needed per Object. Calculated = " + !calculateRaycastsPerObject + "\n";
for (float x_current = x_min; x_current <= x_max !hasTarget; x_current += precision + 0.1f)
{
for (float y_current = y_min; y_current <= y_max !hasTarget; y_current += precision + 0.1f)
{
for (float z_current = z_min; z_current <= z_max !hasTarget; z_current += precision + 0.1f)
{
if (Input.GetKeyDown(KeyCode.Escape))
{
showMenu = true;
return;
}
Vector3 currentPoint = new Vector3(x_current, y_current, z_current);
Vector3 dir = (currentPoint - pos).normalized;
RaycastHit hit;
if (Physics.Raycast(pos, dir, out hit, raycastDistance))
{
raycastsPerUpdate++;
if (hit.collider == col)
{
if (Physics.SphereCast(pos, 2f, dir, out hit, raycastDistance))
{
if (hit.collider == col)
{
Debug.DrawLine(pos, hit.point, Color.green, .02f);
hasTarget = true;
}
}
raycastsPerUpdate++;
}
else if (debugLines)
{
Debug.DrawLine(pos, currentPoint, Color.red, .02f);
}
}
}
}
}
if (hasTarget)
{
break;
}
else if (debugLines)
{
//Debug.DrawLine(pos, col.transform.position, Color.red, .5f);
}
}
}
currentCapsule++;
}
if (showStats)
debugOut += "RayCasts per secount: " + raycastsPerUpdate / (1f / minimumFPS);
}
if (showStats)
debugOut += "\n Instanciated: " + instanciated;
}
void OnGUI()
{
GUILayout.Label("If u get Stuck or you want to see Config press ESC");
if (showMenu)
{
menuWindow = GUI.Window(1, menuWindow, (id) =>
{
GUILayout.Label("Maximum Range: (" + raycastDistance + ")");
raycastDistance = GUILayout.HorizontalSlider(raycastDistance, 10f, 200f);
GUILayout.Label("Precision: (" + precision + ")");
precision = 1f - GUILayout.HorizontalSlider(1f - precision, 0f, 1f);
calculateRaycastsPerObject = GUILayout.Toggle(calculateRaycastsPerObject, " Calculate Raycasts per Object?");
GUILayout.FlexibleSpace();
if (GUILayout.Button("Continue"))
showMenu = false;
GUI.DragWindow();
}, "PAUSE");
}
if (showStats)
{
GUILayout.Label(debugOut);
}
}
void OnDrawGizmos()
{
if (instanciated capsules.Count > currentCapsule)
Gizmos.DrawWireSphere(capsules[currentCapsule].transform.position, raycastDistance);
}
}