|
|
|
@@ -0,0 +1,456 @@
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
#if NATIVE_ARRAYS
|
|
|
|
|
|
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
|
|
|
#if CORE_RP_1703
|
|
|
|
|
#define SUPPORTS_APV
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Rendering;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
using UnityEditor.SceneManagement;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using Unity.Collections;
|
|
|
|
|
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
public class ftAPVBaker : AdaptiveProbeVolumes.LightingBaker
|
|
|
|
|
{
|
|
|
|
|
int bakedProbeCount;
|
|
|
|
|
int _stepCount;
|
|
|
|
|
|
|
|
|
|
public override ulong currentStep => (ulong)bakedProbeCount;
|
|
|
|
|
public override ulong stepCount => (ulong)_stepCount;
|
|
|
|
|
|
|
|
|
|
public NativeArray<SphericalHarmonicsL2> irradianceResults;
|
|
|
|
|
public NativeArray<float> validityResults;
|
|
|
|
|
public NativeArray<Vector4> masks;
|
|
|
|
|
|
|
|
|
|
public override NativeArray<SphericalHarmonicsL2> irradiance => irradianceResults;
|
|
|
|
|
public override NativeArray<float> validity => validityResults;
|
|
|
|
|
public override NativeArray<Vector4> occlusion => masks;
|
|
|
|
|
|
|
|
|
|
bool occlusionRequested = false;
|
|
|
|
|
bool disposeIrradiance = false;
|
|
|
|
|
public bool irradianceSet = false;
|
|
|
|
|
public bool masksSet = false;
|
|
|
|
|
bool disposeMasks = false;
|
|
|
|
|
bool anyStepsDone = false;
|
|
|
|
|
bool finishOnStep = false;
|
|
|
|
|
|
|
|
|
|
public override void Initialize(bool bakeProbeOcclusion, NativeArray<Vector3> probePositions, NativeArray<uint> bakedRenderingLayerMasks)
|
|
|
|
|
{
|
|
|
|
|
Initialize(bakeProbeOcclusion, probePositions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Initialize(bool bakeProbeOcclusion, NativeArray<Vector3> probePositions)
|
|
|
|
|
{
|
|
|
|
|
bakedProbeCount = 0;
|
|
|
|
|
var positions = probePositions;
|
|
|
|
|
_stepCount = positions.Length;
|
|
|
|
|
|
|
|
|
|
anyStepsDone = false;
|
|
|
|
|
finishOnStep = false;
|
|
|
|
|
irradianceSet = false;
|
|
|
|
|
masksSet = false;
|
|
|
|
|
|
|
|
|
|
Debug.Log("Bakery APV baker initialized");
|
|
|
|
|
|
|
|
|
|
irradianceResults = new NativeArray<SphericalHarmonicsL2>(positions.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
|
|
|
|
validityResults = new NativeArray<float>(positions.Length, Allocator.Persistent);//, NativeArrayOptions.UninitializedMemory);
|
|
|
|
|
|
|
|
|
|
occlusionRequested = bakeProbeOcclusion;
|
|
|
|
|
if (bakeProbeOcclusion)
|
|
|
|
|
{
|
|
|
|
|
masks = new NativeArray<Vector4>(positions.Length, Allocator.Persistent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ftAPV.receivedPositions = probePositions;
|
|
|
|
|
ftAPV.positionsUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Step()
|
|
|
|
|
{
|
|
|
|
|
anyStepsDone = true;
|
|
|
|
|
if (finishOnStep) Finish();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Finish()
|
|
|
|
|
{
|
|
|
|
|
if (!anyStepsDone)
|
|
|
|
|
{
|
|
|
|
|
finishOnStep = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!irradianceSet && !masksSet)
|
|
|
|
|
{
|
|
|
|
|
AdaptiveProbeVolumes.Cancel(); // will cause a console error because nobody tested this function? at least it does the job
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!irradianceSet)
|
|
|
|
|
{
|
|
|
|
|
irradianceResults = new NativeArray<SphericalHarmonicsL2>(_stepCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
|
|
|
|
disposeIrradiance = true;
|
|
|
|
|
irradianceSet = true;
|
|
|
|
|
}
|
|
|
|
|
if (!masksSet && occlusionRequested)
|
|
|
|
|
{
|
|
|
|
|
masks = new NativeArray<Vector4>(_stepCount, Allocator.Persistent);
|
|
|
|
|
disposeMasks = true;
|
|
|
|
|
masksSet = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.Log("APV bake finished for "+irradianceResults.Length+" SH probes, "+masks.Length+" occlusion probes, "+validityResults.Length+" validity results.");
|
|
|
|
|
|
|
|
|
|
bakedProbeCount = _stepCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Dispose()
|
|
|
|
|
{
|
|
|
|
|
if (disposeIrradiance) irradianceResults.Dispose();
|
|
|
|
|
if (disposeMasks) masks.Dispose();
|
|
|
|
|
validityResults.Dispose();
|
|
|
|
|
disposeIrradiance = disposeMasks = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class ftAPVSkyBaker : AdaptiveProbeVolumes.SkyOcclusionBaker
|
|
|
|
|
{
|
|
|
|
|
int bakedProbeCount;
|
|
|
|
|
int _stepCount;
|
|
|
|
|
public NativeArray<Vector4> skylightL1;
|
|
|
|
|
public NativeArray<Vector3> skylightDir;
|
|
|
|
|
|
|
|
|
|
public bool skyDataSet = false;
|
|
|
|
|
public bool disposeData = false;
|
|
|
|
|
|
|
|
|
|
public override ulong currentStep => (ulong)bakedProbeCount;
|
|
|
|
|
public override ulong stepCount => (ulong)_stepCount;
|
|
|
|
|
public override NativeArray<Vector4> occlusion => skylightL1;
|
|
|
|
|
public override NativeArray<Vector3> shadingDirections => skylightDir;
|
|
|
|
|
|
|
|
|
|
public override void Initialize(ProbeVolumeBakingSet bakingSet, NativeArray<Vector3> probePositions)
|
|
|
|
|
{
|
|
|
|
|
bakedProbeCount = 0;
|
|
|
|
|
var positions = probePositions;
|
|
|
|
|
_stepCount = positions.Length;
|
|
|
|
|
|
|
|
|
|
Debug.Log("Bakery APV baker (sky occlusion) initialized");
|
|
|
|
|
|
|
|
|
|
ftAPV.skylightRequested = true;
|
|
|
|
|
skyDataSet = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Step()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Finish()
|
|
|
|
|
{
|
|
|
|
|
if (!skyDataSet)
|
|
|
|
|
{
|
|
|
|
|
skylightL1 = new NativeArray<Vector4>(_stepCount, Allocator.Persistent);
|
|
|
|
|
skylightDir = new NativeArray<Vector3>(_stepCount, Allocator.Persistent);
|
|
|
|
|
disposeData = true;
|
|
|
|
|
skyDataSet = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug.Log("APV (sky occlusion) bake finished for "+skylightL1.Length+" SH probes, "+skylightDir.Length+" directions.");
|
|
|
|
|
|
|
|
|
|
bakedProbeCount = _stepCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Dispose()
|
|
|
|
|
{
|
|
|
|
|
if (disposeData)
|
|
|
|
|
{
|
|
|
|
|
skylightL1.Dispose();
|
|
|
|
|
skylightDir.Dispose();
|
|
|
|
|
}
|
|
|
|
|
disposeData = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public class ftAPV
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
static ftAPVBaker baker;
|
|
|
|
|
static ftAPVSkyBaker bakerSky;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public static NativeArray<Vector3> receivedPositions;
|
|
|
|
|
public static bool positionsUpdated;
|
|
|
|
|
public static bool skylightRequested;
|
|
|
|
|
public static float minVoxelSize = 0.5f;
|
|
|
|
|
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
static ProbeVolumeBakingSet CreateOrReplaceAsset(ProbeVolumeBakingSet src, string path)
|
|
|
|
|
{
|
|
|
|
|
var dest = AssetDatabase.LoadAssetAtPath<ProbeVolumeBakingSet>(path);
|
|
|
|
|
if (dest == null)
|
|
|
|
|
{
|
|
|
|
|
AssetDatabase.CreateAsset(src, path);
|
|
|
|
|
dest = src;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var guids = new List<string>();
|
|
|
|
|
foreach(var guid in dest.sceneGUIDs)
|
|
|
|
|
{
|
|
|
|
|
guids.Add(guid);
|
|
|
|
|
}
|
|
|
|
|
for(int i=0; i<guids.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
dest.RemoveScene(guids[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//EditorUtility.CopySerialized(src, dest); // will break ProbeReferenceVolume
|
|
|
|
|
var bset = dest;
|
|
|
|
|
var bakingSet = src;
|
|
|
|
|
bset.minDistanceBetweenProbes = bakingSet.minDistanceBetweenProbes;
|
|
|
|
|
bset.minRendererVolumeSize = bakingSet.minRendererVolumeSize;
|
|
|
|
|
bset.probeOffset = bakingSet.probeOffset;
|
|
|
|
|
bset.renderersLayerMask = bakingSet.renderersLayerMask;
|
|
|
|
|
bset.simplificationLevels = bakingSet.simplificationLevels;
|
|
|
|
|
bset.skyOcclusion = bakingSet.skyOcclusion;
|
|
|
|
|
|
|
|
|
|
EditorUtility.SetDirty(dest);
|
|
|
|
|
}
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static string GenerateLightingDataAssetName()
|
|
|
|
|
{
|
|
|
|
|
var sceneCount = SceneManager.sceneCount;
|
|
|
|
|
var assetName = "";
|
|
|
|
|
var assetNameHashPart = "";
|
|
|
|
|
for(int i=0; i<sceneCount; i++)
|
|
|
|
|
{
|
|
|
|
|
var s = EditorSceneManager.GetSceneAt(i);
|
|
|
|
|
if (!s.isLoaded) continue;
|
|
|
|
|
if (i == 0)
|
|
|
|
|
{
|
|
|
|
|
assetName += s.name;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
assetNameHashPart += s.name;
|
|
|
|
|
if (i < sceneCount - 1) assetNameHashPart += "__";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assetName += "_" + assetNameHashPart.GetHashCode();
|
|
|
|
|
return assetName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool Setup(bool skyOcclusion)
|
|
|
|
|
{
|
|
|
|
|
if (ProbeReferenceVolume.instance == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("ProbeReferenceVolume.instance is null");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var bakingSet = ProbeReferenceVolume.instance.currentBakingSet;
|
|
|
|
|
|
|
|
|
|
// Create our own baking set, keep all placement settings
|
|
|
|
|
var bset = ScriptableObject.CreateInstance<ProbeVolumeBakingSet>();
|
|
|
|
|
bset.name = "BakeryBakingSet_" + GenerateLightingDataAssetName();
|
|
|
|
|
//bset.hideFlags = HideFlags.NotEditable | HideFlags.HideAndDontSave;
|
|
|
|
|
|
|
|
|
|
var setDefFunc = bset.GetType().GetMethod("SetDefaults", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|
|
|
|
if (setDefFunc == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("Can't get ProbeVolumeBakingSet.SetDefaults()");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
setDefFunc.Invoke(bset, null);
|
|
|
|
|
|
|
|
|
|
if (bakingSet != null)
|
|
|
|
|
{
|
|
|
|
|
bset.minDistanceBetweenProbes = bakingSet.minDistanceBetweenProbes;
|
|
|
|
|
bset.minRendererVolumeSize = bakingSet.minRendererVolumeSize;
|
|
|
|
|
bset.probeOffset = bakingSet.probeOffset;
|
|
|
|
|
bset.renderersLayerMask = bakingSet.renderersLayerMask;
|
|
|
|
|
bset.simplificationLevels = bakingSet.simplificationLevels;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Patch baking settings
|
|
|
|
|
bset.skyOcclusion = skyOcclusion;
|
|
|
|
|
|
|
|
|
|
minVoxelSize = bset.minDistanceBetweenProbes;
|
|
|
|
|
|
|
|
|
|
// Save the baking set
|
|
|
|
|
var mainScene = SceneManager.GetActiveScene();
|
|
|
|
|
string path = "Assets";
|
|
|
|
|
if (!string.IsNullOrEmpty(mainScene.path))
|
|
|
|
|
{
|
|
|
|
|
path = (System.IO.Path.GetDirectoryName(mainScene.path) + "/" + mainScene.name);
|
|
|
|
|
if (!System.IO.Directory.Exists(path)) System.IO.Directory.CreateDirectory(path);
|
|
|
|
|
}
|
|
|
|
|
path += "/" + bset.name + ".asset";
|
|
|
|
|
|
|
|
|
|
bset = CreateOrReplaceAsset(bset, path);
|
|
|
|
|
//AssetDatabase.CreateAsset(bset, path);
|
|
|
|
|
AssetDatabase.SaveAssets();
|
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
|
|
|
|
|
|
// Add active scene
|
|
|
|
|
var sceneCount = EditorSceneManager.sceneCount;
|
|
|
|
|
for(int j=0; j<sceneCount; j++)
|
|
|
|
|
{
|
|
|
|
|
var scene = EditorSceneManager.GetSceneAt(j);
|
|
|
|
|
if (!scene.isLoaded) continue;
|
|
|
|
|
|
|
|
|
|
var sceneToAddGUID = AssetDatabase.AssetPathToGUID(scene.path);
|
|
|
|
|
|
|
|
|
|
if (!bset.TryAddScene(sceneToAddGUID))
|
|
|
|
|
{
|
|
|
|
|
bool solved = false;
|
|
|
|
|
var otherSetsGUIDs = AssetDatabase.FindAssets("t:" + typeof(ProbeVolumeBakingSet).Name);
|
|
|
|
|
foreach (var otherSetsGUID in otherSetsGUIDs)
|
|
|
|
|
{
|
|
|
|
|
var otherSetPath = AssetDatabase.GUIDToAssetPath(otherSetsGUID);
|
|
|
|
|
var otherSet = AssetDatabase.LoadAssetAtPath<ProbeVolumeBakingSet>(otherSetPath);
|
|
|
|
|
if (otherSet != null)
|
|
|
|
|
{
|
|
|
|
|
foreach(var sceneGUID in otherSet.sceneGUIDs)
|
|
|
|
|
{
|
|
|
|
|
if (sceneGUID == sceneToAddGUID)
|
|
|
|
|
{
|
|
|
|
|
if (EditorUtility.DisplayDialog("Bakery", "The scene " + scene.path + " is part of the Baking Set " + otherSetPath + ". Do you want to move the scene to a new set?", "OK", "Cancel"))
|
|
|
|
|
{
|
|
|
|
|
otherSet.RemoveScene(sceneGUID);
|
|
|
|
|
if (!bset.TryAddScene(sceneToAddGUID))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("Scene " + scene.path + " was removed from Baking Set " + otherSetPath + ", but TryAddScene still failed.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.Log("Scene " + scene.name + " moved to a new Baking Set");
|
|
|
|
|
solved = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("Scene " + scene.path + " is alreasy used in Baking Set " + otherSetPath + ". Delete the Baking Set or remove the scene from it.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (solved) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!solved)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("ProbeVolumeBakingSet.TryAddScene() failed for unknown reason with scene " + scene.path);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set as active
|
|
|
|
|
ProbeReferenceVolume.instance.SetActiveBakingSet(bset);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public static bool Run(bool skyOcclusion)
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
|
|
|
|
|
if (!Setup(skyOcclusion)) return false;
|
|
|
|
|
|
|
|
|
|
baker = new ftAPVBaker();
|
|
|
|
|
bakerSky = new ftAPVSkyBaker();
|
|
|
|
|
positionsUpdated = false;
|
|
|
|
|
skylightRequested = false;
|
|
|
|
|
AdaptiveProbeVolumes.SetLightingBakerOverride(baker);
|
|
|
|
|
AdaptiveProbeVolumes.SetSkyOcclusionBakerOverride(skyOcclusion ? bakerSky : null);
|
|
|
|
|
if (!AdaptiveProbeVolumes.BakeAsync())
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("AdaptiveProbeVolumes.BakeAsync() failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool IsBaking()
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
return AdaptiveProbeVolumes.isRunning;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SetSHs(NativeArray<SphericalHarmonicsL2> shs)
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
baker.irradianceResults = shs;
|
|
|
|
|
baker.irradianceSet = true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SetMasks(NativeArray<Vector4> masks)
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
baker.masks = masks;
|
|
|
|
|
baker.masksSet = true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SetSkyOcclusion(NativeArray<Vector4> skylightL1, NativeArray<Vector3> skylightDir)
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
bakerSky.skylightL1 = skylightL1;
|
|
|
|
|
bakerSky.skylightDir = skylightDir;
|
|
|
|
|
bakerSky.skyDataSet = true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Finish()
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
baker.Finish();
|
|
|
|
|
bakerSky.Finish();
|
|
|
|
|
Cleanup();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Cleanup()
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
AdaptiveProbeVolumes.SetLightingBakerOverride(null);
|
|
|
|
|
AdaptiveProbeVolumes.SetSkyOcclusionBakerOverride(null);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool AnyAPVsInScene()
|
|
|
|
|
{
|
|
|
|
|
#if SUPPORTS_APV
|
|
|
|
|
var anyAPVs = GameObject.FindObjectsOfType<ProbeVolume>();
|
|
|
|
|
foreach(var apv in anyAPVs)
|
|
|
|
|
{
|
|
|
|
|
if (apv.enabled && apv.gameObject.activeInHierarchy) return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|