void ClearVoxel(Vector3Int pos, CellIndexUpdateInfo cellInfo) { Vector3Int vx_min, vx_max; ClipToIndexSpace(pos, GetVoxelSubdivLevel(), out vx_min, out vx_max, cellInfo); UpdatePhysicalIndex(vx_min, vx_max, -1, cellInfo); }
internal bool AssignIndexChunksToCell(int bricksCount, ref CellIndexUpdateInfo cellUpdateInfo) { // We need to better handle the case where the chunks are full, this is where streaming will need to come into place swapping in/out // Also the current way to find an empty spot might be sub-optimal, when streaming is in place it'd be nice to have this more efficient // if it is meant to happen frequently. int numberOfChunks = Mathf.CeilToInt((float)bricksCount / kIndexChunkSize); // Search for the first empty element with enough space. int firstValidChunk = -1; for (int i = 0; i < m_IndexInChunks; ++i) { if (!m_IndexChunks[i] && (i + numberOfChunks) < m_IndexInChunks) { int emptySlotsStartingHere = 0; for (int k = i; k < (i + numberOfChunks); ++k) { if (!m_IndexChunks[k]) { emptySlotsStartingHere++; } else { break; } } if (emptySlotsStartingHere == numberOfChunks) { firstValidChunk = i; break; } } } if (firstValidChunk < 0) { Debug.LogError("APV Index Allocation failed."); return(false); } // This assert will need to go away or do something else when streaming is allowed (we need to find holes in available chunks or stream out stuff) cellUpdateInfo.firstChunkIndex = firstValidChunk; cellUpdateInfo.numberOfChunks = numberOfChunks; for (int i = firstValidChunk; i < (firstValidChunk + numberOfChunks); ++i) { Debug.Assert(!m_IndexChunks[i]); m_IndexChunks[i] = true; } m_NextFreeChunk += Mathf.Max(0, (firstValidChunk + numberOfChunks) - m_NextFreeChunk); m_AvailableChunkCount -= numberOfChunks; return(true); }
void UpdateIndexForVoxel(Vector3Int voxel, CellIndexUpdateInfo cellInfo) { ClearVoxel(voxel, cellInfo); List <VoxelMeta> vm_list = m_VoxelToBricks[voxel]; foreach (var vm in vm_list) { // get the list of bricks and indices List <ReservedBrick> bricks = m_BricksToVoxels[vm.cell].bricks; List <ushort> indcs = vm.brickIndices; UpdateIndexForVoxel(voxel, bricks, indcs, cellInfo); } }
void UpdatePhysicalIndex(Vector3Int brickMin, Vector3Int brickMax, int value, CellIndexUpdateInfo cellInfo) { // We need to do our calculations in local space to the cell, so we move the brick to local space as a first step. // Reminder that at this point we are still operating at highest resolution possible, not necessarily the one that will be // the final resolution for the chunk. brickMin = brickMin - cellInfo.cellPositionInBricksAtMaxRes; brickMax = brickMax - cellInfo.cellPositionInBricksAtMaxRes; // Since the index is spurious (not same resolution, but varying per cell) we need to bring to the output resolution the brick coordinates // Before finding the locations inside the Index for the current cell/chunk. brickMin /= ProbeReferenceVolume.CellSize(cellInfo.minSubdivInCell); brickMax /= ProbeReferenceVolume.CellSize(cellInfo.minSubdivInCell); // Verify we are actually in local space now. int maxCellSizeInOutputRes = ProbeReferenceVolume.CellSize(ProbeReferenceVolume.instance.GetMaxSubdivision() - 1 - cellInfo.minSubdivInCell); Debug.Assert(brickMin.x >= 0 && brickMin.y >= 0 && brickMin.z >= 0 && brickMax.x >= 0 && brickMax.y >= 0 && brickMax.z >= 0); Debug.Assert(brickMin.x < maxCellSizeInOutputRes && brickMin.y < maxCellSizeInOutputRes && brickMin.z < maxCellSizeInOutputRes && brickMax.x <= maxCellSizeInOutputRes && brickMax.y <= maxCellSizeInOutputRes && brickMax.z <= maxCellSizeInOutputRes); // We are now in the right resolution, but still not considering the valid area, so we need to still normalize against that. // To do so first let's move back the limits to the desired resolution var cellMinIndex = cellInfo.minValidBrickIndexForCellAtMaxRes / ProbeReferenceVolume.CellSize(cellInfo.minSubdivInCell); var cellMaxIndex = cellInfo.maxValidBrickIndexForCellAtMaxResPlusOne / ProbeReferenceVolume.CellSize(cellInfo.minSubdivInCell); // Then perform the rescale of the local indices for min and max. brickMin -= cellMinIndex; brickMax -= cellMinIndex; // In theory now we are all positive since we clipped during the voxel stage. Keeping assert for debugging, but can go later. Debug.Assert(brickMin.x >= 0 && brickMin.y >= 0 && brickMin.z >= 0 && brickMax.x >= 0 && brickMax.y >= 0 && brickMax.z >= 0); // Compute the span of the valid part var size = (cellMaxIndex - cellMinIndex); // Loop through all touched indices int chunkStart = cellInfo.firstChunkIndex * kIndexChunkSize; for (int z = brickMin.z; z < brickMax.z; ++z) { for (int y = brickMin.y; y < brickMax.y; ++y) { for (int x = brickMin.x; x < brickMax.x; ++x) { int localFlatIdx = z * (size.x * size.y) + x * size.y + y; int actualIdx = chunkStart + localFlatIdx; m_PhysicalIndexBufferData[actualIdx] = value; m_UpdateMinIndex = Math.Min(actualIdx, m_UpdateMinIndex); m_UpdateMaxIndex = Math.Max(actualIdx, m_UpdateMaxIndex); } } } m_NeedUpdateIndexComputeBuffer = true; }
public void AddBricks(Cell cell, NativeArray <Brick> bricks, List <Chunk> allocations, int allocationSize, int poolWidth, int poolHeight, CellIndexUpdateInfo cellInfo) { Debug.Assert(bricks.Length <= ushort.MaxValue, "Cannot add more than 65K bricks per RegId."); int largest_cell = ProbeReferenceVolume.CellSize(kMaxSubdivisionLevels); g_Cell = cell; // create a new copy BrickMeta bm = m_BrickMetaPool.Get(); m_BricksToVoxels.Add(cell, bm); int brick_idx = 0; // find all voxels each brick will touch for (int i = 0; i < allocations.Count; i++) { Chunk alloc = allocations[i]; int cnt = Mathf.Min(allocationSize, bricks.Length - brick_idx); for (int j = 0; j < cnt; j++, brick_idx++, alloc.x += ProbeBrickPool.kBrickProbeCountPerDim) { Brick brick = bricks[brick_idx]; int cellSize = ProbeReferenceVolume.CellSize(brick.subdivisionLevel); Debug.Assert(cellSize <= largest_cell, "Cell sizes are not correctly sorted."); largest_cell = Mathf.Min(largest_cell, cellSize); MapBrickToVoxels(brick, bm.voxels); ReservedBrick rbrick = new ReservedBrick(); rbrick.brick = brick; rbrick.flattenedIdx = MergeIndex(alloc.flattenIndex(poolWidth, poolHeight), brick.subdivisionLevel); bm.bricks.Add(rbrick); foreach (var v in bm.voxels) { List <VoxelMeta> vm_list; if (!m_VoxelToBricks.TryGetValue(v, out vm_list)) // first time the voxel is touched { vm_list = m_VoxelMetaListPool.Get(); m_VoxelToBricks.Add(v, vm_list); } VoxelMeta vm = null; int vm_idx = vm_list.FindIndex((VoxelMeta lhs) => lhs.cell == g_Cell); if (vm_idx == -1) // first time a brick from this id has touched this voxel { vm = m_VoxelMetaPool.Get(); vm.cell = cell; vm_list.Add(vm); } else { vm = vm_list[vm_idx]; } // add this brick to the voxel under its regId vm.brickIndices.Add((ushort)brick_idx); } } } foreach (var voxel in bm.voxels) { UpdateIndexForVoxel(voxel, cellInfo); } }
internal bool AssignIndexChunksToCell(int bricksCount, ref CellIndexUpdateInfo cellUpdateInfo, bool ignoreErrorLog) { // We need to better handle the case where the chunks are full, this is where streaming will need to come into place swapping in/out // Also the current way to find an empty spot might be sub-optimal, when streaming is in place it'd be nice to have this more efficient // if it is meant to happen frequently. int numberOfChunks = Mathf.CeilToInt((float)bricksCount / kIndexChunkSize); // Search for the first empty element with enough space. int firstValidChunk = -1; for (int i = 0; i < m_IndexInChunks; ++i) { if (!m_IndexChunks[i] && (i + numberOfChunks) < m_IndexInChunks) { int emptySlotsStartingHere = 0; for (int k = i; k < (i + numberOfChunks); ++k) { if (!m_IndexChunks[k]) { emptySlotsStartingHere++; } else { break; } } if (emptySlotsStartingHere == numberOfChunks) { firstValidChunk = i; break; } } } if (firstValidChunk < 0) { // During baking we know we can hit this when trying to do dilation of all cells at the same time. // That can happen because we try to load all cells at the same time. If the budget is not high enough it will fail. // In this case we'll iterate separately on each cell and their neighbors. // If so, we don't want controlled error message spam during baking so we ignore it. // In theory this should never happen with proper streaming/defrag but we keep the message just in case otherwise. if (!ignoreErrorLog) { Debug.LogError("APV Index Allocation failed."); } return(false); } // This assert will need to go away or do something else when streaming is allowed (we need to find holes in available chunks or stream out stuff) cellUpdateInfo.firstChunkIndex = firstValidChunk; cellUpdateInfo.numberOfChunks = numberOfChunks; for (int i = firstValidChunk; i < (firstValidChunk + numberOfChunks); ++i) { Debug.Assert(!m_IndexChunks[i]); m_IndexChunks[i] = true; } m_NextFreeChunk += Mathf.Max(0, (firstValidChunk + numberOfChunks) - m_NextFreeChunk); m_AvailableChunkCount -= numberOfChunks; return(true); }