Skip to content

Instantly share code, notes, and snippets.

@mihakrajnc
Created November 2, 2017 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mihakrajnc/c7f46ba9a136c1dab1ee36c5cd7dfc47 to your computer and use it in GitHub Desktop.
Save mihakrajnc/c7f46ba9a136c1dab1ee36c5cd7dfc47 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Mapbox.Unity.MeshGeneration.Modifiers.MeshModifiers;
using Mapbox.Unity;
using Mapbox.Unity.Map;
using Mapbox.Unity.MeshGeneration.Components;
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Unity.MeshGeneration.Enums;
using Mapbox.Unity.MeshGeneration.Interfaces;
using Mapbox.Unity.MeshGeneration.Modifiers;
using Pathfinding;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Core.MB
{
[CreateAssetMenu(menuName = "Mapbox/Modifiers/Custom/Color Filtered Prefab Modifier")]
public class ColorFilteredPrefabModifier : GameObjectModifier
{
[SerializeField] private GameObject[] _prefabs;
[SerializeField] private int _density = 10;
[SerializeField] private Color[] colorFilters;
[SerializeField] private float tolerance = 0.02f;
[SerializeField] private float scale = 1;
[SerializeField] private LayerMask mask;
public override void Run(FeatureBehaviour fb, UnityTile tile)
{
switch (tile.RasterDataState)
{
case TilePropertyState.Loaded:
UpdatePrefabs(fb, tile);
break;
case TilePropertyState.Loading:
case TilePropertyState.None:
tile.OnRasterDataChanged += rTile => UpdatePrefabs(fb, tile);
break;
}
}
private void UpdatePrefabs(FeatureBehaviour fb, UnityTile tile)
{
//FIXME: This is shit. Should remove OnRasterDataChanged callback instead.
if (!fb) return;
List<List<Vector3>> subset = fb.Data.Points;
Data flatData = EarcutLibrary.Flatten(subset);
List<int> result = EarcutLibrary.Earcut(flatData.Vertices, flatData.Holes, flatData.Dim);
for (int m = 0; m < result.Count - 3; m += 3)
{
Vector2 vert1Pos = new Vector2(flatData.Vertices[2 * result[m]],
flatData.Vertices[2 * result[m] + 1]);
Vector2 vert2Pos = new Vector2(flatData.Vertices[2 * result[m + 1]],
flatData.Vertices[2 * result[m + 1] + 1]);
Vector2 vert3Pos = new Vector2(flatData.Vertices[2 * result[m + 2]],
flatData.Vertices[2 * result[m + 2] + 1]);
float area = Utils.TriangleArea(vert1Pos, vert2Pos, vert3Pos);
int numberOfPoints = Math.Max(1, (int) (_density * area / 3000));
for (int i = 0; i < numberOfPoints; i++)
{
Vector2 randomPoint =
Utils.RandomPointInTriangle(vert1Pos, vert2Pos, vert3Pos) *
tile.Map.WorldRelativeScale;
float height = tile.QueryHeightData(
(float) ((randomPoint.x + tile.Rect.Size.x / 2) /
tile.Rect.Size.x),
(float) ((randomPoint.y + tile.Rect.Size.y / 2) /
tile.Rect.Size.y)) * tile.Map.WorldRelativeScale;
Vector3 worldPos = new Vector3(randomPoint.x, height, randomPoint.y) + fb.transform.position;
RaycastHit hit;
if (Physics.Raycast(worldPos + Vector3.up * 50f, Vector3.down, out hit, 100, mask))
{
worldPos = hit.point;
Material material = hit.transform.GetComponent<Renderer>().material;
Texture texture = material.mainTexture;
Texture2D tex = texture as Texture2D;
if (tex != null)
{
Vector2 pixelUv = hit.textureCoord;
pixelUv.x *= tex.width;
pixelUv.y *= tex.height;
Color color = tex.GetPixel((int) pixelUv.x, (int) pixelUv.y);
if (ColorMatches(color))
{
GameObject go = Instantiate(_prefabs[Random.Range(0, _prefabs.Length)], worldPos,
Quaternion.identity);
go.transform.localScale = Vector3.one * scale;
go.transform.parent = fb.transform;
}
}
}
}
}
}
private bool ColorMatches(Color color)
{
return colorFilters == null || colorFilters.Length == 0 || colorFilters.Any(colorFilter =>
Math.Abs(colorFilter.r - color.r) < tolerance &&
Math.Abs(colorFilter.g - color.g) < tolerance &&
Math.Abs(colorFilter.b - color.b) < tolerance);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment