ThomagicRenderer/Runtime/Scripts/TileObjectStreamer.cs

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