using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
///
/// Used in the ZED planetarium sample to draw asteroids in the solar system's asteroid belt and rotate them.
/// The asteroids are not instantiated as GameObjects, but drawn each frame with DrawMeshInstanced.
/// Given there are many asteroids to draw, this reduces draw calls substantially along with some CPU overhead.
///
public class AsteroidsManager : MonoBehaviour
{
///
/// Prefab containing the first asteroid mesh type.
///
[Tooltip("Prefab containing the first asteroid mesh type.")]
public GameObject asteroidsType1;
///
/// Prefab containing the first asteroid mesh type.
///
[Tooltip("Prefab containing the first asteroid mesh type.")]
public GameObject asteroidsType2;
///
/// How many asteroids of each type to draw. (There will be twice this number of asteroids in total).
///
[Tooltip("How many asteroids of each type to draw. (There will be twice this number of asteroids in total).")]
public static int amount = 100;
///
/// The radius of the asteroid belt. This is meters when the localscale of this object is 1,1,1.
///
[Tooltip("The radius of the asteroid belt. This is meters when the localscale of this object is 1,1,1. ")]
public float radius = 1;
///
/// How wide the asteroids can be spaced apart. Values too low or high may cause asteroids to intersect Mars or Jupiter.
///
[Tooltip("How wide the asteroids can be spaced apart. Values too low or high may cause asteroids to intersect Mars or Jupiter. ")]
public float offset = 0.05f;
///
/// Holds the transform of where the asteroid started when it was created (for asteroid type 1).
///
Matrix4x4[] listPositionsOrigin = new Matrix4x4[amount];
///
/// Holds the current transforms of the type 1 asteroids, updated each frame based on the solar system's location and its orbit.
///
Matrix4x4[] listPositions = new Matrix4x4[amount];
///
/// Holds the transform of where the asteroid started when it was created (for asteroid type 1).
///
Matrix4x4[] listPositionsOrigin2 = new Matrix4x4[amount];
///
/// Holds the current transforms of the type 2 asteroids, updated each frame based on the solar system's location and its orbit.
///
Matrix4x4[] listPositions2 = new Matrix4x4[amount];
void Start()
{
CreateAsteroids(listPositionsOrigin, amount, radius, offset); //Create all type 1 asteroids.
CreateAsteroids(listPositionsOrigin2, amount, radius, offset); //Create all type 2 asteroids.
}
///
/// Fills the first Matrix array with the origin positions and scales of randomly positioned asteroids.
///
/// Array to be populated with matrixes of each asteroid's starting transform.
/// How many asteroids to make.
/// Radius of the asteroid belt/
/// How far each asteroid can randomly deviate from the radius.
private void CreateAsteroids(Matrix4x4[] listPositionsOrigin, int amount, float radius, float offset)
{
for (int i = 0; i < amount; ++i)
{
// 1. translation: displace along circle with 'radius' in range [-offset, offset]
float angle = (float)i / (float)amount * 360.0f;
float displacement = (Random.Range(0, 30) % (int)(2 * offset * 100)) / 100.0f - offset;
float x = Mathf.Sin(angle) * radius + displacement;
displacement = (Random.Range(0, 30) % (int)(2 * offset * 100)) / 100.0f - offset;
float y = displacement * 2.0f; // keep height of asteroid field smaller compared to width of x and z
displacement = (Random.Range(0, 30) % (int)(2 * offset * 100)) / 100.0f - offset;
float z = Mathf.Cos(angle) * radius + displacement;
Vector3 position = new Vector3(x, y, z);
//position = center.TransformPoint(position);
//// 2. scale: Scale between 0.05 and 0.25f
float scale = Random.Range(0.1f, 0.3f);
//model = glm::scale(model, glm::vec3(scale));
// 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector
float rotAngle = (Random.Range(0, 100000) % 360);
//Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.identity, new Vector3(scale, scale, scale));
Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.Euler(rotAngle, rotAngle, rotAngle), new Vector3(scale, scale, scale));
listPositionsOrigin[i] = m;
}
}
///
/// Called each frame to move, rotate and scale the asteroids based on this object's transform and their orbit.
///
/// All asteroids' initial matrixes.
/// All asteroids' current matrixes.
void UpdatePosition(Matrix4x4[] listPositionsOrigin, Matrix4x4[] listPositions)
{
for (int i = 0; i < listPositionsOrigin.Length; ++i)
{
listPositionsOrigin[i] = listPositionsOrigin[i] * Matrix4x4.TRS(Vector3.zero,
Quaternion.Euler(Time.deltaTime * Random.Range(0, 100), Time.deltaTime * Random.Range(0, 100), Time.deltaTime * Random.Range(0, 100)),
Vector3.one);
listPositions[i] = transform.localToWorldMatrix* ( listPositionsOrigin[i]);
}
}
// Update is called once per frame
void Update()
{
foreach(ZEDManager manager in ZEDManager.GetInstances())
{
DrawAsteroids(manager);
}
}
private void DrawAsteroids(ZEDManager manager)
{
Camera leftcamera = manager.GetLeftCamera();
Camera rightcamera = manager.GetRightCamera();
//Update positions and draw asteroids of type 1
UpdatePosition(listPositionsOrigin, listPositions);
Graphics.DrawMeshInstanced(asteroidsType1.GetComponent().sharedMesh,
0, asteroidsType1.GetComponent().sharedMaterial,
listPositions,
listPositions.Length,
null,
UnityEngine.Rendering.ShadowCastingMode.Off,
false,
gameObject.layer,
leftcamera);
if (manager.IsStereoRig)
{
Graphics.DrawMeshInstanced(asteroidsType1.GetComponent().sharedMesh,
0,
asteroidsType1.GetComponent().sharedMaterial,
listPositions,
listPositions.Length,
null,
UnityEngine.Rendering.ShadowCastingMode.Off,
false,
gameObject.layer,
rightcamera);
}
//Update positions and draw asteroids of type 2
UpdatePosition(listPositionsOrigin2, listPositions2);
Graphics.DrawMeshInstanced(asteroidsType2.GetComponent().sharedMesh,
0,
asteroidsType2.GetComponent().sharedMaterial,
listPositions2,
listPositions2.Length,
null,
UnityEngine.Rendering.ShadowCastingMode.Off,
false,
gameObject.layer,
leftcamera);
if (manager.IsStereoRig)
{
Graphics.DrawMeshInstanced(asteroidsType2.GetComponent().sharedMesh,
0,
asteroidsType2.GetComponent().sharedMaterial,
listPositions2,
listPositions2.Length,
null,
UnityEngine.Rendering.ShadowCastingMode.Off,
false,
gameObject.layer,
rightcamera);
}
}
}