using UnityEngine;
using System.Collections;
namespace WorldStreamer2
{
///
/// Terrain culling system.
///
public class TerrainCullingSystem : MonoBehaviour
{
[Tooltip("Max view distance is referred from camera to terrain center point")]
///
/// The bounding distance - Max view distance is referred from camera to terrain center point.
///
public float renderingDistance = 10000;
float sphereSize = 0.5f;
Terrain terrain;
CullingGroup group;
BoundingSphere[] spheres = new BoundingSphere[1000];
Vector3 offsetVector;
Vector3 offsetVectorUp;
Camera mainCamera;
int heightSphereNumber;
//[HideInInspector]
//public bool disableTrees = false;
///
/// Start this instance, generates culling group and finds terrain.
///
void Start()
{
terrain = GetComponent();
if (terrain != null)
{
if (terrain.terrainData.size.x > terrain.terrainData.size.z)
sphereSize = terrain.terrainData.size.x * 0.75f;
else
sphereSize = terrain.terrainData.size.z * 0.75f;
offsetVector = new Vector3(terrain.terrainData.size.x, 0, terrain.terrainData.size.z) * 0.5f;
group = new CullingGroup();
group.targetCamera = Camera.main;
heightSphereNumber = 2 * (int)(terrain.terrainData.size.y / (float)sphereSize);
heightSphereNumber = Mathf.Max(1, heightSphereNumber);
offsetVectorUp = new Vector3(0, sphereSize * 0.5f, 0);
for (int i = 0; i < heightSphereNumber; i++)
{
spheres[i] = new BoundingSphere(transform.position + offsetVector + i * offsetVectorUp, sphereSize);
}
group.SetBoundingSpheres(spheres);
group.SetBoundingSphereCount(heightSphereNumber);
group.onStateChanged = StateChangedMethod;
group.SetBoundingDistances(new float[] { renderingDistance });
mainCamera = Camera.main;
group.SetDistanceReferencePoint(Camera.main.transform);
Invoke("CheckVisibility", 0.1f);
}
else
Debug.LogError("TerrainCullingSystem: no terrain on game object " + gameObject.name);
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
for (int i = 0; i < heightSphereNumber; i++)
{
Gizmos.DrawWireSphere(transform.position + offsetVector + i * offsetVectorUp, sphereSize);
}
}
///
/// Checks visibility by hand
///
void CheckVisibility()
{
bool visible = false;
for (int i = 0; i < heightSphereNumber; i++)
{
if (group.IsVisible(i))
{
visible = true;
break;
}
}
if (!visible)
{
terrain.drawHeightmap = false;
//if (disableTrees)
terrain.drawTreesAndFoliage = false;
}
}
///
/// sets object possition, and checks camera change;
///
public void Update()
{
for (int i = 0; i < heightSphereNumber; i++)
{
spheres[i] = new BoundingSphere(transform.position + offsetVector + i * offsetVectorUp, sphereSize);
}
if (mainCamera != Camera.main)
{
mainCamera = Camera.main;
group.SetDistanceReferencePoint(Camera.main.transform);
}
}
///
/// Event on cilling group change
///
/// Evt.
private void StateChangedMethod(CullingGroupEvent evt)
{
bool visible = false;
for (int i = 0; i < heightSphereNumber; i++)
{
if (group.IsVisible(i))
{
visible = true;
break;
}
}
if (visible)
{
terrain.drawHeightmap = true;
//if (disableTrees)
terrain.drawTreesAndFoliage = true;
}
else
{
terrain.drawHeightmap = false;
//if (disableTrees)
terrain.drawTreesAndFoliage = false;
}
}
///
/// Raises the disable event.
///
void OnDisable()
{
if (group != null)
{
group.Dispose();
group = null;
}
}
}
}