677 lines
33 KiB
C#
677 lines
33 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.XR;
|
|
|
|
namespace Assets.ThoMagic.Renderer
|
|
{
|
|
public class CameraRenderer : IDisposable
|
|
{
|
|
internal static int nextCameraRendererId = 0;
|
|
int cameraRendererId;
|
|
public static IInstanceRenderSettings ReflectionProbeSettings;
|
|
public readonly Camera Camera;
|
|
public IInstanceRenderSettings cameraSettings;
|
|
|
|
private readonly bool _singlePassInstanced = false;
|
|
|
|
private int cachedBufferHash;
|
|
|
|
private Vector3 _origin;
|
|
private Light _mainLight;
|
|
|
|
List<InstanceStreamer> visibleStreams = new List<InstanceStreamer>();
|
|
|
|
List<PrefabData> prefabData = new List<PrefabData>();
|
|
List<GraphicsBuffer.IndirectDrawIndexedArgs> indirectDrawIndexedArgs = new List<GraphicsBuffer.IndirectDrawIndexedArgs>();
|
|
Dictionary<int, float> objRenderDistanceCache = new Dictionary<int, float>();
|
|
Dictionary<uint, InstanceRenderSettings> appliedSettings = new Dictionary<uint, InstanceRenderSettings>();
|
|
List<uint> cullableIndexes = new List<uint>();
|
|
|
|
public Camera ReferenceCamera { get; private set; }
|
|
|
|
private CommandBuffer commandBuffer;
|
|
private ComputeShader instancingShader;
|
|
private ComputeBuffer prefabBuffer;
|
|
|
|
private GraphicsBuffer indirectDrawIndexedArgsBuffer;
|
|
private ComputeBuffer metaBuffer;
|
|
private ComputeBuffer cullableIndexesBuffer;
|
|
private ComputeBuffer visibleIndexesBuffer;
|
|
private ComputeBuffer visibleShadowIndexesBuffer;
|
|
|
|
private float cachedFov;
|
|
private float cachedBias;
|
|
private bool lodInvalid;
|
|
|
|
SceneRenderSettings sceneSettings = new SceneRenderSettings();
|
|
private Plane[] _cachedFrustumPlanes;
|
|
private Vector4[] _cachedShaderFrustumPlanes;
|
|
internal bool instanceCountChanged = true;
|
|
internal bool rebuildPrefabs = true;
|
|
|
|
private int cullShaderId = 0, clearShaderId = 0;
|
|
|
|
private uint maxInstancesCount = 0;
|
|
private uint indexBufferOffset = 0;
|
|
|
|
private int lastCamSettingsHash = 0;
|
|
|
|
public CameraRenderer(Camera camera)
|
|
{
|
|
commandBuffer = new CommandBuffer();
|
|
cameraRendererId = Interlocked.Increment(ref nextCameraRendererId);
|
|
|
|
instancingShader = UnityEngine.Object.Instantiate(Resources.Load<ComputeShader>("ThoMagic Renderer Instancing"));
|
|
instancingShader.hideFlags = HideFlags.HideAndDontSave;
|
|
cullShaderId = instancingShader.FindKernel("Cull_64");
|
|
clearShaderId = instancingShader.FindKernel("Clear_64");
|
|
|
|
instancingShader.name = $"ThoMagic Renderer Instancing - {camera.name}";
|
|
Camera = camera != null ? camera : throw new ArgumentNullException(nameof(camera));
|
|
cameraSettings = camera.GetComponent<IInstanceRenderSettings>();
|
|
ReferenceCamera = camera;
|
|
if (camera.cameraType == CameraType.Game || camera.cameraType == CameraType.VR)
|
|
{
|
|
_singlePassInstanced = XRSettings.enabled && (XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassInstanced || XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassMultiview);
|
|
if (Application.isEditor && XRSettings.enabled && !_singlePassInstanced && XRSettings.loadedDeviceName == "MockHMD Display" && this.LoadMockHmdSetting() == "SinglePassInstanced")
|
|
_singlePassInstanced = true;
|
|
}
|
|
}
|
|
|
|
public void SetFloatingOrigin(in Vector3 origin)
|
|
{
|
|
_origin = origin;
|
|
}
|
|
|
|
public void SetReferenceCamera(Camera camera)
|
|
{
|
|
ReferenceCamera = camera != null ? camera : Camera;
|
|
cameraSettings = ReferenceCamera.GetComponent<IInstanceRenderSettings>();
|
|
}
|
|
|
|
public void SetMainLight(Light light) => _mainLight = light;
|
|
|
|
private void CalculateFrustumPlanes()
|
|
{
|
|
if (_cachedFrustumPlanes == null)
|
|
_cachedFrustumPlanes = new Plane[6];
|
|
GeometryUtility.CalculateFrustumPlanes(ReferenceCamera, _cachedFrustumPlanes);
|
|
|
|
if (_cachedShaderFrustumPlanes == null)
|
|
_cachedShaderFrustumPlanes = new Vector4[6];
|
|
|
|
for (int index = 0; index < 6; ++index)
|
|
_cachedShaderFrustumPlanes[index] = new Vector4(_cachedFrustumPlanes[index].normal.x, _cachedFrustumPlanes[index].normal.y, _cachedFrustumPlanes[index].normal.z, _cachedFrustumPlanes[index].distance);
|
|
}
|
|
|
|
public void Render()
|
|
{
|
|
//Used in editor if selected camera is not editor scene camera. Then only the culled instances of the selected camera is rendered.
|
|
if (ReferenceCamera == null)
|
|
SetReferenceCamera(Camera);
|
|
|
|
if (_mainLight == null)
|
|
_mainLight = FindMainLight();
|
|
|
|
if (_mainLight != null)
|
|
{
|
|
sceneSettings.HasMainLight = true;
|
|
sceneSettings.HasMainLightShadows = _mainLight.shadows > 0;
|
|
sceneSettings.MainLightDirection = _mainLight.transform.forward;
|
|
}
|
|
else
|
|
{
|
|
sceneSettings.HasMainLight = false;
|
|
sceneSettings.HasMainLightShadows = false;
|
|
}
|
|
|
|
var finalSettings = InstanceRenderSettings.Default(ReferenceCamera);
|
|
|
|
if (ReferenceCamera.cameraType == CameraType.Reflection && ReflectionProbeSettings != null)
|
|
finalSettings.Merge(ReflectionProbeSettings.Settings);
|
|
|
|
if (cameraSettings == null && Application.isEditor && !Application.isPlaying)
|
|
cameraSettings = ReferenceCamera.GetComponent<IInstanceRenderSettings>();
|
|
|
|
if (cameraSettings != null)
|
|
finalSettings.Merge(cameraSettings.Settings);
|
|
|
|
if(finalSettings.GetHashCode() != lastCamSettingsHash)
|
|
{
|
|
lastCamSettingsHash = finalSettings.GetHashCode();
|
|
rebuildPrefabs = true;
|
|
}
|
|
|
|
if (!rebuildPrefabs && Application.isEditor && !Application.isPlaying)
|
|
{
|
|
foreach (var renderObject in RendererPool.objectsList)
|
|
{
|
|
|
|
var settingsEditor = finalSettings;
|
|
var renderObjectSettingsNew = renderObject.GameObject.GetComponent<IInstanceRenderSettings>();
|
|
|
|
if (renderObjectSettingsNew != null)
|
|
settingsEditor.Merge(renderObjectSettingsNew.Settings);
|
|
|
|
if(!appliedSettings.ContainsKey(renderObject.prefabId) || settingsEditor.GetHashCode() != appliedSettings[renderObject.prefabId].GetHashCode())
|
|
{
|
|
renderObject.Settings = renderObjectSettingsNew;
|
|
rebuildPrefabs = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
CalculateFrustumPlanes();
|
|
//Find visible streams for this frame
|
|
visibleStreams.Clear();
|
|
|
|
foreach (var streamer in RendererPool.streamers.Values)
|
|
if (streamer.IsInRange(ReferenceCamera, _cachedFrustumPlanes))
|
|
{
|
|
streamer.UpdateForCamera(ReferenceCamera, _cachedFrustumPlanes);
|
|
visibleStreams.Add(streamer);
|
|
}
|
|
|
|
bool prefabDataChanged = false;
|
|
bool noNeedToUpdateIndirectIndexOffsets = false;
|
|
//A prefab (object) has been added, removed or changed
|
|
if (rebuildPrefabs)
|
|
{
|
|
noNeedToUpdateIndirectIndexOffsets = true;
|
|
rebuildPrefabs = false;
|
|
|
|
lodInvalid = false;
|
|
cachedFov = ReferenceCamera.fieldOfView;
|
|
cachedBias = QualitySettings.lodBias;
|
|
|
|
appliedSettings.Clear();
|
|
indirectDrawIndexedArgs.Clear();
|
|
|
|
prefabData.Clear();
|
|
prefabData.AddRange(RendererPool.prefabData);
|
|
|
|
maxInstancesCount = 0;
|
|
indexBufferOffset = 0;
|
|
|
|
uint batchIndex = 0;
|
|
uint prefabCount = 0;
|
|
uint indexArgsSize = 0;
|
|
int totalIndirectArgsIndex = 0;
|
|
|
|
foreach (var renderObject in RendererPool.objectsList)
|
|
{
|
|
var localPrefabData = prefabData[(int)renderObject.prefabId];
|
|
|
|
var finalObjSettings = finalSettings;
|
|
|
|
if (renderObject.Settings != null)
|
|
{
|
|
finalObjSettings.Merge(renderObject.Settings.Settings);
|
|
ValidateSettings(ref finalObjSettings);
|
|
}
|
|
|
|
CalculateCullingDistances(renderObject, finalObjSettings, cachedFov, cachedBias, renderObject.LodTransitions, renderObject.LodSizes, renderObject.lods);
|
|
|
|
float distance1 = RelativeHeightToDistance(finalObjSettings.DensityInDistanceFalloff.x, renderObject.LodSizes[0], cachedFov);
|
|
float distance2 = RelativeHeightToDistance(finalObjSettings.DensityInDistanceFalloff.y, renderObject.LodSizes[0], cachedFov);
|
|
|
|
var densityInDistance = new Vector4(finalObjSettings.DensityInDistance,
|
|
distance1,
|
|
distance2 - distance1,
|
|
finalObjSettings.ShadowDistance);
|
|
|
|
localPrefabData.lodCount = renderObject.lodCount;
|
|
localPrefabData.fadeLods = renderObject.fadeLods;
|
|
localPrefabData.batchIndex = batchIndex;
|
|
localPrefabData.indexBufferStartOffset = indexBufferOffset;
|
|
localPrefabData.maxCount = renderObject.count;
|
|
localPrefabData.densityInDistance = densityInDistance;
|
|
|
|
renderObject.indirectArgsPerSubmeshOffsets.Clear();
|
|
|
|
indirectDrawIndexedArgs.AddRange(renderObject.indirectDrawIndexedArgs);
|
|
|
|
for (int i = 0; i < renderObject.lodCount; i++)
|
|
{
|
|
renderObject.indirectArgsPerLodOffsets[i] = indexArgsSize;
|
|
|
|
//All indirect arguments for this lod including shadows
|
|
for (int z = 0; z < renderObject.indirectArgsPerLodWithShadowsCounts[i]; z++)
|
|
{
|
|
//Set batchoffset
|
|
var idia = indirectDrawIndexedArgs[totalIndirectArgsIndex];
|
|
idia.startInstance = indexBufferOffset + (uint)(i * renderObject.count);
|
|
indirectDrawIndexedArgs[totalIndirectArgsIndex] = idia;
|
|
//**
|
|
|
|
renderObject.indirectArgsPerSubmeshOffsets.Add(totalIndirectArgsIndex);
|
|
totalIndirectArgsIndex++;
|
|
indexArgsSize += 5;
|
|
}
|
|
}
|
|
|
|
localPrefabData.SetLods(renderObject.lods, renderObject.indirectArgsPerLodOffsets, renderObject.indirectArgsPerLodCounts);
|
|
prefabData[(int)renderObject.prefabId] = localPrefabData;
|
|
appliedSettings[renderObject.prefabId] = finalObjSettings;
|
|
|
|
batchIndex += renderObject.lodCount;
|
|
indexBufferOffset += renderObject.count * renderObject.lodCount;
|
|
maxInstancesCount += renderObject.count;
|
|
prefabCount++;
|
|
}
|
|
|
|
//Nothing to draw yet
|
|
if (maxInstancesCount == 0)
|
|
{
|
|
rebuildPrefabs = true;
|
|
return;
|
|
}
|
|
|
|
if (metaBuffer == null || metaBuffer.count < maxInstancesCount)
|
|
{
|
|
metaBuffer?.Dispose();
|
|
int nextCount = RendererPool.RESIZE_COUNT * (((int)maxInstancesCount - 1) / RendererPool.RESIZE_COUNT + 1);
|
|
metaBuffer = new ComputeBuffer(nextCount, sizeof(uint) * 4, ComputeBufferType.Structured);
|
|
metaBuffer.name = $"ThoMagic metaBuffer ({Camera.name})";
|
|
|
|
cullableIndexesBuffer?.Dispose();
|
|
cullableIndexesBuffer = new ComputeBuffer(nextCount, sizeof(uint), ComputeBufferType.Structured);
|
|
cullableIndexesBuffer.name = $"ThoMagic cullingIndexesBuffer ({Camera.name})";
|
|
}
|
|
|
|
if (indirectDrawIndexedArgsBuffer == null || indirectDrawIndexedArgsBuffer.count < indirectDrawIndexedArgs.Count)
|
|
{
|
|
indirectDrawIndexedArgsBuffer?.Dispose();
|
|
int nextCount = RendererPool.RESIZE_COUNT * (((int)indirectDrawIndexedArgs.Count - 1) / RendererPool.RESIZE_COUNT + 1);
|
|
indirectDrawIndexedArgsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, nextCount, GraphicsBuffer.IndirectDrawIndexedArgs.size);
|
|
indirectDrawIndexedArgsBuffer.name = $"ThoMagic indirectDrawIndexedArgsBuffer ({Camera.name})";
|
|
}
|
|
|
|
indirectDrawIndexedArgsBuffer.SetData(indirectDrawIndexedArgs);
|
|
|
|
if (prefabBuffer == null || prefabBuffer.count < prefabCount)
|
|
{
|
|
prefabBuffer?.Dispose();
|
|
int nextCount = RendererPool.RESIZE_COUNT * (((int)prefabCount - 1) / RendererPool.RESIZE_COUNT + 1);
|
|
prefabBuffer = new ComputeBuffer(nextCount, PrefabData.Stride, ComputeBufferType.Structured);
|
|
prefabBuffer.name = $"ThoMagic prefabBuffer ({Camera.name})";
|
|
}
|
|
|
|
if (visibleIndexesBuffer == null || visibleIndexesBuffer.count < indexBufferOffset)
|
|
{
|
|
visibleIndexesBuffer?.Dispose();
|
|
int nextCount = RendererPool.RESIZE_COUNT * (((int)indexBufferOffset - 1) / RendererPool.RESIZE_COUNT + 1);
|
|
visibleIndexesBuffer = new ComputeBuffer(nextCount, sizeof(uint), ComputeBufferType.Structured);
|
|
visibleIndexesBuffer.name = $"ThoMagic visibleIndexesBuffer ({Camera.name})";
|
|
|
|
visibleShadowIndexesBuffer?.Dispose();
|
|
visibleShadowIndexesBuffer = new ComputeBuffer(nextCount, sizeof(uint), ComputeBufferType.Structured);
|
|
visibleShadowIndexesBuffer.name = $"ThoMagic visibleShadowIndexesBuffer ({Camera.name})";
|
|
};
|
|
|
|
prefabDataChanged = true;
|
|
instanceCountChanged = true;
|
|
}
|
|
|
|
//Nothing to draw yet
|
|
if (maxInstancesCount == 0)
|
|
return;
|
|
|
|
//Either instances have been added/removed or the visible streams have changed.
|
|
//We need to rebuild the visible instances index buffer
|
|
if (instanceCountChanged || BuffersChanged(visibleStreams, ref cachedBufferHash))
|
|
{
|
|
if (instanceCountChanged)
|
|
{
|
|
if (!noNeedToUpdateIndirectIndexOffsets)//If already rebuild by prefab update, this is not needed
|
|
{
|
|
maxInstancesCount = 0;
|
|
indexBufferOffset = 0;
|
|
uint indexArgsSize = 0;
|
|
int totalIndirectArgsIndex = 0;
|
|
|
|
foreach (var renderObject in RendererPool.objectsList)
|
|
{
|
|
for (int i = 0; i < renderObject.lodCount; i++)
|
|
{
|
|
//All indirect arguments for this lod including shadows
|
|
for (int z = 0; z < renderObject.indirectArgsPerLodWithShadowsCounts[i]; z++)
|
|
{
|
|
//Set batchoffset
|
|
var idia = indirectDrawIndexedArgs[totalIndirectArgsIndex];
|
|
idia.startInstance = indexBufferOffset + (uint)(i * renderObject.count);
|
|
indirectDrawIndexedArgs[totalIndirectArgsIndex] = idia;
|
|
//**
|
|
|
|
totalIndirectArgsIndex++;
|
|
indexArgsSize += 5;
|
|
}
|
|
}
|
|
|
|
var pd = prefabData[(int)renderObject.prefabId];
|
|
if (pd.maxCount != renderObject.count)
|
|
prefabDataChanged = true;
|
|
pd.indexBufferStartOffset = indexBufferOffset;
|
|
pd.maxCount = renderObject.count;
|
|
prefabData[(int)renderObject.prefabId] = pd;
|
|
|
|
indexBufferOffset += renderObject.count * renderObject.lodCount;
|
|
maxInstancesCount += renderObject.count;
|
|
}
|
|
|
|
if (metaBuffer == null || metaBuffer.count < maxInstancesCount)
|
|
{
|
|
metaBuffer?.Dispose();
|
|
int nextCount = RendererPool.RESIZE_COUNT * (((int)maxInstancesCount - 1) / RendererPool.RESIZE_COUNT + 1);
|
|
metaBuffer = new ComputeBuffer(nextCount, sizeof(uint) * 4, ComputeBufferType.Structured);
|
|
metaBuffer.name = $"ThoMagic metaBuffer ({Camera.name})";
|
|
|
|
cullableIndexesBuffer?.Dispose();
|
|
cullableIndexesBuffer = new ComputeBuffer(nextCount, sizeof(uint), ComputeBufferType.Structured);
|
|
cullableIndexesBuffer.name = $"ThoMagic cullingIndexesBuffer ({Camera.name})";
|
|
}
|
|
|
|
if (visibleIndexesBuffer == null || visibleIndexesBuffer.count < indexBufferOffset)
|
|
{
|
|
visibleIndexesBuffer?.Dispose();
|
|
int nextCount = RendererPool.RESIZE_COUNT * (((int)indexBufferOffset - 1) / RendererPool.RESIZE_COUNT + 1);
|
|
visibleIndexesBuffer = new ComputeBuffer(nextCount, sizeof(uint), ComputeBufferType.Structured);
|
|
visibleIndexesBuffer.name = $"ThoMagic visibleIndexesBuffer ({Camera.name})";
|
|
|
|
visibleShadowIndexesBuffer?.Dispose();
|
|
visibleShadowIndexesBuffer = new ComputeBuffer(nextCount, sizeof(uint), ComputeBufferType.Structured);
|
|
visibleShadowIndexesBuffer.name = $"ThoMagic visibleShadowIndexesBuffer ({Camera.name})";
|
|
};
|
|
|
|
indirectDrawIndexedArgsBuffer.SetData(indirectDrawIndexedArgs);
|
|
}
|
|
}
|
|
|
|
instanceCountChanged = false;
|
|
|
|
cullableIndexes.Clear();
|
|
|
|
foreach (var stream in visibleStreams)
|
|
{
|
|
foreach (var objectInstanceIds in stream.objectInstanceIds.Values)
|
|
{
|
|
cullableIndexes.AddRange(objectInstanceIds);
|
|
}
|
|
}
|
|
|
|
cullableIndexesBuffer.SetData(cullableIndexes);
|
|
}
|
|
|
|
//Nothing to render
|
|
if (cullableIndexes.Count == 0 || RendererPool.globalInstanceBuffer == null)
|
|
return;
|
|
|
|
//Lod settings changed, update prefab lod data
|
|
if (cachedFov != ReferenceCamera.fieldOfView || cachedBias != QualitySettings.lodBias || lodInvalid)
|
|
{
|
|
lodInvalid = false;
|
|
cachedFov = ReferenceCamera.fieldOfView;
|
|
cachedBias = QualitySettings.lodBias;
|
|
|
|
foreach (var renderObject in RendererPool.objectsList)
|
|
{
|
|
CalculateCullingDistances(renderObject, appliedSettings[renderObject.prefabId], cachedFov, cachedBias, renderObject.LodTransitions, renderObject.LodSizes, renderObject.lods);
|
|
|
|
float distance1 = RelativeHeightToDistance(appliedSettings[renderObject.prefabId].DensityInDistanceFalloff.x, renderObject.LodSizes[0], cachedFov);
|
|
float distance2 = RelativeHeightToDistance(appliedSettings[renderObject.prefabId].DensityInDistanceFalloff.y, renderObject.LodSizes[0], cachedFov);
|
|
|
|
var densityInDistance = new Vector4(appliedSettings[renderObject.prefabId].DensityInDistance,
|
|
distance1,
|
|
distance2 - distance1,
|
|
appliedSettings[renderObject.prefabId].ShadowDistance);
|
|
|
|
var pd = prefabData[(int)renderObject.prefabId];
|
|
pd.SetLods(renderObject.lods, renderObject.indirectArgsPerLodOffsets, renderObject.indirectArgsPerLodCounts);
|
|
pd.densityInDistance = densityInDistance;
|
|
prefabData[(int)renderObject.prefabId] = pd;
|
|
}
|
|
|
|
prefabDataChanged = true;
|
|
}
|
|
|
|
if(prefabDataChanged)
|
|
prefabBuffer.SetData(prefabData);
|
|
|
|
//Compute culling
|
|
|
|
//Reset visible count of instances to zero
|
|
/*instancingShader.SetInt("_Count", indirectDrawIndexedArgs.Count);
|
|
instancingShader.SetBuffer(clearShaderId, "perCamIndirectArgumentsBuffer", indirectDrawIndexedArgsBuffer);
|
|
instancingShader.Dispatch(clearShaderId, Mathf.CeilToInt(indirectDrawIndexedArgs.Count / 64.0f), 1, 1);
|
|
|
|
//Cull
|
|
instancingShader.SetBuffer(cullShaderId, "globalInstances", RendererPool.globalInstanceBuffer);
|
|
instancingShader.SetBuffer(cullShaderId, "perCamPrefabs", prefabBuffer);
|
|
instancingShader.SetBuffer(cullShaderId, "perCamMeta", metaBuffer);
|
|
instancingShader.SetBuffer(cullShaderId, "perCamIndirectArgumentsBuffer", indirectDrawIndexedArgsBuffer);
|
|
instancingShader.SetBuffer(cullShaderId, "perCamCullableIndexesBuffer", cullableIndexesBuffer);
|
|
instancingShader.SetBuffer(cullShaderId, "perCamVisibleIndexesBuffer", visibleIndexesBuffer);
|
|
instancingShader.SetBuffer(cullShaderId, "perCamShadowVisibleIndexesBuffer", visibleShadowIndexesBuffer);
|
|
|
|
instancingShader.SetVector("_CameraPosition", ReferenceCamera.transform.position);
|
|
instancingShader.SetVectorArray("_FrustumPlanes", _cachedShaderFrustumPlanes);
|
|
instancingShader.SetVector("_ShadowDirection", sceneSettings.MainLightDirection);
|
|
instancingShader.SetInt("_Count", cullableIndexes.Count);
|
|
|
|
instancingShader.Dispatch(cullShaderId, Mathf.CeilToInt(cullableIndexes.Count / 64.0f), 1, 1);*/
|
|
|
|
commandBuffer.Clear();
|
|
|
|
commandBuffer.SetComputeIntParam(instancingShader, "_CountClear", indirectDrawIndexedArgs.Count);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, clearShaderId, "perCamIndirectArgumentsBuffer", indirectDrawIndexedArgsBuffer);
|
|
commandBuffer.DispatchCompute(instancingShader, clearShaderId, Mathf.CeilToInt(indirectDrawIndexedArgs.Count / 64.0f), 1, 1);
|
|
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "globalInstances", RendererPool.globalInstanceBuffer);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "perCamPrefabs", prefabBuffer);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "perCamMeta", metaBuffer);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "perCamIndirectArgumentsBuffer", indirectDrawIndexedArgsBuffer);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "perCamCullableIndexesBuffer", cullableIndexesBuffer);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "perCamVisibleIndexesBuffer", visibleIndexesBuffer);
|
|
commandBuffer.SetComputeBufferParam(instancingShader, cullShaderId, "perCamShadowVisibleIndexesBuffer", visibleShadowIndexesBuffer);
|
|
commandBuffer.SetComputeVectorParam(instancingShader, "_CameraPosition", ReferenceCamera.transform.position);
|
|
commandBuffer.SetComputeVectorArrayParam(instancingShader, "_FrustumPlanes", _cachedShaderFrustumPlanes);
|
|
commandBuffer.SetComputeVectorParam(instancingShader, "_ShadowDirection", sceneSettings.MainLightDirection);
|
|
commandBuffer.SetComputeIntParam(instancingShader, "_CountCull", cullableIndexes.Count);
|
|
commandBuffer.DispatchCompute(instancingShader, cullShaderId, Mathf.CeilToInt(cullableIndexes.Count / 64.0f), 1, 1);
|
|
|
|
Graphics.ExecuteCommandBuffer(commandBuffer);
|
|
|
|
var fence = Graphics.CreateGraphicsFence(GraphicsFenceType.AsyncQueueSynchronisation, SynchronisationStageFlags.ComputeProcessing);
|
|
Graphics.WaitOnAsyncGraphicsFence(fence);
|
|
|
|
//Render all prefabs (objects)
|
|
foreach (var renderObject in RendererPool.objectsList)
|
|
if (renderObject.count > 0)//Ignore if no instance is registered
|
|
RenderObject(renderObject, appliedSettings[renderObject.prefabId]);
|
|
}
|
|
|
|
private void CalculateCullingDistances(
|
|
ObjectData renderObject,
|
|
InstanceRenderSettings finalSettings,
|
|
float fieldOfView,
|
|
float bias,
|
|
float[] relativeTransitionHeight,
|
|
float[] detailSize,
|
|
Vector4[] lodData)
|
|
{
|
|
for (int index = 0; index < relativeTransitionHeight.Length; ++index)
|
|
lodData[index] = new Vector4(index > 0 ? lodData[index - 1].y : 0.0f, RelativeHeightToDistance(relativeTransitionHeight[index], detailSize[index], fieldOfView) * bias, detailSize[index], 0.0f);
|
|
|
|
var renderDistance = Mathf.Min(finalSettings.RenderDistance, RelativeHeightToDistance(renderObject.LodTransitions[renderObject.LodTransitions.Length - 1], renderObject.LodSizes[renderObject.LodTransitions.Length - 1], this.ReferenceCamera.fieldOfView, QualitySettings.lodBias));
|
|
objRenderDistanceCache[renderObject.GetHashCode()] = renderDistance;
|
|
|
|
for (int index = 0; index < renderObject.LodSizes.Length; ++index)
|
|
{
|
|
renderObject.lods[index].x = Mathf.Min(renderObject.lods[index].x, renderDistance);
|
|
renderObject.lods[index].y = Mathf.Min(renderObject.lods[index].y, renderDistance);
|
|
}
|
|
}
|
|
|
|
public static float RelativeHeightToDistance(
|
|
float relativeHeight,
|
|
float size,
|
|
float fieldOfView)
|
|
{
|
|
if (relativeHeight <= 0.0f || relativeHeight == float.MaxValue)
|
|
return float.MaxValue;
|
|
|
|
float num = Mathf.Tan((float)(Math.PI / 180.0 * (double)fieldOfView * 0.5));
|
|
return size * 0.5f / relativeHeight / num;
|
|
}
|
|
|
|
private void RenderObject(
|
|
ObjectData obj,
|
|
InstanceRenderSettings renderSettings)
|
|
{
|
|
if (LayerIsCulled(ReferenceCamera, obj.GameObject.layer) || (/*(!Application.isEditor || Application.isPlaying) &&*/ SceneIsCulled(ReferenceCamera, obj.GameObject)))
|
|
return;
|
|
|
|
if (!renderSettings.Render)
|
|
return;
|
|
|
|
foreach(var drawGroup in obj.drawGroups)
|
|
{
|
|
if (drawGroup == null) continue;
|
|
drawGroup.SetInstances(RendererPool.globalInstanceBuffer, visibleIndexesBuffer, metaBuffer);
|
|
drawGroup.Draw(Camera, obj, indirectDrawIndexedArgsBuffer);
|
|
}
|
|
|
|
if (!renderSettings.Shadows)
|
|
return;
|
|
|
|
foreach (var drawGroup in obj.drawShadowGroups)
|
|
{
|
|
if (drawGroup == null) continue;
|
|
drawGroup.SetInstances(RendererPool.globalInstanceBuffer, visibleShadowIndexesBuffer, metaBuffer);
|
|
drawGroup.Draw(Camera, obj, indirectDrawIndexedArgsBuffer);
|
|
}
|
|
}
|
|
|
|
private void ValidateSettings(ref InstanceRenderSettings settings)
|
|
{
|
|
if (settings.RenderDistance <= 0.0f)
|
|
settings.RenderDistance = this.ReferenceCamera.farClipPlane;
|
|
if (settings.ShadowDistance > 0.0f)
|
|
return;
|
|
settings.ShadowDistance = settings.RenderDistance;
|
|
}
|
|
|
|
private bool LayerIsCulled(Camera camera, int layer)
|
|
{
|
|
if (camera.cullingMask != -1)
|
|
{
|
|
int num = layer;
|
|
if ((camera.cullingMask & 1 << num) == 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool SceneIsCulled(Camera camera, GameObject gameObject)
|
|
{
|
|
if (camera.scene != null && camera.scene.handle != 0 && camera.scene != gameObject.scene)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
private string LoadMockHmdSetting()
|
|
{
|
|
try
|
|
{
|
|
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
{
|
|
Type type = assembly.GetType("Unity.XR.MockHMD.MockHMDBuildSettings", false);
|
|
if (!(type == (Type)null))
|
|
{
|
|
object obj = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue((object)null);
|
|
return type.GetField("renderMode").GetValue(obj).ToString();
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private Light FindMainLight()
|
|
{
|
|
Light currentLight = null;
|
|
foreach (Light otherLight in UnityEngine.Object.FindObjectsOfType<Light>())
|
|
{
|
|
if (otherLight.type == LightType.Directional)
|
|
{
|
|
if (otherLight.shadows > 0)
|
|
{
|
|
currentLight = otherLight;
|
|
break;
|
|
}
|
|
if (currentLight == null)
|
|
currentLight = otherLight;
|
|
else if (otherLight.intensity > currentLight.intensity)
|
|
currentLight = otherLight;
|
|
}
|
|
}
|
|
return currentLight;
|
|
}
|
|
|
|
private float RelativeHeightToDistance(
|
|
float relativeHeight,
|
|
float size,
|
|
float fieldOfView,
|
|
float bias)
|
|
{
|
|
if ((double)relativeHeight <= 0.0 || (double)relativeHeight == 3.40282346638529E+38)
|
|
return float.MaxValue;
|
|
float num = Mathf.Tan((float)(Math.PI / 180.0 * (double)fieldOfView * 0.5));
|
|
return size * 0.5f / relativeHeight / num * bias;
|
|
}
|
|
|
|
private bool BuffersChanged(List<InstanceStreamer> buffers, ref int cachedHash)
|
|
{
|
|
int hash = ComputeHash(buffers);
|
|
if (hash == cachedHash)
|
|
return false;
|
|
cachedHash = hash;
|
|
return true;
|
|
}
|
|
|
|
private int ComputeHash(List<InstanceStreamer> buffers)
|
|
{
|
|
if (buffers == null || buffers.Count == 0)
|
|
return 0;
|
|
int num = buffers[0].GetHashCode();
|
|
for (int index = 1; index < buffers.Count; ++index)
|
|
num = HashCode.Combine(num, buffers[index].GetHashCode());
|
|
return num;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
UnityEngine.Object.DestroyImmediate(instancingShader);
|
|
prefabBuffer?.Dispose();
|
|
indirectDrawIndexedArgsBuffer?.Dispose();
|
|
metaBuffer?.Dispose();
|
|
cullableIndexesBuffer?.Dispose();
|
|
visibleIndexesBuffer?.Dispose();
|
|
visibleShadowIndexesBuffer?.Dispose();
|
|
commandBuffer?.Dispose();
|
|
prefabBuffer = null;
|
|
indirectDrawIndexedArgsBuffer = null;
|
|
metaBuffer = null;
|
|
visibleIndexesBuffer = null;
|
|
visibleShadowIndexesBuffer = null;
|
|
}
|
|
}
|
|
}
|