Skip to content

Instantly share code, notes, and snippets.

@zulfajuniadi
Created June 30, 2018 11:51
Show Gist options
  • Save zulfajuniadi/ab63483e44f9f9ae29f3a4581d642e3e to your computer and use it in GitHub Desktop.
Save zulfajuniadi/ab63483e44f9f9ae29f3a4581d642e3e to your computer and use it in GitHub Desktop.
Fast Terrain Scanning
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
[System.Serializable]
public class Tile
{
public int Key;
public Vector3 Position;
public Vector3 Normal;
public float Elevation;
public bool Sloped;
public Tile (int key, Vector3 position, Vector3 normal, bool sloped)
{
Key = key;
position.y = Elevation = Mathf.Round (position.y * 10) / 10;
Normal = normal;
Position = position;
Sloped = sloped;
}
}
public class TerrainScanner : MonoBehaviour
{
public Dictionary<int, Tile> TilePositions = new Dictionary<int, Tile> ();
public LayerMask raycastMask;
public Vector2Int MapSize = new Vector2Int (512, 512);
private void Start ()
{
MapTerrain ();
}
public void MapTerrain ()
{
var sw = new System.Diagnostics.Stopwatch ();
sw.Start ();
TilePositions.Clear ();
var commandSize = (MapSize.x * MapSize.y);
var up = Vector3.up;
var down = Vector3.down;
var hits = 1;
var results = new NativeArray<RaycastHit> (commandSize * hits, Allocator.Temp);
var commands = new NativeArray<RaycastCommand> (commandSize, Allocator.Temp);
for (int x = 0; x < MapSize.x; x++)
{
for (int y = 0; y < MapSize.y; y++)
{
var key = GetKey (x, y);
var origin = new Vector3 (x, 200, y);
commands[key] = new RaycastCommand (origin, down, 300, raycastMask, hits);
}
}
var handle = RaycastCommand.ScheduleBatch (commands, results, MapSize.x);
handle.Complete ();
commands.Dispose ();
for (int x = 0; x < MapSize.x; x++)
{
for (int y = 0; y < MapSize.y; y++)
{
var position = new Vector3 (x, 0, y);
position.y = 0;
var key = GetKey (x, y);
var result = results[key];
var isSloped = false;
var normal = up;
if (result.collider)
{
position = result.point;
normal = result.normal;
isSloped = normal != up;
}
var tile = new Tile (key, position, normal, isSloped);
TilePositions[key] = tile;
}
}
results.Dispose ();
sw.Stop ();
Debug.Log ("Scanning done in " + sw.ElapsedMilliseconds + "ms");
}
public Tile GetTileAtPosition (Vector3 position)
{
if (TilePositions.Count == 0) return null;
var x = Mathf.RoundToInt (position.x);
var z = Mathf.RoundToInt (position.z);
var key = GetKey (x, z);
if (!TilePositions.ContainsKey (key)) return null;
return TilePositions[key];
}
int GetKey (int x, int y)
{
return x * MapSize.x + y;
}
}
@zulfajuniadi
Copy link
Author

zulfajuniadi commented Jun 30, 2018

For a 512 x 512 terain:
Scanning done in 176ms

Minimum Unity Version: 2018.1
Set project to use .net 4
Install the entities package from the Package Manager

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment