[TASK] Initial commit with basic product setup
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
// Author: Eric Haines (Eric5h5)
|
||||
// SOURCE: http://wiki.unity3d.com/index.php/TextureScale
|
||||
|
||||
namespace Mapbox.Examples.Voxels
|
||||
{
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
public class TextureScale
|
||||
{
|
||||
public class ThreadData
|
||||
{
|
||||
public int start;
|
||||
public int end;
|
||||
public ThreadData(int s, int e)
|
||||
{
|
||||
start = s;
|
||||
end = e;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color[] texColors;
|
||||
private static Color[] newColors;
|
||||
private static int w;
|
||||
private static float ratioX;
|
||||
private static float ratioY;
|
||||
private static int w2;
|
||||
private static int finishCount;
|
||||
private static Mutex mutex;
|
||||
|
||||
public static void Point(Texture2D tex, int newWidth, int newHeight)
|
||||
{
|
||||
ThreadedScale(tex, newWidth, newHeight, false);
|
||||
}
|
||||
|
||||
public static void Bilinear(Texture2D tex, int newWidth, int newHeight)
|
||||
{
|
||||
ThreadedScale(tex, newWidth, newHeight, true);
|
||||
}
|
||||
|
||||
private static void ThreadedScale(Texture2D tex, int newWidth, int newHeight, bool useBilinear)
|
||||
{
|
||||
texColors = tex.GetPixels();
|
||||
newColors = new Color[newWidth * newHeight];
|
||||
if (useBilinear)
|
||||
{
|
||||
ratioX = 1.0f / ((float)newWidth / (tex.width - 1));
|
||||
ratioY = 1.0f / ((float)newHeight / (tex.height - 1));
|
||||
}
|
||||
else {
|
||||
ratioX = ((float)tex.width) / newWidth;
|
||||
ratioY = ((float)tex.height) / newHeight;
|
||||
}
|
||||
w = tex.width;
|
||||
w2 = newWidth;
|
||||
#if WINDOWS_UWP
|
||||
var cores = 1;
|
||||
#else
|
||||
var cores = Mathf.Min(SystemInfo.processorCount, newHeight);
|
||||
#endif
|
||||
var slice = newHeight / cores;
|
||||
|
||||
finishCount = 0;
|
||||
if (mutex == null)
|
||||
{
|
||||
mutex = new Mutex(false);
|
||||
}
|
||||
|
||||
#if WINDOWS_UWP
|
||||
ThreadData threadData = new ThreadData(0, newHeight);
|
||||
if (useBilinear)
|
||||
{
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else
|
||||
{
|
||||
PointScale(threadData);
|
||||
}
|
||||
#else
|
||||
if (cores > 1)
|
||||
{
|
||||
int i = 0;
|
||||
ThreadData threadData;
|
||||
for (i = 0; i < cores - 1; i++)
|
||||
{
|
||||
threadData = new ThreadData(slice * i, slice * (i + 1));
|
||||
ParameterizedThreadStart ts = useBilinear ? new ParameterizedThreadStart(BilinearScale) : new ParameterizedThreadStart(PointScale);
|
||||
Thread thread = new Thread(ts);
|
||||
thread.Start(threadData);
|
||||
}
|
||||
threadData = new ThreadData(slice * i, newHeight);
|
||||
if (useBilinear)
|
||||
{
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else
|
||||
{
|
||||
PointScale(threadData);
|
||||
}
|
||||
while (finishCount < cores)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadData threadData = new ThreadData(0, newHeight);
|
||||
if (useBilinear)
|
||||
{
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else
|
||||
{
|
||||
PointScale(threadData);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
tex.Resize(newWidth, newHeight);
|
||||
tex.SetPixels(newColors);
|
||||
tex.Apply();
|
||||
|
||||
texColors = null;
|
||||
newColors = null;
|
||||
}
|
||||
|
||||
public static void BilinearScale(System.Object obj)
|
||||
{
|
||||
ThreadData threadData = (ThreadData)obj;
|
||||
for (var y = threadData.start; y < threadData.end; y++)
|
||||
{
|
||||
int yFloor = (int)Mathf.Floor(y * ratioY);
|
||||
var y1 = yFloor * w;
|
||||
var y2 = (yFloor + 1) * w;
|
||||
var yw = y * w2;
|
||||
|
||||
for (var x = 0; x < w2; x++)
|
||||
{
|
||||
int xFloor = (int)Mathf.Floor(x * ratioX);
|
||||
var xLerp = x * ratioX - xFloor;
|
||||
newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor + 1], xLerp),
|
||||
ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor + 1], xLerp),
|
||||
y * ratioY - yFloor);
|
||||
}
|
||||
}
|
||||
|
||||
mutex.WaitOne();
|
||||
finishCount++;
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
public static void PointScale(System.Object obj)
|
||||
{
|
||||
ThreadData threadData = (ThreadData)obj;
|
||||
for (var y = threadData.start; y < threadData.end; y++)
|
||||
{
|
||||
var thisY = (int)(ratioY * y) * w;
|
||||
var yw = y * w2;
|
||||
for (var x = 0; x < w2; x++)
|
||||
{
|
||||
newColors[yw + x] = texColors[(int)(thisY + ratioX * x)];
|
||||
}
|
||||
}
|
||||
|
||||
mutex.WaitOne();
|
||||
finishCount++;
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
private static Color ColorLerpUnclamped(Color c1, Color c2, float value)
|
||||
{
|
||||
return new Color(c1.r + (c2.r - c1.r) * value,
|
||||
c1.g + (c2.g - c1.g) * value,
|
||||
c1.b + (c2.b - c1.b) * value,
|
||||
c1.a + (c2.a - c1.a) * value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8a25e65acfda4860a278fa12af6af15
|
||||
timeCreated: 1479789123
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mapbox.Examples.Voxels
|
||||
{
|
||||
public class VoxelData
|
||||
{
|
||||
public Vector3 Position;
|
||||
public GameObject Prefab;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f62c746136134da5babc8ba012436d1
|
||||
timeCreated: 1482518006
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mapbox.Examples.Voxels
|
||||
{
|
||||
public class VoxelFetcher : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
VoxelColorMapper[] _voxels;
|
||||
|
||||
public GameObject GetVoxelFromColor(Color color)
|
||||
{
|
||||
GameObject matchingVoxel = _voxels[0].Voxel;
|
||||
var minDistance = Mathf.Infinity;
|
||||
foreach (var voxel in _voxels)
|
||||
{
|
||||
var distance = GetDistanceBetweenColors(voxel.Color, color);
|
||||
if (distance < minDistance)
|
||||
{
|
||||
matchingVoxel = voxel.Voxel;
|
||||
minDistance = distance;
|
||||
}
|
||||
}
|
||||
return matchingVoxel;
|
||||
}
|
||||
|
||||
public static float GetDistanceBetweenColors(Color color1, Color color2)
|
||||
{
|
||||
return Mathf.Sqrt(Mathf.Pow(color1.r - color2.r, 2f) + Mathf.Pow(color1.g - color2.g, 2f) + Mathf.Pow(color1.b - color2.b, 2f));
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class VoxelColorMapper
|
||||
{
|
||||
public Color Color;
|
||||
public GameObject Voxel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb0ebec3dc2616941bc6ed14d239dd56
|
||||
timeCreated: 1478714265
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,216 @@
|
||||
namespace Mapbox.Examples.Voxels
|
||||
{
|
||||
using Mapbox.Geocoding;
|
||||
using Mapbox.Map;
|
||||
using Mapbox.Unity;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Mapbox.Utils;
|
||||
using Mapbox.Platform;
|
||||
using Mapbox.Unity.Utilities;
|
||||
class VoxelTile : MonoBehaviour, Mapbox.Utils.IObserver<RasterTile>, Mapbox.Utils.IObserver<RawPngRasterTile>
|
||||
{
|
||||
[SerializeField]
|
||||
ForwardGeocodeUserInput _geocodeInput;
|
||||
|
||||
[SerializeField]
|
||||
int _zoom = 17;
|
||||
|
||||
[SerializeField]
|
||||
float _elevationMultiplier = 1f;
|
||||
|
||||
[SerializeField]
|
||||
int _voxelDepthPadding = 1;
|
||||
|
||||
[SerializeField]
|
||||
int _tileWidthInVoxels;
|
||||
|
||||
[SerializeField]
|
||||
VoxelFetcher _voxelFetcher;
|
||||
|
||||
[SerializeField]
|
||||
GameObject _camera;
|
||||
|
||||
[SerializeField]
|
||||
int _voxelBatchCount = 100;
|
||||
|
||||
[SerializeField]
|
||||
string _styleUrl;
|
||||
|
||||
Map<RasterTile> _raster;
|
||||
Map<RawPngRasterTile> _elevation;
|
||||
|
||||
Texture2D _rasterTexture;
|
||||
Texture2D _elevationTexture;
|
||||
|
||||
IFileSource _fileSource;
|
||||
|
||||
List<VoxelData> _voxels = new List<VoxelData>();
|
||||
|
||||
List<GameObject> _instantiatedVoxels = new List<GameObject>();
|
||||
|
||||
float _tileScale;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_geocodeInput.OnGeocoderResponse += GeocodeInput_OnGeocoderResponse;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (_geocodeInput)
|
||||
{
|
||||
_geocodeInput.OnGeocoderResponse -= GeocodeInput_OnGeocoderResponse;
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
_fileSource = MapboxAccess.Instance;
|
||||
|
||||
_raster = new Map<RasterTile>(_fileSource);
|
||||
_elevation = new Map<RawPngRasterTile>(_fileSource);
|
||||
|
||||
if (!string.IsNullOrEmpty(_styleUrl))
|
||||
{
|
||||
_raster.MapId = _styleUrl;
|
||||
}
|
||||
_elevation.MapId = "mapbox.terrain-rgb";
|
||||
|
||||
_elevation.Subscribe(this);
|
||||
_raster.Subscribe(this);
|
||||
|
||||
// Torres Del Paine
|
||||
FetchWorldData(new Vector2d(-50.98306, -72.96639));
|
||||
}
|
||||
|
||||
void GeocodeInput_OnGeocoderResponse(ForwardGeocodeResponse response)
|
||||
{
|
||||
Cleanup();
|
||||
FetchWorldData(_geocodeInput.Coordinate);
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
_rasterTexture = null;
|
||||
_elevationTexture = null;
|
||||
_voxels.Clear();
|
||||
foreach (var voxel in _instantiatedVoxels)
|
||||
{
|
||||
Destroy(voxel);
|
||||
}
|
||||
}
|
||||
|
||||
void FetchWorldData(Vector2d coordinates)
|
||||
{
|
||||
_tileScale = (_tileWidthInVoxels / 256f) / Conversions.GetTileScaleInMeters((float)coordinates.x, _zoom);
|
||||
var bounds = new Vector2dBounds();
|
||||
bounds.Center = coordinates;
|
||||
_raster.SetVector2dBoundsZoom(bounds, _zoom);
|
||||
_elevation.SetVector2dBoundsZoom(bounds, _zoom);
|
||||
_raster.Update();
|
||||
_elevation.Update();
|
||||
}
|
||||
|
||||
public void OnNext(RasterTile tile)
|
||||
{
|
||||
if (
|
||||
!tile.HasError
|
||||
&& (tile.CurrentState == Tile.State.Loaded || tile.CurrentState == Tile.State.Updated)
|
||||
)
|
||||
{
|
||||
_rasterTexture = new Texture2D(2, 2);
|
||||
_rasterTexture.LoadImage(tile.Data);
|
||||
TextureScale.Point(_rasterTexture, _tileWidthInVoxels, _tileWidthInVoxels);
|
||||
|
||||
if (ShouldBuildWorld())
|
||||
{
|
||||
BuildVoxelWorld();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNext(RawPngRasterTile tile)
|
||||
{
|
||||
if (
|
||||
!tile.HasError
|
||||
&& (tile.CurrentState == Tile.State.Loaded || tile.CurrentState == Tile.State.Updated)
|
||||
)
|
||||
{
|
||||
_elevationTexture = new Texture2D(2, 2);
|
||||
_elevationTexture.LoadImage(tile.Data);
|
||||
TextureScale.Point(_elevationTexture, _tileWidthInVoxels, _tileWidthInVoxels);
|
||||
|
||||
if (ShouldBuildWorld())
|
||||
{
|
||||
BuildVoxelWorld();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldBuildWorld()
|
||||
{
|
||||
return _rasterTexture != null && _elevationTexture != null;
|
||||
}
|
||||
|
||||
void BuildVoxelWorld()
|
||||
{
|
||||
var baseHeight = (int)Conversions.GetRelativeHeightFromColor(
|
||||
(_elevationTexture.GetPixel(_elevationTexture.width / 2, _elevationTexture.height / 2))
|
||||
, _elevationMultiplier * _tileScale
|
||||
);
|
||||
|
||||
for (int x = 0; x < _rasterTexture.width; x++)
|
||||
{
|
||||
for (int z = 0; z < _rasterTexture.height; z++)
|
||||
{
|
||||
var height = (int)Conversions.GetRelativeHeightFromColor(
|
||||
_elevationTexture.GetPixel(x, z)
|
||||
, _elevationMultiplier * _tileScale
|
||||
) - baseHeight;
|
||||
|
||||
var startHeight = height - _voxelDepthPadding - 1;
|
||||
var color = _rasterTexture.GetPixel(x, z);
|
||||
|
||||
for (int y = startHeight; y < height; y++)
|
||||
{
|
||||
_voxels.Add(new VoxelData() { Position = new Vector3(x, y, z), Prefab = _voxelFetcher.GetVoxelFromColor(color) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_camera != null)
|
||||
{
|
||||
_camera.transform.position = new Vector3(_tileWidthInVoxels * .5f, 2f, _tileWidthInVoxels * .5f);
|
||||
}
|
||||
|
||||
if (this != null)
|
||||
{
|
||||
StartCoroutine(BuildRoutine());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator BuildRoutine()
|
||||
{
|
||||
var distanceOrderedVoxels = _voxels.OrderBy(x => (_camera.transform.position - x.Position).magnitude).ToList();
|
||||
|
||||
for (int i = 0; i < distanceOrderedVoxels.Count; i += _voxelBatchCount)
|
||||
{
|
||||
for (int j = 0; j < _voxelBatchCount; j++)
|
||||
{
|
||||
var index = i + j;
|
||||
if (index < distanceOrderedVoxels.Count)
|
||||
{
|
||||
var voxel = distanceOrderedVoxels[index];
|
||||
_instantiatedVoxels.Add(Instantiate(voxel.Prefab, voxel.Position, Quaternion.identity, transform) as GameObject);
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de5fb1ae8036545848eae9ab4c9dd119
|
||||
timeCreated: 1482517130
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user