public static bool OBBIntersect(ref ProbeReferenceVolume.Volume a, ref ProbeReferenceVolume.Volume b) { // First we test if the bounding spheres intersects, in which case we case do the more complex OBB test a.CalculateCenterAndSize(out var aCenter, out var aSize); b.CalculateCenterAndSize(out var bCenter, out var bSize); var aRadius = aSize.sqrMagnitude / 2.0f; var bRadius = bSize.sqrMagnitude / 2.0f; if (Vector3.SqrMagnitude(aCenter - bCenter) > aRadius + bRadius) { return(false); } m_Axes[0] = a.X.normalized; m_Axes[1] = a.Y.normalized; m_Axes[2] = a.Z.normalized; m_Axes[3] = b.X.normalized; m_Axes[4] = b.Y.normalized; m_Axes[5] = b.Z.normalized; foreach (Vector3 axis in m_Axes) { Vector2 aProj = ProjectOBB(ref a, axis); Vector2 bProj = ProjectOBB(ref b, axis); if (aProj.y < bProj.x || bProj.y < aProj.x) { return(false); } } return(true); }
static IEnumerable <(ProbeReferenceVolume.Volume volume, Vector3 parentPosition)> SubdivideVolumeIntoSubVolume(GPUSubdivisionContext ctx, ProbeReferenceVolume.Volume volume) { volume.CalculateCenterAndSize(out var center, out var size); float maxBrickInSubCell = Mathf.Pow(3, k_MaxSubdivisionInSubCell); float subdivisionCount = ctx.maxBrickCountPerAxis / (float)ctx.maxBrickCountPerAxisInSubCell; var subVolumeSize = size / subdivisionCount; for (int x = 0; x < (int)subdivisionCount; x++) { for (int y = 0; y < (int)subdivisionCount; y++) { for (int z = 0; z < (int)subdivisionCount; z++) { var subVolume = new ProbeReferenceVolume.Volume() { corner = volume.corner + new Vector3(x * subVolumeSize.x, y * subVolumeSize.y, z * subVolumeSize.z), X = volume.X / subdivisionCount, Y = volume.Y / subdivisionCount, Z = volume.Z / subdivisionCount, maxSubdivisionMultiplier = volume.maxSubdivisionMultiplier, minSubdivisionMultiplier = volume.minSubdivisionMultiplier, }; var parentCellPosition = new Vector3(x, y, z); yield return(subVolume, parentCellPosition); } } } }
private static Vector2 ProjectOBB(ref ProbeReferenceVolume.Volume a, Vector3 axis) { float min = Vector3.Dot(axis, a.corner); float max = min; for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { for (int z = 0; z < 2; z++) { Vector3 vert = a.corner + a.X * x + a.Y * y + a.Z * z; float proj = Vector3.Dot(axis, vert); if (proj < min) { min = proj; } else if (proj > max) { max = proj; } } } } return(new Vector2(min, max)); }
static protected int RenderersToVolumes(ref Renderer[] renderers, ref ProbeReferenceVolume.Volume cellVolume, ref List <ProbeReferenceVolume.Volume> volumes, ref Dictionary <Scene, int> sceneRefs) { int num = 0; foreach (Renderer r in renderers) { var flags = GameObjectUtility.GetStaticEditorFlags(r.gameObject) & StaticEditorFlags.ContributeGI; bool contributeGI = (flags & StaticEditorFlags.ContributeGI) != 0; if (!r.enabled || !r.gameObject.activeSelf || !contributeGI) { continue; } ProbeReferenceVolume.Volume v = ToVolume(r.bounds); if (ProbeVolumePositioning.OBBIntersect(ref cellVolume, ref v)) { volumes.Add(v); TrackSceneRefs(r.gameObject.scene, ref sceneRefs); num++; } } return(num); }
public static void Subdivide(ProbeReferenceVolume.Volume cellVolume, ProbeReferenceVolume refVol, List <ProbeReferenceVolume.Volume> influencerVolumes, ref Vector3[] positions, ref List <ProbeBrickIndex.Brick> bricks) { // TODO move out var indicatorVolumes = new List <ProbeReferenceVolume.Volume>(); foreach (ProbeVolume pv in UnityEngine.Object.FindObjectsOfType <ProbeVolume>()) { if (!pv.enabled) { continue; } indicatorVolumes.Add(new ProbeReferenceVolume.Volume(Matrix4x4.TRS(pv.transform.position, pv.transform.rotation, pv.GetExtents()), pv.parameters.maxSubdivisionMultiplier, pv.parameters.minSubdivisionMultiplier)); } ProbeReferenceVolume.SubdivisionDel subdivDel = (RefTrans refTrans, int subdivisionLevel, List <Brick> inBricks, List <Flags> outFlags) => { SubdivisionAlgorithm(cellVolume, indicatorVolumes, influencerVolumes, refTrans, inBricks, subdivisionLevel, outFlags); }; bricks = new List <ProbeBrickIndex.Brick>(); // get a list of bricks for this volume int numProbes; refVol.CreateBricks(new List <ProbeReferenceVolume.Volume>() { cellVolume }, influencerVolumes, subdivDel, bricks, out numProbes); positions = new Vector3[numProbes]; refVol.ConvertBricks(bricks, positions); }
static public ProbeReferenceVolume.Volume ToVolume(Bounds bounds) { ProbeReferenceVolume.Volume v = new ProbeReferenceVolume.Volume(); v.corner = bounds.center - bounds.size * 0.5f; v.X = new Vector3(bounds.size.x, 0, 0); v.Y = new Vector3(0, bounds.size.y, 0); v.Z = new Vector3(0, 0, bounds.size.z); return(v); }
public static void SubdivisionAlgorithm(ProbeReferenceVolume.Volume cellVolume, List <ProbeReferenceVolume.Volume> probeVolumes, List <ProbeReferenceVolume.Volume> influenceVolumes, RefTrans refTrans, List <Brick> inBricks, int subdivisionLevel, List <Flags> outFlags) { Flags f = new Flags(); for (int i = 0; i < inBricks.Count; i++) { ProbeReferenceVolume.Volume brickVolume = ProbeVolumePositioning.CalculateBrickVolume(ref refTrans, inBricks[i]); // Find the local max from all overlapping probe volumes: float localMaxSubdiv = 0; float localMinSubdiv = 0; bool overlap = false; foreach (ProbeReferenceVolume.Volume v in probeVolumes) { ProbeReferenceVolume.Volume vol = v; if (ProbeVolumePositioning.OBBIntersect(ref vol, ref brickVolume)) { overlap = true; localMaxSubdiv = Mathf.Max(localMaxSubdiv, vol.maxSubdivisionMultiplier); // Do we use max for min subdiv too? localMinSubdiv = Mathf.Max(localMinSubdiv, vol.minSubdivisionMultiplier); } } bool belowMaxSubdiv = subdivisionLevel <= ProbeReferenceVolume.instance.GetMaxSubdivision(localMaxSubdiv); bool belowMinSubdiv = subdivisionLevel <= ProbeReferenceVolume.instance.GetMaxSubdivision(localMinSubdiv); // Keep bricks that overlap at least one probe volume, and at least one influencer (mesh) if ((belowMinSubdiv && overlap) || (belowMaxSubdiv && ShouldKeepBrick(probeVolumes, brickVolume) && ShouldKeepBrick(influenceVolumes, brickVolume))) { f.subdivide = true; // Transform into refvol space brickVolume.Transform(refTrans.refSpaceToWS.inverse); ProbeReferenceVolume.Volume cellVolumeTrans = new ProbeReferenceVolume.Volume(cellVolume); cellVolumeTrans.Transform(refTrans.refSpaceToWS.inverse); cellVolumeTrans.maxSubdivisionMultiplier = localMaxSubdiv; // Discard parent brick if it extends outside of the cell, to prevent duplicates var brickVolumeMax = brickVolume.corner + brickVolume.X + brickVolume.Y + brickVolume.Z; var cellVolumeMax = cellVolumeTrans.corner + cellVolumeTrans.X + cellVolumeTrans.Y + cellVolumeTrans.Z; f.discard = brickVolumeMax.x > cellVolumeMax.x || brickVolumeMax.y > cellVolumeMax.y || brickVolumeMax.z > cellVolumeMax.z || brickVolume.corner.x < cellVolumeTrans.corner.x || brickVolume.corner.y < cellVolumeTrans.corner.y || brickVolume.corner.z < cellVolumeTrans.corner.z; } else { f.discard = true; f.subdivide = false; } outFlags.Add(f); } }
internal static bool ShouldKeepBrick(List <ProbeReferenceVolume.Volume> volumes, ProbeReferenceVolume.Volume brick) { foreach (ProbeReferenceVolume.Volume v in volumes) { ProbeReferenceVolume.Volume vol = v; if (ProbeVolumePositioning.OBBIntersect(ref vol, ref brick)) { return(true); } } return(false); }
// TODO: Take refvol translation and rotation into account public static ProbeReferenceVolume.Volume CalculateBrickVolume(ref RefTrans refTrans, Brick brick) { float scaledSize = Mathf.Pow(3, brick.subdivisionLevel); Vector3 scaledPos = refTrans.refSpaceToWS.MultiplyPoint(brick.position); var bounds = new ProbeReferenceVolume.Volume( scaledPos, refTrans.refSpaceToWS.GetColumn(0) * scaledSize, refTrans.refSpaceToWS.GetColumn(1) * scaledSize, refTrans.refSpaceToWS.GetColumn(2) * scaledSize ); return(bounds); }
static protected void CullVolumes(ref List <ProbeReferenceVolume.Volume> cullees, ref List <ProbeReferenceVolume.Volume> cullers, ref List <ProbeReferenceVolume.Volume> result) { foreach (ProbeReferenceVolume.Volume v in cullers) { ProbeReferenceVolume.Volume lv = v; foreach (ProbeReferenceVolume.Volume c in cullees) { if (result.Contains(c)) { continue; } ProbeReferenceVolume.Volume lc = c; if (ProbeVolumePositioning.OBBIntersect(ref lv, ref lc)) { result.Add(c); } } } }
static public void CreateInfluenceVolumes(ref ProbeReferenceVolume.Volume cellVolume, Renderer[] renderers, ProbeVolume[] probeVolumes, out List <ProbeReferenceVolume.Volume> culledVolumes, out Dictionary <Scene, int> sceneRefs) { // Keep track of volumes and which scene they originated from sceneRefs = new Dictionary <Scene, int>(); // Extract all influencers inside the cell List <ProbeReferenceVolume.Volume> influenceVolumes = new List <ProbeReferenceVolume.Volume>(); RenderersToVolumes(ref renderers, ref cellVolume, ref influenceVolumes, ref sceneRefs); NavPathsToVolumes(ref cellVolume, ref influenceVolumes, ref sceneRefs); ImportanceVolumesToVolumes(ref cellVolume, ref influenceVolumes, ref sceneRefs); LightsToVolumes(ref cellVolume, ref influenceVolumes, ref sceneRefs); // Extract all ProbeVolumes inside the cell List <ProbeReferenceVolume.Volume> indicatorVolumes = new List <ProbeReferenceVolume.Volume>(); ProbeVolumesToVolumes(ref probeVolumes, ref cellVolume, ref indicatorVolumes, ref sceneRefs); // Cull all influencers against ProbeVolumes culledVolumes = new List <ProbeReferenceVolume.Volume>(); CullVolumes(ref influenceVolumes, ref indicatorVolumes, ref culledVolumes); }
static protected int ProbeVolumesToVolumes(ref ProbeVolume[] probeVolumes, ref ProbeReferenceVolume.Volume cellVolume, ref List <ProbeReferenceVolume.Volume> volumes, ref Dictionary <Scene, int> sceneRefs) { int num = 0; foreach (ProbeVolume pv in probeVolumes) { if (!pv.isActiveAndEnabled) { continue; } ProbeReferenceVolume.Volume indicatorVolume = new ProbeReferenceVolume.Volume(Matrix4x4.TRS(pv.transform.position, pv.transform.rotation, pv.GetExtents()), pv.parameters.maxSubdivisionMultiplier, pv.parameters.minSubdivisionMultiplier); if (ProbeVolumePositioning.OBBIntersect(ref cellVolume, ref indicatorVolume)) { cellVolume.maxSubdivisionMultiplier = Mathf.Max(cellVolume.maxSubdivisionMultiplier, pv.parameters.maxSubdivisionMultiplier, pv.parameters.minSubdivisionMultiplier); volumes.Add(indicatorVolume); TrackSceneRefs(pv.gameObject.scene, ref sceneRefs); num++; } } return(num); }
public static List <Brick> SubdivideCell(ProbeReferenceVolume.Volume cellVolume, ProbeSubdivisionContext subdivisionCtx, GPUSubdivisionContext ctx, List <(Renderer component, ProbeReferenceVolume.Volume volume)> renderers, List <(ProbeVolume component, ProbeReferenceVolume.Volume volume)> probeVolumes)
public static bool OBBIntersect(ref RefTrans refTrans, Brick brick, ref ProbeReferenceVolume.Volume volume) { var transformed = CalculateBrickVolume(ref refTrans, brick); return(OBBIntersect(ref transformed, ref volume)); }
internal Bounds GetBounds() { ProbeReferenceVolume.Volume volume = new ProbeReferenceVolume.Volume(Matrix4x4.TRS(transform.position, transform.rotation, GetExtents()), 0, 0); return(volume.CalculateAABB()); }
static protected int LightsToVolumes(ref ProbeReferenceVolume.Volume cellVolume, ref List <ProbeReferenceVolume.Volume> volumes, ref Dictionary <Scene, int> sceneRefs) { // TODO return(0); }