197 lines
7.1 KiB
C#
197 lines
7.1 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Assets.ThoMagic.Renderer
|
|
{
|
|
public class GrassRenderer : GrassStreamer
|
|
{
|
|
|
|
private readonly Terrain terrain;
|
|
private readonly TerrainData terrainData;
|
|
private bool isDirty;
|
|
|
|
public GrassRenderer(Terrain terrain)
|
|
: base(terrain)
|
|
{
|
|
this.terrain = terrain;
|
|
terrainData = terrain.terrainData;
|
|
}
|
|
|
|
public void OnTerrainChanged(TerrainChangedFlags flags)
|
|
{
|
|
if (flags.HasFlag(TerrainChangedFlags.DelayedHeightmapUpdate))
|
|
isDirty = true;
|
|
else if (flags.HasFlag(TerrainChangedFlags.Heightmap))
|
|
isDirty = true;
|
|
else if (flags.HasFlag(TerrainChangedFlags.HeightmapResolution))
|
|
isDirty = true;
|
|
else if (flags.HasFlag(TerrainChangedFlags.Holes))
|
|
isDirty = true;
|
|
else if (flags.HasFlag(TerrainChangedFlags.DelayedHolesUpdate))
|
|
isDirty = true;
|
|
else if (flags.HasFlag(TerrainChangedFlags.FlushEverythingImmediately))
|
|
isDirty = true;
|
|
}
|
|
|
|
public void Destroy()
|
|
{
|
|
Recycle();
|
|
}
|
|
|
|
public void LateUpdate()
|
|
{
|
|
if (isDirty)
|
|
{
|
|
isDirty = false;
|
|
Load();
|
|
}
|
|
|
|
if (Application.isEditor && !Application.isPlaying)
|
|
RebuildChangedPrototypes();
|
|
|
|
Update();
|
|
}
|
|
|
|
public void Load()
|
|
{
|
|
DetailPrototype[] detailPrototypes = terrainData.detailPrototypes;
|
|
|
|
Recycle();
|
|
|
|
int ownerHash = GetHashCode();
|
|
|
|
if (grassPrefabs == null)
|
|
{
|
|
grassPrefabs = new List<int>();
|
|
grassPrefabSet = new List<bool>();
|
|
}
|
|
|
|
float maxDetailDistance = float.MinValue;
|
|
|
|
for (int index = 0; index < detailPrototypes.Length; ++index)
|
|
{
|
|
if (!detailPrototypes[index].usePrototypeMesh || detailPrototypes[index].prototype == null)
|
|
{
|
|
AddDummy(index);
|
|
}
|
|
else
|
|
{
|
|
GameObject prototypeToRender = RendererUtility.GetPrototypeToRender(detailPrototypes[index]);
|
|
if (!RendererUtility.SupportsProceduralInstancing(prototypeToRender))
|
|
{
|
|
AddDummy(index);
|
|
}
|
|
else
|
|
{
|
|
var settings = GetSettingsOrDefault(prototypeToRender);
|
|
maxDetailDistance = Mathf.Max(maxDetailDistance, settings.Settings.RenderDistance);
|
|
grassPrefabs.Add(RendererPool.RegisterObject(prototypeToRender, settings, this, ownerHash));
|
|
grassPrefabSet.Add(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
Build(maxDetailDistance, detailPrototypes.Length);
|
|
}
|
|
|
|
private void AddDummy(int i)
|
|
{
|
|
grassPrefabs.Add(-1);
|
|
grassPrefabSet.Add(false);
|
|
}
|
|
|
|
public override void Recycle()
|
|
{
|
|
if (grassPrefabs == null)
|
|
return;
|
|
|
|
base.Recycle();
|
|
|
|
int ownerHash = GetHashCode();
|
|
for (int index = 0; index < grassPrefabs.Count; ++index)
|
|
{
|
|
if (grassPrefabSet[index])
|
|
{
|
|
RendererPool.RemoveObject(grassPrefabs[index], ownerHash);
|
|
}
|
|
}
|
|
|
|
grassPrefabs.Clear();
|
|
grassPrefabSet.Clear();
|
|
}
|
|
|
|
private void RebuildChangedPrototypes()
|
|
{
|
|
DetailPrototype[] detailPrototypes = terrainData.detailPrototypes;
|
|
if (detailPrototypes.Length != grassPrefabs.Count)
|
|
{
|
|
Load();
|
|
}
|
|
else
|
|
{
|
|
int ownerHash = GetHashCode();
|
|
|
|
for (int index = 0; index < grassPrefabs.Count; ++index)
|
|
{
|
|
if (grassPrefabSet[index])
|
|
{
|
|
GameObject prototypeToRender = RendererUtility.GetPrototypeToRender(detailPrototypes[index]);
|
|
GameObject gameObject = RendererPool.GetObject(grassPrefabs[index]);
|
|
if (prototypeToRender != gameObject)
|
|
{
|
|
RendererPool.RemoveObject(grassPrefabs[index], ownerHash);
|
|
|
|
if (prototypeToRender != null)
|
|
{
|
|
grassPrefabs[index] = RendererPool.RegisterObject(prototypeToRender, GetSettingsOrDefault(prototypeToRender), this, ownerHash);
|
|
grassPrefabSet[index] = true;
|
|
}
|
|
else
|
|
{
|
|
grassPrefabs[index] = -1;
|
|
grassPrefabSet[index] = false;
|
|
}
|
|
}
|
|
else if (RendererPool.ContentHashChanged(grassPrefabs[index]))
|
|
{
|
|
RendererPool.RemoveObject(grassPrefabs[index], GetHashCode());
|
|
if (prototypeToRender != null)
|
|
{
|
|
grassPrefabs[index] = RendererPool.RegisterObject(prototypeToRender, GetSettingsOrDefault(prototypeToRender), this, ownerHash);
|
|
grassPrefabSet[index] = true;
|
|
}
|
|
else
|
|
{
|
|
grassPrefabs[index] = -1;
|
|
grassPrefabSet[index] = false;
|
|
}
|
|
}
|
|
else if (prototypeToRender != null)
|
|
RendererPool.SetObjectSettings(prototypeToRender, GetSettingsOrDefault(prototypeToRender));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private IInstanceRenderSettings GetSettingsOrDefault(GameObject gameObject)
|
|
{
|
|
IInstanceRenderSettings instanceRenderSettings;
|
|
return gameObject.TryGetComponent(out instanceRenderSettings) ? instanceRenderSettings : new DefaultRenderSettings();
|
|
}
|
|
|
|
private class DefaultRenderSettings : IInstanceRenderSettings
|
|
{
|
|
public InstanceRenderSettings Settings => new InstanceRenderSettings()
|
|
{
|
|
Render = true,
|
|
DensityInDistance = 0.125f,
|
|
DensityInDistanceFalloff = new Vector2(0.08f, 0.0075f),
|
|
RenderDistance = 150f,
|
|
ShadowDistance = 50f,
|
|
Shadows = true,
|
|
Supported = true
|
|
};
|
|
}
|
|
}
|
|
}
|