/// <summary> /// Checks only immediate children (any deeper would take too long). /// </summary> private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null) { return(false); } Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod); var start = thisLodCell.CoordInLod << shiftToChild; var end = start + ((1 << shiftToChild) >> 1); Vector3I.Max(ref childLod.m_lodSizeMinusOne, ref Vector3I.Zero, out childLod.m_lodSizeMinusOne); Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); childLodCell.CoordInLod = start; for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out childLodCell.CoordInLod)) { var key = childLodCell.PackId64(); CellData data; if (!childLod.m_storedCellData.TryGetValue(key, out data) || !data.WasLoaded) { return(false); } } return(true); }
private void GetNearbyLodLevels(out LodLevel parentLod, out LodLevel childLod) { var levels = m_parent.m_lodLevels; int parentIdx = m_lodIndex + 1; if (levels.IsValidIndex(parentIdx)) { parentLod = levels[parentIdx]; } else { parentLod = null; } int childIdx = m_lodIndex - 1; if (levels.IsValidIndex(childIdx)) { childLod = levels[childIdx]; } else { childLod = null; } }
/// <summary> /// Checks only immediate children (any deeper would take too long). /// </summary> private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null || !childLod.Visible) return false; Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var start = thisLodCell.CoordInLod << 1; var end = start + 1; Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); for (childLodCell.CoordInLod.Z = start.Z; childLodCell.CoordInLod.Z <= end.Z; ++childLodCell.CoordInLod.Z) for (childLodCell.CoordInLod.Y = start.Y; childLodCell.CoordInLod.Y <= end.Y; ++childLodCell.CoordInLod.Y) for (childLodCell.CoordInLod.X = start.X; childLodCell.CoordInLod.X <= end.X; ++childLodCell.CoordInLod.X) { var key = childLodCell.PackId64(); CellData data; if (!childLod.m_storedCellData.TryGetValue(key, out data)) { return false; } if (!data.WasLoaded) { return false; } } return true; }
/// <summary> /// Checks ancestor nodes recursively. /// </summary> private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell) { if (parentLod == null || !parentLod.m_fitsInFrustum || !parentLod.Visible) { return(true); } Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1); var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(thisLodCell.Lod); var parentCell = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> shiftToParent); CellData data; if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data)) { return(data.WasLoaded); } LodLevel ancestor; if (parentLod.m_parent.m_lodLevels.TryGetValue(parentLod.m_lodIndex + 1, out ancestor)) { return(WasAncestorCellLoaded(ancestor, ref parentCell)); } else { return(false); } }
bool ShowLodLevel(LodLevel lod, int index) { bool removeThis = false; EGL.BeginVertical(GuiUtils.Skin.box); { GUILayout.Label("[" + index + "]"); lod.Level = EGL.IntField("Lod Level", lod.Level); GUILayout.BeginHorizontal(); { lod.FolderPath = EGL.TextField("Folder Path", lod.FolderPath); if (GUILayout.Button("Browse", GUILayout.Width(50f))) { lod.FolderPath = UPath.GetProjectPath(EditorUtility.OpenFolderPanel("Browse", lod.FolderPath, Application.dataPath)); } } GUILayout.EndHorizontal(); lod.GridSize = EGL.IntField("Grid Size", lod.GridSize); lod.HeightmapResolution = EGL.IntField("Heightmap Resolution (px)", lod.HeightmapResolution); lod.SplatmapResolution = EGL.IntField("Splatmap Resolution (px)", lod.SplatmapResolution); lod.HasDetailMap = EGL.Toggle("Use Detail Map?", lod.HasDetailMap); lod.HasTreeMap = EGL.Toggle("Use Tree Map?", lod.HasTreeMap); if (lod.HasDetailMap) { lod.DetailmapResolution = EGL.IntField("Detailmap Resolution (px)", lod.DetailmapResolution); lod.DetailResolutionPerPatch = EGL.IntField("Detailmap Patch Size (px)", lod.DetailResolutionPerPatch); } EGL.Space(); GUILayout.Label("In-game terrain dimensions."); lod.TerrainWidth = EGL.FloatField("Width & Length (m)", lod.TerrainWidth); lod.TerrainHeight = EGL.FloatField("Height (m)", lod.TerrainHeight); EGL.Space(); GUILayout.Label("Relief Terrain Configuration"); lod.ColormapResolution = EGL.IntField("Colormap Resolution", lod.ColormapResolution); lod.NormalmapResolution = EGL.IntField("Normalmap Resolution", lod.NormalmapResolution); EGL.Space(); if (GUILayout.Button("Remove", GUILayout.Width(64f), GUILayout.Height(64f))) { removeThis = true; } } EGL.EndVertical(); return(removeThis); }
public void CreateLodGroupColliders(LODGroup lodGroup, Transform parentT) { var lodGroupGO = new GameObject("L_" + lodGroup.name); Transform lodGroupT = lodGroupGO.transform; lodGroupT.parent = parentT; LOD[] lods = lodGroup.GetLODs(); bool meshColliderCreated = false; for (int i = 0; i < lods.Length; i++) { LOD lod = lods[i]; LodLevel lodLevel = new LodLevel(); Renderer[] rs = lod.renderers; for (int j = 0; j < rs.Length; j++) { Renderer r = rs[j]; GameObject go = r.gameObject; if (r.enabled && go.activeInHierarchy) { MeshFilter mf = go.GetComponent <MeshFilter>(); if (mf == null) { continue; } Mesh mesh = mf.sharedMesh; if (mesh == null) { continue; } meshColliderCreated = true; MeshCollider mc = CreateMeshCollider(mf, lodGroupT, "L" + i + "_"); lodLevel.colliders.Add(mc); lodLevel.gos.Add(mc.gameObject); lodInfoLookup.Add(mc, this); lodGroupMeshes.Add(mesh); } } lodLevels.Add(lodLevel); } if (meshColliderCreated) { lodInfos.Add(this); } }
public MeshLOD GetLOD(LodLevel level) { string lodName; switch (level) { case LodLevel.Physics: lodName = "physics_mesh"; break; case LodLevel.LOD0: lodName = "lowest_lod"; break; case LodLevel.LOD1: lodName = "low_lod"; break; case LodLevel.LOD2: lodName = "medium_lod"; break; case LodLevel.LOD3: lodName = "high_lod"; break; default: throw new ArgumentOutOfRangeException(nameof(level)); } IValue iv; if (!m_MeshData.TryGetValue(lodName, out iv)) { throw new NoSuchMeshDataException(); } var lodMap = iv as Map; if (lodMap == null) { throw new NoSuchMeshDataException(); } int physOffset = lodMap["offset"].AsInt + m_EndOfHeader; int physSize = lodMap["size"].AsInt; if (physOffset < m_EndOfHeader || physSize <= 0) { throw new NotAMeshFormatException(); } return(new MeshLOD(m_AssetData, physOffset, physSize)); }
public bool TryGetLODByteSize(LodLevel level, out int bytesize) { bytesize = 0; string lodName; switch (level) { case LodLevel.Physics: lodName = "physics_mesh"; break; case LodLevel.LOD0: lodName = "lowest_lod"; break; case LodLevel.LOD1: lodName = "low_lod"; break; case LodLevel.LOD2: lodName = "medium_lod"; break; case LodLevel.LOD3: lodName = "high_lod"; break; default: throw new ArgumentOutOfRangeException(nameof(level)); } IValue iv; if (!m_MeshData.TryGetValue(lodName, out iv)) { return(false); } var lodMap = iv as Map; if (lodMap == null) { return(false); } bytesize = lodMap["size"].AsInt; if (bytesize < m_EndOfHeader || bytesize <= 0) { bytesize = 0; return(false); } return(true); }
public MyClipmap(uint id, MyClipmapScaleEnum scaleGroup, MatrixD worldMatrix, Vector3I sizeLod0, IMyClipmapCellHandler cellProvider) { m_scaleGroup = scaleGroup; m_worldMatrix = worldMatrix; MatrixD.Invert(ref m_worldMatrix, out m_invWorldMatrix); m_sizeLod0 = sizeLod0; m_localAABB = new BoundingBoxD(Vector3D.Zero, new Vector3D(sizeLod0 * MyVoxelConstants.RENDER_CELL_SIZE_IN_METRES)); for (int lod = 0; lod < m_lodLevels.Length; ++lod) { m_lodLevels[lod] = new LodLevel(this, lod, ((m_sizeLod0 - 1) >> lod) + 1); } m_updateQueueItem = new UpdateQueueItem(this); m_requestCollector = new RequestCollector(id); m_cellHandler = cellProvider; }
public MyClipmap(uint id, MyClipmapScaleEnum scaleGroup, MatrixD worldMatrix, Vector3I sizeLod0, IMyClipmapCellHandler cellProvider) { m_scaleGroup = scaleGroup; m_worldMatrix = worldMatrix; MatrixD.Invert(ref m_worldMatrix, out m_invWorldMatrix); m_sizeLod0 = sizeLod0; m_localAABB = new BoundingBoxD(Vector3D.Zero, new Vector3D(sizeLod0 * MyVoxelCoordSystems.RenderCellSizeInMeters(0))); for (int lod = 0; lod < m_lodLevels.Length; ++lod) { var sizeShift = lod + MyVoxelCoordSystems.RenderCellSizeInLodVoxelsShiftDelta(lod); m_lodLevels[lod] = new LodLevel(this, lod, ((m_sizeLod0 - 1) >> sizeShift) + 1); } m_updateQueueItem = new UpdateQueueItem(this); m_requestCollector = new RequestCollector(id); m_cellHandler = cellProvider; }
private bool TryAddCellRequest(RequestCollector collector, LodLevel parentLod, MyCellCoord cell, ulong cellId, CellData data) { var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod); var parentCell = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell; BoundingBoxD worldAABB; MyVoxelCoordSystems.RenderCellCoordToWorldAABB(m_clipmap.m_worldMatrix.Translation, ref parentCell, out worldAABB); worldAABB.Inflate(-1.0f * m_lodIndex * m_lodIndex); var parentCellId = parentCell.PackId64(); //if (PriorityFunc(worldAABB.Center, parentLod, parentCellId) == int.MaxValue) //this cell would just slow down sorting, it will be added again if needed // return false; collector.AddRequest(cellId, data.WasLoaded, () => PriorityFunc(worldAABB, parentLod, parentCellId, cell), (c) => DebugDrawJob(c, worldAABB)); data.State = CellState.Pending; return(true); }
private static BoundingBox GetChildrenCoords(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null) { return(BoundingBox.CreateInvalid()); } Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod); var start = thisLodCell.CoordInLod << shiftToChild; var end = start + ((1 << shiftToChild) >> 1); Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); return(new BoundingBox(start, end)); }
/// <summary> /// Checks ancestor nodes recursively. Typically, this checks at most 9 nodes or so (depending on settings). /// </summary> private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell) { if (parentLod == null || !parentLod.m_fitsInFrustum || !parentLod.Visible) { return true; } Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1); var parentCell = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> 1); CellData data; if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data)) { return data.WasLoaded; } LodLevel ancestor; if (parentLod.m_parent.m_lodLevels.TryGetValue(parentLod.m_lodIndex+1, out ancestor)) return WasAncestorCellLoaded(ancestor, ref parentCell); else return false; }
public bool HasLOD(LodLevel level) { switch (level) { case LodLevel.Physics: return(m_MeshData.ContainsKey("physics_mesh")); case LodLevel.LOD0: return(m_MeshData.ContainsKey("lowest_lod")); case LodLevel.LOD1: return(m_MeshData.ContainsKey("low_lod")); case LodLevel.LOD2: return(m_MeshData.ContainsKey("medium_lod")); case LodLevel.LOD3: return(m_MeshData.ContainsKey("high_lod")); default: throw new ArgumentOutOfRangeException(nameof(level)); } }
/// <summary> /// Priority function for sorting render cell precalc jobs /// </summary> /// <param name="cellWorldPos"></param> /// <param name="parent"></param> /// <param name="parentCellId"></param> /// <param name="cell"></param> /// <returns></returns> int PriorityFunc(BoundingBoxD cellWorldPos, LodLevel parent, ulong parentCellId, MyCellCoord cell) { //not using priority now, only physics prefetch is prioritized before graphics return(int.MaxValue); //commented out since now we are not dependent on parent //if (parent != null)//topmost lod does not have parent //{ // //var coordCell = new MyCellCoord(); // //coordCell.SetUnpack(parentCellId); // //if (!AllSiblingsWereLoaded(ref coordCell))//doesnt improve holes and slows progression awfully // // return int.MaxValue; // CellData data; // if (!parent.m_storedCellData.TryGetValue(parentCellId, out data) || !data.WasLoaded) //we need loaded parent for blending lods // return int.MaxValue; //} //var cam = CameraMatrixGetter();//get current cam position ////float mult = m_lodIndex; //var dir = (cellWorldPos.Center - cam.Translation); //direction to camera //var length = dir.Length(); //var dot = (dir/length).Dot(cam.Forward); //dot with look direction //if (cellWorldPos.Contains(cam.Translation) != ContainmentType.Disjoint) //{//we are inside the cell so top priority // length = 1; //} ////commented out since now we are not dependent on parent ////else if (AnySiblingChildrenLoaded(ref cell)) //// mult = 0.1f; //we should speed up since sibling child cannot be rendered without us //length *= 1.5f - dot; //prioritize by view direction //const double intMax = (double)int.MaxValue; //return length > intMax ? (int)intMax : (int)length; }
private void GetNearbyLodLevels(out LodLevel parentLod, out LodLevel childLod) { var levels = m_parent.m_lodLevels; int parentIdx = m_lodIndex + 1; if (levels.IsValidIndex(parentIdx)) parentLod = levels[parentIdx]; else parentLod = null; int childIdx = m_lodIndex - 1; if (levels.IsValidIndex(childIdx)) childLod = levels[childIdx]; else childLod = null; }
private static BoundingBox GetChildrenCoords(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null) return BoundingBox.CreateInvalid(); Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod); var start = thisLodCell.CoordInLod << shiftToChild; var end = start + ((1 << shiftToChild) >> 1); Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); return new VRageMath.BoundingBox(start, end); }
/// <summary> /// Checks only immediate children (any deeper would take too long). /// </summary> private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null) return false; Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod); var start = thisLodCell.CoordInLod << shiftToChild; var end = start + ((1 << shiftToChild) >> 1); Vector3I.Max(ref childLod.m_lodSizeMinusOne, ref Vector3I.Zero, out childLod.m_lodSizeMinusOne); Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); childLodCell.CoordInLod = start; for (var it = new Vector3I_RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out childLodCell.CoordInLod)) { var key = childLodCell.PackId64(); MyClipmap_CellData data; if (!childLod.m_storedCellData.TryGetValue(key, out data) || !data.WasLoaded) { return false; } } return true; }
/// <summary> /// Checks ancestor nodes recursively. /// </summary> private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell) { if (parentLod == null || !parentLod.m_fitsInFrustum) { return true; } Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1); var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(thisLodCell.Lod); var parentCell = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> shiftToParent); MyClipmap_CellData data; if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data)) { return data.WasLoaded; } LodLevel ancestor; if (parentLod.m_clipmap.m_lodLevels.TryGetValue(parentLod.m_lodIndex + 1, out ancestor)) return WasAncestorCellLoaded(ancestor, ref parentCell); else return false; }
private bool TryAddCellRequest(RequestCollector collector, LodLevel parentLod, MyCellCoord cell, ulong cellId, CellData data) { var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod); var parentCell = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell; BoundingBoxD worldAABB; MyVoxelCoordSystems.RenderCellCoordToWorldAABB(m_clipmap.m_worldMatrix.Translation, ref parentCell, out worldAABB); worldAABB.Inflate(-1.0f * m_lodIndex * m_lodIndex); var parentCellId = parentCell.PackId64(); //if (PriorityFunc(worldAABB.Center, parentLod, parentCellId) == int.MaxValue) //this cell would just slow down sorting, it will be added again if needed // return false; collector.AddRequest(cellId, data.WasLoaded, () => PriorityFunc(worldAABB, parentLod, parentCellId, cell), (c) => DebugDrawJob(c, worldAABB)); data.State = CellState.Pending; return true; }
/// <summary> /// Priority function for sorting render cell precalc jobs /// </summary> /// <param name="cellWorldPos"></param> /// <param name="parent"></param> /// <param name="parentCellId"></param> /// <param name="cell"></param> /// <returns></returns> int PriorityFunc(BoundingBoxD cellWorldPos, LodLevel parent, ulong parentCellId, MyCellCoord cell) { //not using priority now, only physics prefetch is prioritized before graphics return int.MaxValue; //commented out since now we are not dependent on parent //if (parent != null)//topmost lod does not have parent //{ // //var coordCell = new MyCellCoord(); // //coordCell.SetUnpack(parentCellId); // //if (!AllSiblingsWereLoaded(ref coordCell))//doesnt improve holes and slows progression awfully // // return int.MaxValue; // CellData data; // if (!parent.m_storedCellData.TryGetValue(parentCellId, out data) || !data.WasLoaded) //we need loaded parent for blending lods // return int.MaxValue; //} //var cam = CameraMatrixGetter();//get current cam position ////float mult = m_lodIndex; //var dir = (cellWorldPos.Center - cam.Translation); //direction to camera //var length = dir.Length(); //var dot = (dir/length).Dot(cam.Forward); //dot with look direction //if (cellWorldPos.Contains(cam.Translation) != ContainmentType.Disjoint) //{//we are inside the cell so top priority // length = 1; //} ////commented out since now we are not dependent on parent ////else if (AnySiblingChildrenLoaded(ref cell)) //// mult = 0.1f; //we should speed up since sibling child cannot be rendered without us //length *= 1.5f - dot; //prioritize by view direction //const double intMax = (double)int.MaxValue; //return length > intMax ? (int)intMax : (int)length; }