247 lines
8.1 KiB
C#
247 lines
8.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Assets.ThoMagic.Renderer
|
|
{
|
|
public class TileObjectStreamer : InstanceStreamer
|
|
{
|
|
private readonly GameObject objectContainer;
|
|
private Bounds worldBounds;
|
|
private float maxDistance;
|
|
|
|
private Dictionary<int, int> registeredPrefabs = new Dictionary<int, int>();
|
|
private Dictionary<int, GameObject> instanceToGameObject = new Dictionary<int, GameObject>();
|
|
|
|
private bool isDirty = true;
|
|
|
|
public TileObjectStreamer(GameObject objectContainer)
|
|
: base()
|
|
{
|
|
this.objectContainer = objectContainer;
|
|
}
|
|
|
|
public void Recycle()
|
|
{
|
|
Clear();
|
|
|
|
int ownerHash = GetHashCode();
|
|
foreach (var item in registeredPrefabs)
|
|
{
|
|
RendererPool.RemoveObject(item.Value, ownerHash);
|
|
}
|
|
|
|
foreach (var item in instanceToGameObject)
|
|
{
|
|
var mrs = item.Value.gameObject.GetComponentsInChildren<MeshRenderer>();
|
|
foreach(var mr in mrs)
|
|
mr.enabled = true;
|
|
|
|
var lod = item.Value.gameObject.GetComponent<LODGroup>();
|
|
if (lod != null)
|
|
lod.enabled = true;
|
|
|
|
}
|
|
|
|
registeredPrefabs.Clear();
|
|
instanceToGameObject.Clear();
|
|
}
|
|
|
|
public void Load()
|
|
{
|
|
isDirty = false;
|
|
|
|
Recycle();
|
|
|
|
worldBounds.SetMinMax(Vector3.zero, Vector3.zero);
|
|
|
|
registeredPrefabs.Clear();
|
|
instanceToGameObject.Clear();
|
|
|
|
int ownerHash = GetHashCode();
|
|
|
|
foreach (Transform child in objectContainer.transform)
|
|
{
|
|
var hash = CalculateHash(child.gameObject);
|
|
|
|
if(hash != 0)
|
|
{
|
|
int objectId;
|
|
|
|
if (registeredPrefabs.ContainsKey(hash))
|
|
{
|
|
objectId = registeredPrefabs[hash];
|
|
}
|
|
else
|
|
{
|
|
var settings = GetSettingsOrDefault(child.gameObject);
|
|
objectId = RendererPool.RegisterObject(child.gameObject, settings, this, ownerHash);
|
|
registeredPrefabs.Add(hash, objectId);
|
|
if (settings.Settings.RenderDistance == 0)
|
|
maxDistance = float.MaxValue;
|
|
|
|
maxDistance = Mathf.Max(maxDistance, settings.Settings.RenderDistance);
|
|
}
|
|
|
|
var mrs = child.gameObject.GetComponentsInChildren<MeshRenderer>();
|
|
Bounds bounds = new Bounds();
|
|
bool first = true;
|
|
foreach (var mr in mrs)
|
|
{
|
|
if (first)
|
|
{
|
|
bounds = mr.bounds;
|
|
}
|
|
else
|
|
{
|
|
bounds.Encapsulate(mr.bounds);
|
|
}
|
|
|
|
mr.enabled = false;
|
|
}
|
|
|
|
var lod = child.gameObject.GetComponent<LODGroup>();
|
|
if(lod != null)
|
|
lod.enabled = false;
|
|
|
|
var instanceId = AddInstance(objectId, new Vector3(child.position.x, child.position.y, child.position.z), child.rotation, child.lossyScale.x, child.lossyScale.z);
|
|
|
|
instanceToGameObject.Add(instanceId, child.gameObject);
|
|
if (instanceToGameObject.Count == 1)
|
|
worldBounds = bounds;
|
|
else
|
|
worldBounds.Encapsulate(bounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
private IInstanceRenderSettings GetSettingsOrDefault(GameObject gameObject)
|
|
{
|
|
IInstanceRenderSettings instanceRenderSettings;
|
|
return gameObject.TryGetComponent(out instanceRenderSettings) ? instanceRenderSettings : new DefaultRenderSettings();
|
|
}
|
|
|
|
private int CalculateHash(GameObject gameObject)
|
|
{
|
|
int num = 13;
|
|
|
|
var lodGroup = gameObject.GetComponent<LODGroup>();
|
|
|
|
LOD[] lodArray;
|
|
|
|
if (lodGroup == null)
|
|
{
|
|
var mr = gameObject.GetComponentsInChildren<MeshRenderer>();
|
|
|
|
if (mr == null)
|
|
return 0;
|
|
|
|
lodArray = new LOD[1]
|
|
{
|
|
new LOD(0.0001f, mr)
|
|
};
|
|
}
|
|
else
|
|
lodArray = lodGroup.GetLODs();
|
|
|
|
|
|
foreach (var loD in lodArray)
|
|
num = HashCode.Combine<int, int>(num, CalcualteContentHash(loD));
|
|
|
|
return num;
|
|
}
|
|
|
|
private int CalcualteContentHash(LOD lod)
|
|
{
|
|
int num = 13;
|
|
if (lod.renderers != null)
|
|
{
|
|
foreach (var renderer in lod.renderers)
|
|
{
|
|
if (renderer == null)
|
|
{
|
|
num = HashCode.Combine<int, int>(num, 13);
|
|
}
|
|
else
|
|
{
|
|
MeshFilter component = renderer.GetComponent<MeshFilter>();
|
|
|
|
num = HashCode.Combine<int, int, int>(HashCode.Combine<int, int, int, int, int, int, int, int>(
|
|
num,
|
|
component == null || component.sharedMesh == null ? 13 : component.sharedMesh.GetHashCode(),
|
|
renderer.shadowCastingMode.GetHashCode(),
|
|
CalculateContentHash(renderer.sharedMaterials),
|
|
renderer.motionVectorGenerationMode.GetHashCode(),
|
|
renderer.receiveShadows.GetHashCode(),
|
|
renderer.rendererPriority.GetHashCode(),
|
|
renderer.renderingLayerMask.GetHashCode()),
|
|
renderer.gameObject.layer.GetHashCode(),
|
|
lod.screenRelativeTransitionHeight.GetHashCode());
|
|
}
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
private int CalculateContentHash(Material[] materials)
|
|
{
|
|
int num = 13;
|
|
if (materials != null)
|
|
{
|
|
foreach (Material material in materials)
|
|
num = HashCode.Combine<int, int>(num,
|
|
material != null ? material.GetHashCode() : 13);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public override bool IsInRange(Camera referenceCamera, Plane[] planes)
|
|
{
|
|
var eyePos = referenceCamera.transform.position;
|
|
|
|
if ((eyePos - worldBounds.ClosestPoint(eyePos)).magnitude <= Mathf.Min(referenceCamera.farClipPlane, maxDistance))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return streamerInstanceId.GetHashCode();//HashCode.Combine(streamerInstanceId, objectInstanceIds.Count);
|
|
}
|
|
|
|
public void Destroy()
|
|
{
|
|
Recycle();
|
|
}
|
|
|
|
public void LateUpdate()
|
|
{
|
|
if (isDirty)
|
|
{
|
|
Load();
|
|
}
|
|
}
|
|
|
|
public void MarkDirty()
|
|
{
|
|
isDirty = true;
|
|
}
|
|
|
|
private class DefaultRenderSettings : IInstanceRenderSettings
|
|
{
|
|
public InstanceRenderSettings Settings => new InstanceRenderSettings()
|
|
{
|
|
Render = true,
|
|
DensityInDistance = 1f,
|
|
DensityInDistanceFalloff = Vector2.zero,
|
|
RenderDistance = 0.0f,
|
|
ShadowDistance = 0.0f,
|
|
Shadows = true,
|
|
Supported = true
|
|
};
|
|
}
|
|
}
|
|
}
|