/// <summary> /// Writes <paramref name="offset"/> to <paramref name="terrain"/> height data. /// </summary> /// <param name="terrainData">Terrain to modify.</param> /// <param name="offset">Height offset.</param> private static TerrainUtils.NativeHeights WriteTerrainDataOffset(Terrain terrain, float offset) { var terrainData = terrain.terrainData; var nativeHeightData = TerrainUtils.FindHeights(terrainData); var tmp = new float[, ] { { 0.0f } }; for (int i = 0; i < nativeHeightData.Heights.Count; ++i) { var newHeight = nativeHeightData.Heights[i] += offset; var vertexX = i % nativeHeightData.ResolutionX; var vertexY = i / nativeHeightData.ResolutionY; tmp[0, 0] = (float)newHeight / terrainData.heightmapScale.y; terrainData.SetHeightsDelayLOD(TerrainUtils.TerrainDataResolution(terrainData) - vertexX - 1, TerrainUtils.TerrainDataResolution(terrainData) - vertexY - 1, tmp); } #if UNITY_2019_1_OR_NEWER terrainData.SyncHeightmap(); #else terrain.ApplyDelayedHeightmapModification(); #endif return(nativeHeightData); }
public bool FindAllTreeInstancesAroundPosition(Vector3 worldPosition, float selectionRange, Terrain terrain, ref List <TreeNode> nodes, bool clear = true) { if (clear) { nodes.Clear(); } TerrainUtils.WorldPositionToTerrain(worldPosition, terrain, out var belongsToTile); if (!belongsToTile) { return(false); } var treeData = _terrainToTreeData[terrain]; var quadTree = treeData.QuadTree; var rect = new Rect(worldPosition.x, worldPosition.z, selectionRange, selectionRange); quadTree.RetrieveObjectsInAreaNoAlloc(rect, ref nodes); if (!nodes.Any()) { Debug.Log("No nodes found in area"); return(false); } return(true); }
public void GenerateTreePrototypeData() { List <string> prefabNames = new List <string>(); List <GameObject> prefabs = new List <GameObject>(); System.Array.ForEach(m_ItemsToExtract, (x) => { prefabNames.Add(x.m_ItemPrefab.name); prefabs.Add(x.m_ItemPrefab); }); if (TerrainUtils.TreeHashCheck(prefabNames.ToArray())) { Debug.LogError("Tree name hash collision, fix!"); return; } GameObject[] proto = prefabs.ToArray(); List <TreeSystemPrototypeData> managed = new List <TreeSystemPrototypeData>(); for (int i = 0; i < proto.Length; i++) { GameObject prefab = proto[i]; if (PrefabUtility.GetPrefabType(prefab) != PrefabType.ModelPrefab || prefab.GetComponent <LODGroup>() == null || prefab.GetComponentInChildren <BillboardRenderer>() == null) { Debug.LogError("Invalid prefab: " + prefab.name + ". Make sure that it is a SpeedTree, that it contains a 'LODGroup' and that it has a 'BillboardRenderer' component."); continue; } TreeSystemPrototypeData data = new TreeSystemPrototypeData(); data.m_TreePrototype = prefab; // Use hash here instead of the old index data.m_TreePrototypeHash = TUtils.GetStableHashCode(prefab.name); // Instantiate LOD data that is going to be populated at runtime LOD[] lods = prefab.GetComponent <LODGroup>().GetLODs(); TreeSystemLODData[] lodData = new TreeSystemLODData[lods.Length]; // Generate some partial LOD data that doesn't have to be calculated at runtime data.m_LODData = lodData; for (int lod = 0; lod < lodData.Length; lod++) { TreeSystemLODData d = new TreeSystemLODData(); lodData[lod] = d; } data.m_MaxLod3DIndex = lodData.Length - 2; managed.Add(data); } m_ManagedPrototypes = managed.ToArray(); // Try and set the prototypes to our tree system TreeSystem t = FindObjectOfType <TreeSystem>(); if (t) { t.m_ManagedPrototypes = m_ManagedPrototypes; } }
/** * Parse file and render buildings when scene starts */ private void Start() { Caching.ClearCache(); //hide and lock cursor into center UiUtils.HideCursor(); TutorialUtils.InitTutorial(TutorialCanvas, Settings); BuildingPickerCanvas.SetActive(false); ExitCanvasDialog.SetActive(false); //load XML file tags var xmlFile = new XmlDocument(); //load file xmlFile.Load(FileUtils.GetFullMapPath(Map.MapName)); //get node and way tags var nodeTags = xmlFile.SelectNodes(".//node"); var wayTags = xmlFile.SelectNodes(".//way"); //cache IDs in node tag for coordinate pairing var nodeTagIds = CacheNodeTagIds(nodeTags); //parse building and roads var buildings = BuildingLoader.Get().LoadFile(nodeTags, nodeTagIds, wayTags); var roads = RoadLoader.Get().LoadFile(nodeTags, nodeTagIds, wayTags); var trees = TreeLoader.Get().LoadFile(); var mapMiddlePoint = GetMiddlePoint(buildings, roads); //download elevation data AltitudeLoader.Get().SetAltitude(TerrainUtils.GetLatLngGrid(mapMiddlePoint)); //render terrain, buildings, roads etc. StartCoroutine(RenderObjects(mapMiddlePoint, buildings, roads, trees)); }
private void Start() { switch (MenuManager.terrainType) { case TerrainType.PERMEAVEL: range = 20; riverHeightCountMax = 4.0f; break; case TerrainType.SEMI_PERMEAVEL: range = 35; riverHeightCountMax = 8.0f; break; case TerrainType.IMPERMEAVEL: range = 50; riverHeightCountMax = 16.0f; break; } minPosition = river.position.y; maxPosition = river.position.y + range; TerrainUtils terrainUtils = new TerrainUtils(terrain.terrainData); terrainUtils.SetTerrainTexture(MenuManager.terrainType); }
private int DecideWallVarient(int x, int y) { Terrain[,] locality = new Terrain[3, 3]; for (int j = x - 1; j <= x + 1; j++) { for (int k = y - 1; k <= y + 1; k++) { if (Util.WithinArrayBounds2D(ref Locations, j, k)) { locality[j - (x - 1), k - (y - 1)] = Locations[j, k].terrain; } else { locality[j - (x - 1), k - (y - 1)] = Terrain.Empty; } } } for (int i = 0; i < Constants.WALL_VARIENTS_MAPPING.GetLength(0); i++) { if (TerrainUtils.EqualArrays2D(locality, Util.Get2DFrom3D(Constants.WALL_VARIENTS_MAPPING, i))) { return(i); } } return(0); }
public void Generate() { UnityEngine.Random.InitState(Seed); //pick a random position for the feature(s) var position = this.Generator.GetRandomPointInChunk(); float sampleheight = ParentChunk.Terrain.terrainData.GetHeight(position.X, position.Z); Vector3 worldPosition = new Vector3( (ChunkCoords.X * TerrainChunkSettings.ChunkSize) + position.X, sampleheight - 0.5f, (ChunkCoords.Z * TerrainChunkSettings.ChunkSize) + position.Z ); var randomRotation = Quaternion.Euler(0, UnityEngine.Random.Range(0, 360), 0); GameObject dungeontower = (GameObject)Resources.Load("DungeonTower"); var spawntower = Instantiate(dungeontower, worldPosition, randomRotation); Generator.FeatureAssets.Add( spawntower ); //setting the seed for the dungeon in the tower we just placed DungeonEntranceTrigger enterancetrigger = spawntower.gameObject.transform.GetComponentInChildren <DungeonEntranceTrigger>(); enterancetrigger.Seed = ChunkCoords.X * ChunkCoords.Z + 123456; //raycasting the tower to the ground level float distanceToGround = TerrainUtils.RaycastToTerrain(spawntower.transform.position); var pos = spawntower.transform.position; pos = new Vector3(pos.x, (pos.y + distanceToGround), pos.z); spawntower.transform.position = pos; spawntower.transform.SetParent(this.transform); RemoveOverlappingAssets(); }
public void GenerateTrees() { if (m_ManagedTerrains.Length != m_CellSizes.Length) { Debug.LogError("Invalid cell sizes for the count of managed terrains!"); return; } for (int i = 0; i < m_ManagedTerrains.Length; i++) { Terrain t = m_ManagedTerrains[i]; if (t.transform.rotation != Quaternion.identity) { Debug.LogError("Terrains must not be rotated, sorry!"); return; } if (TerrainUtils.CanGridify(t, m_CellSizes[i]) == false) { Debug.LogError("Can't gridify terrain [" + t + "] with cell size: " + m_CellSizes[i]); return; } } List <TreeSystemTerrain> systemTerrains = new List <TreeSystemTerrain>(); // Set the cell holder in the origin and mark it static if (!m_CellHolder) { m_CellHolder = new GameObject("TreeSystemCellHolder"); } m_CellHolder.transform.position = Vector3.zero; m_CellHolder.transform.localScale = Vector3.one; m_CellHolder.transform.rotation = Quaternion.identity; m_CellHolder.isStatic = true; for (int i = 0; i < m_ManagedTerrains.Length; i++) { GameObject cellHolder = new GameObject(); cellHolder.isStatic = true; cellHolder.name = m_ManagedTerrains[i].name + "_TreeSystem_Managed_" + i; // Destroy any previous data if (m_CellHolder.transform.Find(cellHolder.name)) { DestroyImmediate(m_CellHolder.transform.Find(cellHolder.name).gameObject); } // Set parent cellHolder.transform.parent = m_CellHolder.transform; systemTerrains.Add(ProcessTerrain(m_ManagedTerrains[i], m_CellSizes[i], cellHolder)); } // TODO: implement a scriptable object maybe? But it works fine with 250k trees so... FindObjectOfType <TreeSystem>().m_ManagedTerrains = systemTerrains.ToArray(); }
public List <WorldPos> OccupiedBlocks() { List <WorldPos> pos = new List <WorldPos>(); pos.Add(TerrainUtils.GetBlockPos(_playerRayOrigin)); pos.Add(new WorldPos(pos[0].x, pos[0].y - 1)); return(pos); }
public int FindTreeInstanceThroughBVH(Vector3 worldPosition, out Terrain ownerTerrain, out TreeNode node) { node = null; ownerTerrain = null; foreach (var pair in _terrainToTreeData) { var terrain = pair.Key; var local = TerrainUtils.WorldPositionToTerrain(worldPosition, terrain, out bool belongsToTile); if (!belongsToTile) { continue; } ownerTerrain = terrain; var quadTree = pair.Value.QuadTree; var rect = new Rect(worldPosition.x, worldPosition.z, SelectionRange, SelectionRange); var nodes = quadTree.RetrieveObjectsInArea(rect); _lastCheckedPosition = worldPosition; if (!nodes.Any()) { Debug.Log("Found no tree nodes around the specified area through BVH check"); return(-1); } if (nodes.Count == 1) { node = nodes[0]; Debug.Log($"Found exactly one tree node around the specified area through BVH check. Index: {node.TreeIndex}"); return(nodes[0].TreeIndex); } else { Debug.Log($"Found multiple tree nodes around the specified area through BVH check. Count: {nodes.Count}"); var twoDimWorldPos = new Vector2(worldPosition.x, worldPosition.z); float minDist = Single.MaxValue; foreach (var treeNode in nodes) { var squaredDistance = (twoDimWorldPos - treeNode.Position).SqrMagnitude(); if (squaredDistance >= minDist) { node = treeNode; minDist = squaredDistance; } } return(-1); } } return(-1); }
void Awake() { if (GameObject.Find("Terrain")) terrainUtils = GameObject.Find ("Terrain").GetComponent<TerrainUtils>(); selector = gameObject.AddComponent<Selector>(); input = gameObject.AddComponent<InputController>(); time = gameObject.AddComponent<TimeController>(); commanderSkin = Resources.Load("CommanderGUI") as GUISkin; }
private void GenerateHeightmapThread() { BiomeType[] impactors = new BiomeType[2]; //Out to BIOME_SAMPLES int offsetX = this.Position.X * (Settings.HeightmapResolution); int offsetZ = this.Position.Z * (Settings.HeightmapResolution); Heightmap = new float[Settings.HeightmapResolution, Settings.HeightmapResolution]; lock (HeightmapThreadLockObject) { ChunkBlend = WorldGenerator.ChunkBlendProvider; impactors = WorldGenerator.GetChunkBiomes(Position); this.Biomes.AddRange(impactors); //Debug.Log("Chunk " + this.Position.X + ", " + this.Position.Z + ":: " + impactors[0] + ", " + impactors[1]); var biomeA = GetBiomeNoiseProvider(impactors[0]); var biomeB = GetBiomeNoiseProvider(impactors[1]); var SelectModule = new Select(biomeA, biomeB, this.ChunkBlend.Provider); SelectModule.FallOff = 0.125f; SelectModule.SetBounds(0, 0.3); var heightmap = new float[Settings.HeightmapResolution, Settings.HeightmapResolution]; for (var zRes = 0; zRes < Settings.HeightmapResolution; zRes++) { for (var xRes = 0; xRes < Settings.HeightmapResolution; xRes++) { var xCoordinate = Position.X + (float)xRes / (Settings.HeightmapResolution - 1); var zCoordinate = Position.Z + (float)zRes / (Settings.HeightmapResolution - 1); heightmap[zRes, xRes] = (float)SelectModule.GetValue(xCoordinate, 0, zCoordinate) / 2f + 0.5f; } } //if this chunk is a world edge, we need to mask it to blend with the ocean if (this.EdgeType != ChunkEdge.NotEdge) { Debug.Log("[" + Position.X + "," + Position.Z + "] is a " + this.EdgeType + " edge so will mask."); //interpolation causes seams, we fix that here: float[,] mask = TerrainUtils.GetEdgeMask(this.EdgeType); for (int x = 0; x < TerrainChunkSettings.ChunkSize; x++) { for (int z = 0; z < TerrainChunkSettings.ChunkSize; z++) { heightmap[x, z] *= mask[x, z]; } } } Heightmap = heightmap; } this.HeightmapReady = true; }
public void PrintPossibleCellCounts() { Debug.Log("------------------------------------"); foreach (TerrainExtract t in m_ManagedTerrains) { Debug.Log("---- BEGIN TERRAIN INFO ----"); TerrainUtils.CellInfo(t.m_ManagedTerrain); Debug.Log("---- END TERRAIN INFO ----"); } Debug.Log("------------------------------------"); }
public int FindTreeInstanceInTerrain(Vector3 worldPosition, Terrain terrain, out TreeNode node) { node = null; TerrainUtils.WorldPositionToTerrain(worldPosition, terrain, out var belongsToTile); if (!belongsToTile) { return(-1); } var treeData = _terrainToTreeData[terrain]; var quadTree = treeData.QuadTree; var rect = new Rect(worldPosition.x, worldPosition.z, SelectionRange, SelectionRange); var nodes = quadTree.RetrieveObjectsInArea(rect); _lastCheckedPosition = worldPosition; if (!nodes.Any()) { Debug.Log("Found no tree nodes around the specified area through BVH check"); return(-1); } if (nodes.Count == 1) { node = nodes[0]; Debug.Log($"Found exactly one tree node around the specified area through BVH check. Index: {node.TreeIndex}"); return(nodes[0].TreeIndex); } else { Debug.Log($"Found multiple tree nodes around the specified area through BVH check. Count: {nodes.Count}"); // TODO find the closest through raw distance and return it var twoDimWorldPos = new Vector2(worldPosition.x, worldPosition.z); float minDist = Single.MaxValue; foreach (var treeNode in nodes) { var squaredDistance = (twoDimWorldPos - treeNode.Position).SqrMagnitude(); if (squaredDistance >= minDist) { node = treeNode; minDist = squaredDistance; } } return(-1); } }
public void Cut(CutEntry cutEntry, bool cutDetails) { if (cutEntry.RemoveDetailsOnly == 0) { transparencyMap.SetPixel(cutEntry.X, cutEntry.Z, Color.clear); } if (cutDetails) { var tData = digger.Terrain.terrainData; var detailMapPos = TerrainUtils.AlphamapPositionToDetailMapPosition(tData, cutEntry.X, cutEntry.Z); CutDetailMaps(tData, detailMapPos.y, detailMapPos.x); } }
public void PlaceTreeUnderCursor(Vector3 worldPosition, Terrain terrain) { if (terrain == null) { Debug.LogError("Tried to place a tree but the terrain was null"); return; } var localSpace = TerrainUtils.WorldPositionToTerrain(worldPosition, terrain, out var belongsToTile); var normalizedLocalSpace = localSpace / (terrain.terrainData.heightmapResolution - TerrainUtils.UnityTextureBorder); var treeInstance = new TreeInstance(); treeInstance.position = normalizedLocalSpace; treeInstance.color = Color.green; treeInstance.lightmapColor = Color.green; treeInstance.prototypeIndex = IndexOfLivePrototype; treeInstance.heightScale = 1; treeInstance.rotation = 1; treeInstance.widthScale = 1; var treeInstancesCopy = terrain.terrainData.treeInstances.ToArray(); var length = treeInstancesCopy.Length; Array.Resize(ref treeInstancesCopy, length + 1); treeInstancesCopy[length] = treeInstance; terrain.terrainData.SetTreeInstances(treeInstancesCopy, false); var treeData = _terrainToTreeData[terrain]; var treeNode = new TreeNode() { Position = new Vector2(worldPosition.x, worldPosition.z), TreeIndex = length, TreeType = (byte)IndexOfLivePrototype }; var quadTree = treeData.QuadTree; quadTree.Insert(treeNode); var handler = treeData.Handler; handler.MarkTreeLive(terrain.terrainData.GetTreeInstance(length)); terrain.Flush(); }
void Awake() { weightedSpawnables = new WeightedList <Spawnable>(); foreach (Spawnable s in Spawnables) { weightedSpawnables.Add(s, s.weight); } WorldContainer = new GameObject("WorldContainer"); WorldContainer.transform.parent = transform; Terrain = GetComponentInChildren <Terrain>(); bounds = TerrainUtils.GetTerrainBounds(Terrain); positions = new List <ObjectLocation>(); }
public void PrintPossibleCellCounts() { Log.d("------------------------------------"); Log.d("---- BEGIN MAIN TERRAIN INFO ----"); TerrainUtils.CellInfo(m_MainManagedTerrain); Log.d("---- END MAIN TERRAIN INFO ----"); foreach (Terrain t in m_ManagedTerrains) { Log.d("---- BEGIN TERRAIN INFO ----"); TerrainUtils.CellInfo(t); Log.d("---- END TERRAIN INFO ----"); } Log.d("------------------------------------"); }
/// <summary> /// Writes <paramref name="offset"/> to <paramref name="terrain"/> height data. /// </summary> /// <param name="terrainData">Terrain to modify.</param> /// <param name="offset">Height offset.</param> private static TerrainUtils.NativeHeights WriteTerrainDataOffset(Terrain terrain, float offset) { var terrainData = terrain.terrainData; var nativeHeightData = TerrainUtils.FindHeights(terrainData); var tmp = new float[, ] { { 0.0f } }; var dataMaxHeight = terrainData.size.y; var maxClampedHeight = -1.0f; for (int i = 0; i < nativeHeightData.Heights.Count; ++i) { var newHeight = nativeHeightData.Heights[i] += offset; var vertexX = i % nativeHeightData.ResolutionX; var vertexY = i / nativeHeightData.ResolutionY; tmp[0, 0] = (float)newHeight / terrainData.heightmapScale.y; if (newHeight > dataMaxHeight) { maxClampedHeight = System.Math.Max(maxClampedHeight, (float)newHeight); } terrainData.SetHeightsDelayLOD(TerrainUtils.TerrainDataResolution(terrainData) - vertexX - 1, TerrainUtils.TerrainDataResolution(terrainData) - vertexY - 1, tmp); } if (maxClampedHeight > 0.0f) { Debug.LogWarning("Terrain heights were clamped: UnityEngine.TerrainData max height = " + dataMaxHeight + " and AGXUnity.Model.DeformableTerrain.MaximumDepth = " + offset + ". Resolve this by increasing max height and lower the terrain or decrease Maximum Depth.", terrain); } #if UNITY_2019_1_OR_NEWER terrainData.SyncHeightmap(); #else terrain.ApplyDelayedHeightmapModification(); #endif return(nativeHeightData); }
public override void OnInspectorGUI() { TerrainUtils utils = (TerrainUtils)target; serializedObject.Update(); if (utils == null) { return; } lineStartProp.vector3Value = EditorGUILayout.Vector3Field("LineStartPos", lineStartProp.vector3Value); lineEndProp.vector3Value = EditorGUILayout.Vector3Field("LineEndPos", lineEndProp.vector3Value); lineWidthProp.floatValue = EditorGUILayout.FloatField("Line Width", lineWidthProp.floatValue); if (EditorGUILayout.ToggleLeft("Paint Line", false)) { utils.PaintLine(); } serializedObject.ApplyModifiedProperties(); }
private void SmoothWorld(ref Terrain[,] world) { Terrain[,] newWorld = (Terrain[, ])world.Clone(); for (int x = 1; x < world.GetLength(0) - 1; x++) { for (int y = 1; y < world.GetLength(1) - 1; y++) { if (TerrainUtils.CountLocalTerrain(ref world, Terrain.Wall, x, y) >= 5) { newWorld[x, y] = Terrain.Wall; } else { newWorld[x, y] = Terrain.Floor; } } } world = newWorld; }
/// <summary> /// Creates native height field object given current Unity Terrain /// object - if present (in component level or in parents). /// </summary> /// <returns>Native height field shape object.</returns> protected override agxCollide.Shape CreateNative() { var terrainData = TerrainData; if (terrainData == null) { return(null); } var heights = TerrainUtils.FindHeights(terrainData); var hf = new agxCollide.HeightField((uint)heights.ResolutionX, (uint)heights.ResolutionY, GetWidth(), GetHeight(), heights.Heights, false, 150.0); return(hf); }
private void Update() { // Block Interaction Plane playerPlane = new Plane(Vector3.back, transform.position); _playerRayOrigin = new Vector3(transform.position.x, transform.position.y + 0.4f, transform.position.z); Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit2D hit; float d; if (playerPlane.Raycast(mouseRay, out d)) { Vector3 hitPoint = mouseRay.GetPoint(d); if (Input.GetMouseButtonDown(0)) { hit = Physics2D.Raycast(_playerRayOrigin, (hitPoint - _playerRayOrigin).normalized, 100, RaycastMask); Debug.Log(hit.collider.name); if (hit.collider != null) { TerrainUtils.SetBlock(hit, new BlockAir()); } } if (Input.GetMouseButtonDown(1)) { hit = Physics2D.Raycast(_playerRayOrigin, (hitPoint - _playerRayOrigin).normalized, 100, RaycastMask); if (hit.collider != null) { TerrainUtils.SetBlock(hit, new Block(), true); } } Debug.DrawRay(_playerRayOrigin, (hitPoint - _playerRayOrigin).normalized, Color.red); } Debug.DrawRay(Camera.main.transform.position, mouseRay.direction, Color.yellow); }
/// <summary> /// Invoked when the tool will be updated /// </summary> protected override void OnToolUpdate() { base.OnToolUpdate(); m_mouseTerrainPosition = TerrainUtils.GetTerrainMousePosition(); // Checks if mouse is over UI if (!m_mouseHoverOptionPanel && !m_mouseHoverScrollablePanel && !m_mouseHoverToolbar) { m_action?.OnUpdate(m_mouseTerrainPosition.Value); if (Input.GetMouseButtonDown(0)) { m_action?.OnLeftMouseIsDown(m_mouseTerrainPosition.Value); } else if (Input.GetMouseButton(0)) { m_action?.OnLeftMouseIsPressed(m_mouseTerrainPosition.Value); } else if (Input.GetMouseButtonUp(0)) { m_action?.OnLeftMouseIsUp(m_mouseTerrainPosition.Value); } if (Input.GetMouseButtonDown(1)) { m_action?.OnRightMouseIsDown(m_mouseTerrainPosition.Value); } else if (Input.GetMouseButton(1)) { m_action?.OnRightMouseIsPressed(m_mouseTerrainPosition.Value); } else if (Input.GetMouseButtonUp(1)) { m_action?.OnRightMouseIsUp(m_mouseTerrainPosition.Value); } } }
public void GlobalGenerateTrees(int count = 10000) { for (var index = _terrainToTreeData.Count - 1; index >= 0; index--) { var dataPair = _terrainToTreeData.ElementAt(index); var terrain = dataPair.Key; var treeData = dataPair.Value; var handler = treeData.Handler; var quadTree = treeData.QuadTree; quadTree.Clear(); TerrainUtils.MassPlaceTreesOfPrototype(terrain.terrainData, count, IndexOfLivePrototype, Color.green); terrain.Flush(); var regenTreeData = PrepareTerrainTreeData(terrain); regenTreeData.Handler = handler; _terrainToTreeData[terrain] = regenTreeData; _handlersToTreeData[handler] = regenTreeData; handler.ReInit(regenTreeData); } }
public void Execute(int i) { results[i] = TerrainUtils.TerrainVectorBarycentric(positions[i], nativeHeightmap, -size / 2f, -size / 2f, 0f, size, maxHeight, res).y; }
void HeightsTest() { Unity.Mathematics.Random r = new Unity.Mathematics.Random(seed); float3[] positions = new float3[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { positions[i] = (new Vector3(r.NextFloat(-size / 2f, size / 2f), 0f, r.NextFloat(-size / 2f, size / 2f))); } NativeArray <float> nativeHeightmap = TerrainUtils.ManagedToNativeHeightmap(heightmap); NativeArray <float3> nativePositions = new NativeArray <float3>(positions, Allocator.Persistent); NativeArray <float> yBarycentricJob = new NativeArray <float>(numberOfPoints, Allocator.Persistent); NativeArray <float> steepnessJob = new NativeArray <float>(numberOfPoints, Allocator.Persistent); float[] yUnity = new float[numberOfPoints]; float[] yBilinear = new float[numberOfPoints]; float[] yInlined = new float[numberOfPoints]; float[] yNativeArray = new float[numberOfPoints]; float[] yBarycentric = new float[numberOfPoints]; float[] steepnessUnity = new float[numberOfPoints]; // Unity; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < numberOfPoints; i++) { yUnity[i] = TerrainUtils.TerrainVectorUnity(positions[i], terrain).y; } double tUnity = stopwatch.Elapsed.TotalMilliseconds; // Bilinear; for (int i = 0; i < numberOfPoints; i++) { yBilinear[i] = TerrainUtils.TerrainVectorBilinear(positions[i], heightmap, -size / 2f, -size / 2f, 0f, size, maxHeight, resolution).y; } double tBilinear = stopwatch.Elapsed.TotalMilliseconds; // Inlined; for (int i = 0; i < numberOfPoints; i++) { yInlined[i] = TerrainUtils.TerrainVectorInlined(positions[i], heightmap, -size / 2f, -size / 2f, 0f, size, maxHeight, resolution).y; } double tInlined = stopwatch.Elapsed.TotalMilliseconds; // Native array; for (int i = 0; i < numberOfPoints; i++) { yNativeArray[i] = TerrainUtils.TerrainVectorNativeArray(positions[i], nativeHeightmap, -size / 2f, -size / 2f, 0f, size, maxHeight, resolution).y; } double tNativeArray = stopwatch.Elapsed.TotalMilliseconds; // Native array; for (int i = 0; i < numberOfPoints; i++) { yBarycentric[i] = TerrainUtils.TerrainVectorBarycentric(positions[i], nativeHeightmap, -size / 2f, -size / 2f, 0f, size, maxHeight, resolution).y; } double tBarycentric = stopwatch.Elapsed.TotalMilliseconds; TerrainVectorBarycentricJob terrainVectorBarycentricJob = new TerrainVectorBarycentricJob { positions = nativePositions, nativeHeightmap = nativeHeightmap, size = size, maxHeight = maxHeight, res = resolution, results = yBarycentricJob }; terrainVectorBarycentricJob.Schedule(numberOfPoints, System.Environment.ProcessorCount).Complete(); double tBarycentricJob = stopwatch.Elapsed.TotalMilliseconds; // Steepness Unity for (int i = 0; i < numberOfPoints; i++) { steepnessUnity[i] = TerrainUtils.TerrainSteepnessUnity(terrainData, positions[i], terrain.transform.position); } double tSteepnessUnity = stopwatch.Elapsed.TotalMilliseconds; // Steepness manual TerrainSteepnessJob terrainSteepnessJob = new TerrainSteepnessJob { positions = nativePositions, nativeHeightmap = nativeHeightmap, size = size, maxHeight = maxHeight, res = resolution, results = steepnessJob }; terrainSteepnessJob.Schedule(numberOfPoints, System.Environment.ProcessorCount).Complete(); double tSteepnessJob = stopwatch.Elapsed.TotalMilliseconds; float maxDiffBilinear = 0f; float maxDiffInlined = 0f; float maxDiffNativeArray = 0f; float maxDiffBarycentric = 0f; float maxDiffBarycentricJob = 0f; float maxDiffSteepnessJob = 0f; float maxDiffBilinearFrac = 0f; float maxDiffInlinedFrac = 0f; float maxDiffNativeArrayFrac = 0f; float maxDiffBarycentricFrac = 0f; float maxDiffBarycentricJobFrac = 0f; float maxDiffSteepnessJobFrac = 0f; for (int i = 0; i < numberOfPoints; i++) { maxDiffBilinear = math.max(maxDiffBilinear, math.abs(yBilinear[i] - yUnity[i])); maxDiffInlined = math.max(maxDiffInlined, math.abs(yInlined[i] - yUnity[i])); maxDiffNativeArray = math.max(maxDiffNativeArray, math.abs(yNativeArray[i] - yUnity[i])); maxDiffBarycentric = math.max(maxDiffBarycentric, math.abs(yBarycentric[i] - yUnity[i])); maxDiffBarycentricJob = math.max(maxDiffBarycentricJob, math.abs(yBarycentricJob[i] - yUnity[i])); maxDiffSteepnessJob = math.max(maxDiffSteepnessJob, math.abs(steepnessJob[i] - steepnessUnity[i])); maxDiffBilinearFrac = math.max(maxDiffBilinearFrac, math.abs(yBilinear[i] - yUnity[i]) / yUnity[i]); maxDiffInlinedFrac = math.max(maxDiffInlinedFrac, math.abs(yInlined[i] - yUnity[i]) / yUnity[i]); maxDiffNativeArrayFrac = math.max(maxDiffNativeArrayFrac, math.abs(yNativeArray[i] - yUnity[i]) / yUnity[i]); maxDiffBarycentricFrac = math.max(maxDiffBarycentricFrac, math.abs(yBarycentric[i] - yUnity[i]) / yUnity[i]); maxDiffBarycentricJobFrac = math.max(maxDiffBarycentricJobFrac, math.abs(yBarycentric[i] - yUnity[i]) / yUnity[i]); maxDiffSteepnessJobFrac = math.max(maxDiffSteepnessJobFrac, math.abs(steepnessJob[i] - steepnessUnity[i]) / 90f); } UnityEngine.Debug.Log($"Setup : resolution={resolution} size={size} maxHeight={maxHeight} numberOfPoints={numberOfPoints} noiseSize={noiseSize}"); UnityEngine.Debug.Log($"Unity : dt={tUnity}ms"); UnityEngine.Debug.Log($"Bilinear : diff={maxDiffBilinear} frac={maxDiffBilinearFrac * 100f}% dt={tBilinear - tUnity}ms"); UnityEngine.Debug.Log($"Inlined : diff={maxDiffInlined} frac={maxDiffInlinedFrac * 100f}% dt={tInlined - tBilinear}ms"); UnityEngine.Debug.Log($"NativeArray : diff={maxDiffNativeArray} frac={maxDiffNativeArrayFrac * 100f}% dt={tNativeArray - tInlined}ms"); UnityEngine.Debug.Log($"Barycentric : diff={maxDiffBarycentric} frac={maxDiffBarycentricFrac * 100f}% dt={tBarycentric - tNativeArray}ms"); UnityEngine.Debug.Log($"Barycentric Job : diff={maxDiffBarycentricJob} frac={maxDiffBarycentricJobFrac * 100f}% dt={tBarycentricJob - tBarycentric}ms"); UnityEngine.Debug.Log($"Steepness Unity : dt={tSteepnessUnity - tBarycentricJob}ms"); UnityEngine.Debug.Log($"Steepness Job : diff={maxDiffSteepnessJob} frac={maxDiffSteepnessJobFrac * 100f}% dt={tSteepnessJob - tSteepnessUnity}ms"); nativeHeightmap.Dispose(); nativePositions.Dispose(); yBarycentricJob.Dispose(); steepnessJob.Dispose(); }
/// <summary> /// Shape offset, rotates native height field from z up to y up, flips x and z (?) and /// moves to center of the terrain (Unity Terrain has origin "lower corner"). /// </summary> /// <returns>Shape transform to be used between native geometry and shape.</returns> public override agx.AffineMatrix4x4 GetNativeGeometryOffset() { return(TerrainUtils.CalculateNativeOffset(transform, TerrainData)); }
/** * Create trees on the terrain */ public void GenerateTrees(LatLngObject middleMapPoint, List <TreeObject> trees) { Vector3 middleMapXyz; ConiferousTree = Resources.Load("3DObjects/Trees/Prefabs/Fir_Tree", typeof(GameObject)) as GameObject; LeafyTree = Resources.Load("3DObjects/Trees/Prefabs/Poplar_Tree", typeof(GameObject)) as GameObject; //default position, if map does not contain any building or road if (middleMapPoint.Equals(new LatLngObject())) { middleMapXyz = Vector3.zero; } else { middleMapXyz = Converter.ConvertLatLngToXyz(middleMapPoint); } var treeCount = Main.Settings.NumberOfTrees; const float treeScale = 0.06f; var terrain = TerrainRender.Get().Terrain; var random = new Random(); //GENERATE RANDOM TREE POSITIONS if (trees.Count == 0) { for (var i = 0; i < treeCount; i++) { var decimalRandomPartX = random.NextDouble(); var decimalRandomPartZ = random.NextDouble(); const int limitX = (TerrainUtils.MapWidth / 2) - 2; const int limitZ = (TerrainUtils.MapHeight / 2) - 2; var randomX = random.Next((int)(middleMapXyz.x - limitX), (int)(middleMapXyz.x + limitX)); // + 2 a + 1 kvuli korekcim umisteni na hranice terenu var randomZ = random.Next((int)(middleMapXyz.z - limitZ + 2), (int)(middleMapXyz.z + limitZ + 1)); var randomDecX = (float)(randomX + decimalRandomPartX); var randomDecZ = (float)(randomZ + decimalRandomPartZ); var randomPos = new Vector3(randomDecX, 0, randomDecZ); var terrainY = terrain.SampleHeight(randomPos); randomPos.y = terrainY; var randNumberTree = random.Next(0, 2); if (!IsPointInCollision(randomPos)) { GameObject tree; switch (randNumberTree) { case 0: tree = Instantiate(LeafyTree); break; default: tree = Instantiate(ConiferousTree); break; } var treeTransform = tree.transform; treeTransform.position = randomPos; treeTransform.localScale = new Vector3(treeScale, treeScale, treeScale); } else { --i; } } } //CUSTOM TREE POSITIONS else { foreach (var currentTree in trees) { var treePos = Converter.ConvertLatLngToXyz(currentTree.LatLngCoordinate); //if tree is outside the map if (TerrainUtils.IsObjectOutsideMap(treePos, middleMapXyz)) { continue; } //set y position from terrain var terrainY = terrain.SampleHeight(treePos); treePos.y = terrainY; var randNumberTree = random.Next(0, 2); GameObject tree; switch (randNumberTree) { case 0: tree = Instantiate(LeafyTree); break; default: tree = Instantiate(ConiferousTree); break; } var treeTransform = tree.transform; treeTransform.position = treePos; treeTransform.localScale = new Vector3(treeScale, treeScale, treeScale); } } }
public override void OnInspectorGUI() { DrawDefaultInspector(); TerrainUtils utils = (TerrainUtils)target; // Set the trees only if (GUILayout.Button("Set Tree Prototypes Only")) { utils.CopyTerrainTreePrototypes(); } if (GUILayout.Button("Set Heightmap Only")) { utils.CopyTerrainHeightmap(); } if (GUILayout.Button("Copy Trees")) { utils.CopyTerrainTrees(); } if (GUILayout.Button("Copy Details")) { utils.CopyTerrainDetailPrototypes(); } if (GUILayout.Button("Copy Textures")) { utils.CopyTerrainTextures(); } if (GUILayout.Button("Delete Main Terrain Trees")) { utils.ClearMainTerrainTrees(); } if (GUILayout.Button("Delete Terrain Trees")) { utils.ClearTrees(); } if (GUILayout.Button("Count Trees")) { Debug.Log("Tree count: " + utils.m_MainTerrain.terrainData.treeInstanceCount); } if (GUILayout.Button("Cell Info")) { utils.CellInfo(); } if (GUILayout.Button("Full Copy")) { utils.FullCopy(); } if (GUILayout.Button("Convert Main Terrain Splatmap")) { utils.ConvertTerrainResolution(); } if (GUILayout.Button("Add Trees From Main And Delete")) { utils.AddFromMainAndDelete(); } }
public void Execute(int i) { float3 pos = positions[i]; results[i] = TerrainUtils.GetTerrainSteepnessTriangle(nativeHeightmap, -size / 2f, -size / 2f, size, pos.x, pos.z, maxHeight, res); }