public static int DeriveBorderSize(NMGenConfig config) { if (config.TileSize > 0) { return((int)Mathf.Ceil( config.WalkableRadius / config.mRoot.xzCellSize) + 3); } return(0); }
public static void OnGUIButtons(NavmeshBuild build , NMGenConfig config , bool isInspector) { if (!build) { return; } if (build.HasBuildData) { // Not an option if the build is in progress. return; } if (isInspector) { EditorGUILayout.BeginHorizontal(); } if (GUILayout.Button("Clean")) { config.Clean(); config.ApplyDecimalLimits(); GUI.changed = true; } if (GUILayout.Button("Reset")) { config.Reset(); GUI.changed = true; } if (!isInspector) { GUILayout.Space(2 * MarginSize); } if (build.HasInputData) { if (GUILayout.Button("Derive")) { InputGeometry geom = build.InputGeom; config.Derive(geom.BoundsMin, geom.BoundsMax); config.ApplyDecimalLimits(); GUI.changed = true; } } if (isInspector) { EditorGUILayout.EndHorizontal(); } }
/// <summary> /// Duplicates the object. /// </summary> /// <returns>A duplicate of the object.</returns> public NMGenConfig Clone() { NMGenConfig result = new NMGenConfig(); result.mRoot = mRoot; result.mMaxEdgeLength = mMaxEdgeLength; result.mMergeRegionArea = mMergeRegionArea; result.mMinRegionArea = mMinRegionArea; result.mWalkableHeight = mWalkableHeight; result.mWalkableRadius = mWalkableRadius; result.mWalkableStep = mWalkableStep; result.mBuildFlags = mBuildFlags; return(result); }
protected override void OnGUIMain() { NavmeshBuild build = Context.Build; if (!build) { return; } NMGenConfig config = build.Config; GUI.Box(Context.MainArea, ""); Rect colA = Context.MainArea; colA.width = colA.width * 0.5f - 4 * MarginSize; Rect colB = colA; colA.x += MarginSize; colB.x += Context.MainArea.width * 0.5f + MarginSize; GUILayout.BeginArea(colA); OnGUIPrimary(build, config, false); if (GUI.changed) { // Conservative: Just in case the tile size was altered. DebugContext.NeedsRepaint = true; } GUILayout.EndArea(); GUILayout.BeginArea(colB); OnGUIAdvanced(config, false); GUILayout.EndArea(); if (GUI.changed) { build.IsDirty = true; } }
public static int DeriveTileSize( NMGenConfig config , UnityEngine.Vector3 boundsMin , UnityEngine.Vector3 boundsMax) { UnityEngine.Vector3 diff = boundsMax - boundsMin; float maxXZLength = Mathf.Max(diff.x, diff.z); int maxCells = Mathf.CeilToInt(maxXZLength / config.XZCellSize); if (maxCells <= MaxCells) { return(0); } else { return(Mathf.Min(mStandardCells, maxCells / 2)); } }
public static float DeriveDetailSampleDistance( NMGenConfig config , UnityEngine.Vector3 boundsMin , UnityEngine.Vector3 boundsMax) { UnityEngine.Vector3 diff = boundsMax - boundsMin; float maxXZLength = Mathf.Max(diff.x, diff.z); int maxCells = Mathf.CeilToInt(maxXZLength / config.XZCellSize); if (config.TileSize == 0 || maxCells <= MaxCells) { return((float)Math.Round( Mathf.Max(0.9f, maxXZLength / mSampleResolution), 2)); } else { return((float)Math.Round(Mathf.Max(0.9f , config.TileSize * config.XZCellSize / mSampleResolution), 2)); } }
public static void OnGUIAdvanced(NMGenConfig config , bool isInspector) { GUILayout.Label("Advanced Settings"); EditorGUIUtility.LookLikeControls(170); float xz = config.XZCellSize; float a = xz * xz; float effective; ///////////////////////////////////////////////////////////// GUILayout.Space(MarginSize); effective = Mathf.Ceil(config.MaxEdgeLength / xz) * xz; config.MaxEdgeLength = EditorGUILayout.FloatField( NMGenConfig.EdgeLenLabel + Effective(effective) , config.MaxEdgeLength); config.EdgeMaxDeviation = EditorGUILayout.FloatField( NMGenConfig.EdgeDevLabel , config.EdgeMaxDeviation); config.MaxVertsPerPoly = EditorGUILayout.IntSlider( NMGenConfig.MaxPolyVertLabel , config.MaxVertsPerPoly , 3 , NMGen.MaxAllowedVertsPerPoly); effective = Mathf.Ceil(config.MergeRegionArea / a) * a; config.MergeRegionArea = EditorGUILayout.FloatField( NMGenConfig.MergeSizeLabel + Effective(effective) , config.MergeRegionArea); GUILayout.Space(MarginSize * 2); NMGenBuildFlag flags = config.BuildFlags; HandleFlagGUI(ref flags , NMGenConfig.LedgeSpansLabel , NMGenBuildFlag.LedgeSpansNotWalkable , isInspector); HandleFlagGUI(ref flags , NMGenConfig.LowHeightLabel , NMGenBuildFlag.LowHeightSpansNotWalkable , isInspector); HandleFlagGUI(ref flags , NMGenConfig.LowObstacleLabel , NMGenBuildFlag.LowObstaclesWalkable , isInspector); ContourBuildFlags cflags = config.ContourOptions; HandleFlagGUI(ref cflags , NMGenConfig.TessWallsLabel , ContourBuildFlags.TessellateWallEdges , isInspector); HandleFlagGUI(ref cflags , NMGenConfig.TessAreasLabel , ContourBuildFlags.TessellateAreaEdges , isInspector); config.ContourOptions = cflags; if (isInspector) { config.UseMonotone = EditorGUILayout.Toggle(NMGenConfig.UseMonoLabel , config.UseMonotone); } else { config.UseMonotone = GUILayout.Toggle(config.UseMonotone , NMGenConfig.UseMonoLabel); } HandleFlagGUI(ref flags , NMGenConfig.FlagPolysLabel , NMGenBuildFlag.ApplyPolyFlags , isInspector); bool includeDetail; if (isInspector) { includeDetail = EditorGUILayout.Toggle("Include Detail Mesh" , (config.ResultOptions & NMGenAssetFlag.DetailMesh) != 0); } else { includeDetail = GUILayout.Toggle( (config.ResultOptions & NMGenAssetFlag.DetailMesh) != 0 , "Include Detail Mesh"); } if (includeDetail) { config.ResultOptions |= NMGenAssetFlag.DetailMesh; } else { config.ResultOptions &= ~NMGenAssetFlag.DetailMesh; } HandleFlagGUI(ref flags , NMGenConfig.BVTreeLabel , NMGenBuildFlag.BVTreeEnabled , isInspector); config.BuildFlags = flags; }
/// <summary> /// Duplicates the object. /// </summary> /// <returns>A duplicate of the object.</returns> public NMGenConfig Clone() { NMGenConfig result = new NMGenConfig(); result.mRoot = mRoot; result.mMaxEdgeLength = mMaxEdgeLength; result.mMergeRegionArea = mMergeRegionArea; result.mMinRegionArea = mMinRegionArea; result.mWalkableHeight = mWalkableHeight; result.mWalkableRadius = mWalkableRadius; result.mWalkableStep = mWalkableStep; result.mBuildFlags = mBuildFlags; return result; }
public static float DeriveDetailSampleDistance( NMGenConfig config , Vector3 boundsMin , Vector3 boundsMax) { Vector3 diff = boundsMax - boundsMin; float maxXZLength = Mathf.Max(diff.x, diff.z); int maxCells = Mathf.CeilToInt(maxXZLength / config.XZCellSize); if (config.TileSize == 0 || maxCells <= MaxCells) { return (float)Math.Round( Mathf.Max(0.9f, maxXZLength / mSampleResolution), 2); } else return (float)Math.Round(Mathf.Max(0.9f , config.TileSize * config.XZCellSize / mSampleResolution), 2); }
public static float DeriveDetailMaxDeviation(NMGenConfig config) { return (float)Math.Round(config.YCellSize * mDeviationFactor, 2); }
public static void OnGUIButtons(NavmeshBuild build , NMGenConfig config , bool isInspector) { if (!build) return; if (build.HasBuildData) // Not an option if the build is in progress. return; if (isInspector) EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Clean")) { config.Clean(); config.ApplyDecimalLimits(); GUI.changed = true; } if (GUILayout.Button("Reset")) { config.Reset(); GUI.changed = true; } if (!isInspector) GUILayout.Space(2 * MarginSize); if (build.HasInputData) { if (GUILayout.Button("Derive")) { InputGeometry geom = build.InputGeom; config.Derive(geom.BoundsMin, geom.BoundsMax); config.ApplyDecimalLimits(); GUI.changed = true; } } if (isInspector) EditorGUILayout.EndHorizontal(); }
public static void OnGUIAdvanced(NMGenConfig config , bool isInspector) { GUILayout.Label("Advanced Settings"); EditorGUIUtility.LookLikeControls(170); float xz = config.XZCellSize; float a = xz * xz; float effective; ///////////////////////////////////////////////////////////// GUILayout.Space(MarginSize); effective = Mathf.Ceil(config.MaxEdgeLength / xz) * xz; config.MaxEdgeLength = EditorGUILayout.FloatField( NMGenConfig.EdgeLenLabel + Effective(effective) , config.MaxEdgeLength); config.EdgeMaxDeviation = EditorGUILayout.FloatField( NMGenConfig.EdgeDevLabel , config.EdgeMaxDeviation); config.MaxVertsPerPoly = EditorGUILayout.IntSlider( NMGenConfig.MaxPolyVertLabel , config.MaxVertsPerPoly , 3 , NMGen.MaxAllowedVertsPerPoly); effective = Mathf.Ceil(config.MergeRegionArea / a) * a; config.MergeRegionArea = EditorGUILayout.FloatField( NMGenConfig.MergeSizeLabel + Effective(effective) , config.MergeRegionArea); GUILayout.Space(MarginSize * 2); NMGenBuildFlag flags = config.BuildFlags; HandleFlagGUI(ref flags , NMGenConfig.LedgeSpansLabel , NMGenBuildFlag.LedgeSpansNotWalkable , isInspector); HandleFlagGUI(ref flags , NMGenConfig.LowHeightLabel , NMGenBuildFlag.LowHeightSpansNotWalkable , isInspector); HandleFlagGUI(ref flags , NMGenConfig.LowObstacleLabel , NMGenBuildFlag.LowObstaclesWalkable , isInspector); ContourBuildFlags cflags = config.ContourOptions; HandleFlagGUI(ref cflags , NMGenConfig.TessWallsLabel , ContourBuildFlags.TessellateWallEdges , isInspector); HandleFlagGUI(ref cflags , NMGenConfig.TessAreasLabel , ContourBuildFlags.TessellateAreaEdges , isInspector); config.ContourOptions = cflags; if (isInspector) { config.UseMonotone = EditorGUILayout.Toggle(NMGenConfig.UseMonoLabel , config.UseMonotone); } else { config.UseMonotone = GUILayout.Toggle(config.UseMonotone , NMGenConfig.UseMonoLabel); } HandleFlagGUI(ref flags , NMGenConfig.FlagPolysLabel , NMGenBuildFlag.ApplyPolyFlags , isInspector); bool includeDetail; if (isInspector) { includeDetail = EditorGUILayout.Toggle("Include Detail Mesh" , (config.ResultOptions & NMGenAssetFlag.DetailMesh) != 0); } else { includeDetail = GUILayout.Toggle( (config.ResultOptions & NMGenAssetFlag.DetailMesh) != 0 , "Include Detail Mesh"); } if (includeDetail) config.ResultOptions |= NMGenAssetFlag.DetailMesh; else config.ResultOptions &= ~NMGenAssetFlag.DetailMesh; HandleFlagGUI(ref flags , NMGenConfig.BVTreeLabel , NMGenBuildFlag.BVTreeEnabled , isInspector); config.BuildFlags = flags; }
public static void OnGUIPrimary(NavmeshBuild build , NMGenConfig config , bool includeSlope) { if (!build) return; bool guiEnabled = GUI.enabled; EditorGUIUtility.LookLikeControls(155); float xz = config.XZCellSize; float y = config.YCellSize; float a = xz * xz; float effective; ////////////////////////////////////////////////////////////// GUILayout.Label("Agent Settings"); GUILayout.Space(MarginSize); TileBuildData tdata = build.BuildData; GUI.enabled = guiEnabled && (tdata == null); effective = (float)Mathf.Ceil(config.WalkableHeight / y) * y; config.WalkableHeight = EditorGUILayout.FloatField( NMGenConfig.HeightLabel + Effective(effective) , config.WalkableHeight); effective = (float)Mathf.Floor(config.WalkableStep / y) * y; config.WalkableStep = EditorGUILayout.FloatField( NMGenConfig.StepLabel + Effective(effective) , config.WalkableStep); effective = (float)Mathf.Ceil(config.WalkableRadius / xz) * xz; config.WalkableRadius = EditorGUILayout.FloatField( NMGenConfig.RadiusLabel + Effective(effective) , config.WalkableRadius); GUI.enabled = guiEnabled; if (includeSlope) { config.WalkableSlope = EditorGUILayout.FloatField( NMGenConfig.SlopeLabel , config.WalkableSlope); } ///////////////////////////////////////////////////////////////// GUILayout.Space(2 * MarginSize); GUILayout.Label("Resolution and Tile Settings"); GUILayout.Space(MarginSize); GUI.enabled = guiEnabled && (tdata == null); config.XZCellSize = EditorGUILayout.FloatField( NMGenConfig.XZSizeLabel , config.XZCellSize); config.YCellSize = EditorGUILayout.FloatField( NMGenConfig.YSizeLabel , config.YCellSize); config.TileSize = EditorGUILayout.IntField( NMGenConfig.TileSizeLabel + " (" + config.TileSize * config.XZCellSize + ")" , config.TileSize); config.BorderSize = EditorGUILayout.IntField( NMGenConfig.HFBorderLabel , config.BorderSize); GUI.enabled = guiEnabled; int derBorderSize = NMGenConfig.DeriveBorderSize(config); float derXZ = NMGenConfig.DeriveXZCellSize(config); float derY = NMGenConfig.DeriveYCellSize(config); if ((config.TileSize == 0 && config.BorderSize != derBorderSize) || config.BorderSize < derBorderSize || config.XZCellSize > derXZ || config.YCellSize > derY) { GUILayout.Space(MarginSize); System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("Recommendations:"); if (config.XZCellSize > derXZ) sb.AppendLine(NMGenConfig.XZSizeLabel + " of " + derXZ + " or less."); if (config.YCellSize > derY) sb.AppendLine(NMGenConfig.YSizeLabel + " of " + derY + " or less."); if (config.TileSize == 0 && config.BorderSize != derBorderSize) sb.AppendLine("Border Size of " + derBorderSize + "."); else if (config.BorderSize < derBorderSize) sb.AppendLine("Border Size of " + derBorderSize + " or higher."); GUILayout.Box(sb.ToString().Trim(), EditorUtil.HelpStyle, GUILayout.ExpandWidth(true)); } if (build.HasInputData) { InputGeometry geom = build.InputGeom; Vector3 bmin = geom.BoundsMin; Vector3 bmax = geom.BoundsMax; float w = bmax.x - bmin.x; float d = bmax.z - bmin.z; GUILayout.Space(MarginSize); int tw = Mathf.CeilToInt(w / xz); int td = Mathf.CeilToInt(d / xz); GUILayout.Label(string.Format("Cells: {0:N0} ({1:N0} x {2:N0})" , tw * td, tw, td)); if (config.TileSize > 0) { tw = Mathf.Max(1, Mathf.CeilToInt((float)tw / config.TileSize)); td = Mathf.Max(1, Mathf.CeilToInt((float)td / config.TileSize)); } else { tw = 1; td = 1; } GUILayout.Label(string.Format("Tiles: {0:N0} ({1:N0} x {2:N0})" , tw * td, tw, td)); } ///////////////////////////////////////////////////////////////// GUILayout.Space(2 * MarginSize); GUILayout.Label("Miscellaneous Settings"); GUILayout.Space(MarginSize); config.DetailSampleDistance = EditorGUILayout.FloatField( NMGenConfig.DetailSampleLabel , config.DetailSampleDistance); config.DetailMaxDeviation = EditorGUILayout.FloatField( NMGenConfig.DetailDevLabel , config.DetailMaxDeviation); effective = Mathf.Ceil(config.MinRegionArea / a) * a; config.MinRegionArea = EditorGUILayout.FloatField( NMGenConfig.IslandRegionLabel + Effective(effective) , config.MinRegionArea); }
public bool QueueTask(int tx, int tz, int priority, BuildContext logger) { // Check for existing task and purge it. NavmeshBuild build = Build; if (!build) { return(false); } TileBuildData tdata = build.BuildData; if (build.TileSetDefinition == null && (tx > 0 || tz > 0)) { logger.LogError("Tile build requested, but no tile set found.", this); return(false); } if (AbortRequest(tx, tz, "Overriden by new task.")) { tdata.ClearUnbaked(tx, tz); logger.LogWarning(string.Format( "Existing build task overridden by new task. ({0}, {1})" , tx, tz), this); } IncrementalBuilder builder; NMGenConfig config = build.Config; if (build.TileSetDefinition == null) { InputGeometry geom = build.InputGeom; if (geom == null) { logger.LogError("Input geometry not available.", this); tdata.SetAsFailed(tx, tz); return(false); } builder = IncrementalBuilder.Create(config.GetConfig() , config.ResultOptions , geom , build.NMGenProcessors); } else { builder = IncrementalBuilder.Create(tx, tz , config.ResultOptions , build.TileSetDefinition , build.NMGenProcessors); } if (builder == null) { logger.LogError(string.Format("Tile set did not produce a builder. Tile: ({0},{1})" , tx, tz) , this); return(false); } NMGenTask task = NMGenTask.Create(builder, priority); if (!mTaskProcessor.QueueTask(task)) { logger.LogError(string.Format("Processor rejected task. Tile: ({0},{1})" , tx, tz), this); return(false); } mNMGenTasks.Add(task); tdata.SetAsQueued(tx, tz); return(true); }
protected override void OnGUIButtons() { NavmeshBuild build = Context.Build; if (!build) { return; } NMGenConfig config = build.Config; // Buttons area. ControlUtil.BeginButtonArea(Context.ButtonArea); // Standard config buttons. OnGUIButtons(build, config, false); // Build initialialization buttons. bool guiEnabled = GUI.enabled; bool targetOK = build.CanLoadFromTarget(null, false); GUILayout.Space(MarginSize * 2); if (build.BuildState == NavmeshBuildState.Buildable) { GUI.enabled = (Context.TaskCount == 0); if (GUILayout.Button("Reinitialize Builder")) { build.DiscardBuildData(); } } else if (build.HasInputData) { if (targetOK) { if (GUILayout.Button("Load Target's Config")) { if (!build.SetConfigFromTarget(Logger)) { Logger.PostError("Could not load target config.", Context.Build); } Logger.ResetLog(); } GUILayout.Space(MarginSize); GUILayout.Label("Initialize Build:"); GUILayout.Space(MarginSize); if (GUILayout.Button("From Scratch", ControlUtil.HighlightedButton)) { InitializeBuild(false); } if (GUILayout.Button("Based on Target")) { InitializeBuild(true); } GUILayout.Space(MarginSize); GUILayout.Box("Basing your build on the target's navigation" + " mesh will automatically lock you in to the" + " target's configuration settings." , EditorUtil.HelpStyle , GUILayout.ExpandWidth(true)); } else { if (GUILayout.Button("Ready to Build", ControlUtil.HighlightedButton)) { InitializeBuild(false); } } } GUI.enabled = guiEnabled; ViewOption option = build.HasInputData ? (ViewOption.Grid | ViewOption.Input) : 0; DebugContext.SetViews(option); ControlUtil.OnGUIStandardButtons(Context, DebugContext, true); ControlUtil.EndButtonArea(); if (GUI.changed) { build.IsDirty = true; } }
public static float DeriveXZCellSize(NMGenConfig config) { return (float)Math.Round(Mathf.Max(0.05f, config.WalkableRadius / 2), 2); }
public static float DeriveYCellSize(NMGenConfig config) { return (float)Math.Round(Mathf.Max(0.05f, config.WalkableStep / 3), 2); }
public static float DeriveXZCellSize(NMGenConfig config) { return((float)Math.Round(Mathf.Max(0.05f, config.WalkableRadius / 2), 2)); }
public static int DeriveBorderSize(NMGenConfig config) { if (config.TileSize > 0) { return (int)Mathf.Ceil( config.WalkableRadius / config.mRoot.xzCellSize) + 3; } return 0; }
public static float DeriveYCellSize(NMGenConfig config) { return((float)Math.Round(Mathf.Max(0.05f, config.WalkableStep / 3), 2)); }
public static int DeriveTileSize( NMGenConfig config , Vector3 boundsMin , Vector3 boundsMax) { Vector3 diff = boundsMax - boundsMin; float maxXZLength = Mathf.Max(diff.x, diff.z); int maxCells = Mathf.CeilToInt(maxXZLength / config.XZCellSize); if (maxCells <= MaxCells) return 0; else return Mathf.Min(mStandardCells, maxCells / 2); }
public static float DeriveDetailMaxDeviation(NMGenConfig config) { return((float)Math.Round(config.YCellSize * mDeviationFactor, 2)); }
private bool BuildSingleTile() { TileBuildData tdata = mBuild.BuildData; NMGenConfig config = mBuild.Config; InputGeometry geom = mBuild.InputGeom; mContext.ResetLog(); /* * Design note: * * Not using the build task since it doesn't provide enough progress * feedback for a single tile. * */ // Create the NMGen builder. IncrementalBuilder builder = IncrementalBuilder.Create(config.GetConfig() , config.ResultOptions , geom , mBuild.NMGenProcessors); if (builder == null) { mContext.PostError("Unexpected failure creating NMGen builder.", mBuild); tdata.SetAsFailed(0, 0); return(false); } else if (builder.IsFinished) { if (builder.State == NMGenState.NoResult) { mContext.PostError("NMGen build did not produce a result. (Early exit.)" , builder.GetMessages(), mBuild); tdata.SetAsFailed(0, 0); return(false); } else { mContext.PostError("Unexpected NMGen builder completion." , builder.GetMessages(), mBuild); tdata.SetAsFailed(0, 0); return(false); } } mBuild.BuildData.SetAsInProgress(0, 0); // Run the NMGen builder. while (!builder.IsFinished) { if (EditorUtility.DisplayCancelableProgressBar("Build Single Tile Mesh" , IncrementalBuilder.ToLabel(builder.State) , IncrementalBuilder.ToProgress(builder.State))) { return(false); } builder.Build(); } // Handle NMGen failures. mContext.Log(builder.GetMessages()); // Single tile build. So go ahead an record. switch (builder.State) { case NMGenState.Aborted: mContext.PostError("NMGen build failed.", mBuild); tdata.SetAsFailed(0, 0); return(false); case NMGenState.NoResult: mContext.PostError("NMGen build did not produce a result.", mBuild); tdata.SetAsFailed(0, 0); return(false); } mContext.Log(string.Format("Completed NMGen build: {0} polygons." , builder.Result.PolyMesh.PolyCount) , mBuild); // Build the tile. NMGenAssets result = builder.Result; if (result.DetailMesh == null) { Debug.LogError("result.DetailMesh ==null!"); } NavmeshTileBuildData tbd = org.critterai.nmbuild.NMBuild.GetBuildData( mContext, 0, 0 , result.PolyMesh.GetData(false), result.DetailMesh.GetData(false) , mBuild.Connections , (config.BuildFlags & NMGenBuildFlag.BVTreeEnabled) != 0); if (tbd == null) { // No need to log the error. The above method takes care of that. tdata.SetAsFailed(0, 0); return(false); } NavmeshTileData td = NavmeshTileData.Create(tbd); if (td.Size == 0) { mContext.PostError( "Could not create {0} object. Cause unknown." + typeof(NavmeshTileData) , mBuild); tdata.SetAsFailed(0, 0); return(false); } // Finalize the tile. tdata.SetWorkingData(0, 0, result.PolyMesh, result.DetailMesh); tdata.SetWorkingData(0, 0, td, tbd.PolyCount); mContext.PostTrace("Completed single tile build.", mBuild); return(true); }
public static void OnGUIPrimary(NavmeshBuild build , NMGenConfig config , bool includeSlope) { if (!build) { return; } bool guiEnabled = GUI.enabled; EditorGUIUtility.LookLikeControls(155); float xz = config.XZCellSize; float y = config.YCellSize; float a = xz * xz; float effective; ////////////////////////////////////////////////////////////// GUILayout.Label("Agent Settings"); GUILayout.Space(MarginSize); TileBuildData tdata = build.BuildData; GUI.enabled = guiEnabled && (tdata == null); effective = (float)Mathf.Ceil(config.WalkableHeight / y) * y; config.WalkableHeight = EditorGUILayout.FloatField( NMGenConfig.HeightLabel + Effective(effective) , config.WalkableHeight); effective = (float)Mathf.Floor(config.WalkableStep / y) * y; config.WalkableStep = EditorGUILayout.FloatField( NMGenConfig.StepLabel + Effective(effective) , config.WalkableStep); effective = (float)Mathf.Ceil(config.WalkableRadius / xz) * xz; config.WalkableRadius = EditorGUILayout.FloatField( NMGenConfig.RadiusLabel + Effective(effective) , config.WalkableRadius); GUI.enabled = guiEnabled; if (includeSlope) { config.WalkableSlope = EditorGUILayout.FloatField( NMGenConfig.SlopeLabel , config.WalkableSlope); } ///////////////////////////////////////////////////////////////// GUILayout.Space(2 * MarginSize); GUILayout.Label("Resolution and Tile Settings"); GUILayout.Space(MarginSize); GUI.enabled = guiEnabled && (tdata == null); config.XZCellSize = EditorGUILayout.FloatField( NMGenConfig.XZSizeLabel , config.XZCellSize); config.YCellSize = EditorGUILayout.FloatField( NMGenConfig.YSizeLabel , config.YCellSize); config.TileSize = EditorGUILayout.IntField( NMGenConfig.TileSizeLabel + " (" + config.TileSize * config.XZCellSize + ")" , config.TileSize); config.BorderSize = EditorGUILayout.IntField( NMGenConfig.HFBorderLabel , config.BorderSize); GUI.enabled = guiEnabled; int derBorderSize = NMGenConfig.DeriveBorderSize(config); float derXZ = NMGenConfig.DeriveXZCellSize(config); float derY = NMGenConfig.DeriveYCellSize(config); if ((config.TileSize == 0 && config.BorderSize != derBorderSize) || config.BorderSize < derBorderSize || config.XZCellSize > derXZ || config.YCellSize > derY) { GUILayout.Space(MarginSize); System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("Recommendations:"); if (config.XZCellSize > derXZ) { sb.AppendLine(NMGenConfig.XZSizeLabel + " of " + derXZ + " or less."); } if (config.YCellSize > derY) { sb.AppendLine(NMGenConfig.YSizeLabel + " of " + derY + " or less."); } if (config.TileSize == 0 && config.BorderSize != derBorderSize) { sb.AppendLine("Border Size of " + derBorderSize + "."); } else if (config.BorderSize < derBorderSize) { sb.AppendLine("Border Size of " + derBorderSize + " or higher."); } GUILayout.Box(sb.ToString().Trim(), EditorUtil.HelpStyle, GUILayout.ExpandWidth(true)); } if (build.HasInputData) { InputGeometry geom = build.InputGeom; Vector3 bmin = geom.BoundsMin; Vector3 bmax = geom.BoundsMax; float w = bmax.x - bmin.x; float d = bmax.z - bmin.z; GUILayout.Space(MarginSize); int tw = Mathf.CeilToInt(w / xz); int td = Mathf.CeilToInt(d / xz); GUILayout.Label(string.Format("Cells: {0:N0} ({1:N0} x {2:N0})" , tw * td, tw, td)); if (config.TileSize > 0) { tw = Mathf.Max(1, Mathf.CeilToInt((float)tw / config.TileSize)); td = Mathf.Max(1, Mathf.CeilToInt((float)td / config.TileSize)); } else { tw = 1; td = 1; } GUILayout.Label(string.Format("Tiles: {0:N0} ({1:N0} x {2:N0})" , tw * td, tw, td)); } ///////////////////////////////////////////////////////////////// GUILayout.Space(2 * MarginSize); GUILayout.Label("Miscellaneous Settings"); GUILayout.Space(MarginSize); config.DetailSampleDistance = EditorGUILayout.FloatField( NMGenConfig.DetailSampleLabel , config.DetailSampleDistance); config.DetailMaxDeviation = EditorGUILayout.FloatField( NMGenConfig.DetailDevLabel , config.DetailMaxDeviation); effective = Mathf.Ceil(config.MinRegionArea / a) * a; config.MinRegionArea = EditorGUILayout.FloatField( NMGenConfig.IslandRegionLabel + Effective(effective) , config.MinRegionArea); }