This commit is contained in:
2025-06-09 00:11:54 +08:00
parent d8c6eb0bd6
commit c773a6bb8d
11207 changed files with 48929 additions and 304 deletions

View File

@@ -0,0 +1,20 @@
/* INFINITY CODE 2013-2019 */
/* http://www.infinity-code.com */
#if BUILDR2
using System.Collections.Generic;
using BuildR2;
#endif
namespace InfinityCode.RealWorldTerrain
{
public class RealWorldTerrainBuildR2Material
{
#if BUILDR2
public Facade applyFacade;
public Surface roofSurface;
public Roof.Types roofType = Roof.Types.Flat;
public List<Facade> facades;
#endif
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3c28a4517ca6c5c469273a4fffa52a46
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,18 @@
/* INFINITY CODE */
/* https://infinity-code.com */
#if BUILDR3
using BuildRCities;
#endif
namespace InfinityCode.RealWorldTerrain
{
public class RealWorldTerrainBuildR3Material
{
#if BUILDR3
public FacadeAsset wallFacade;
public DynamicTextureAsset roofTexture;
public Roof.Types roofType;
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 434cc2378df29a74299c7f3a3dd96dd7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
/* INFINITY CODE 2013-2019 */
/* http://www.infinity-code.com */
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
/// <summary>
/// This class contains basic information about BuildR building.
/// </summary>
[AddComponentMenu("")]
public class RealWorldTerrainBuildRBuilding : MonoBehaviour
{
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f2c1d10b35fec2c4a824c7d1cc6dd498
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,456 @@
/* INFINITY CODE */
/* https://infinity-code.com */
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
/// <summary>
/// This class contains basic information about the building.
/// </summary>
[AddComponentMenu("")]
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class RealWorldTerrainBuilding : MonoBehaviour
{
/// <summary>
/// The height of the walls.
/// </summary>
public float baseHeight;
/// <summary>
/// Array of base vertices.
/// </summary>
public Vector3[] baseVertices;
/// <summary>
/// Reference to RealWorldTerrainContainer instance.
/// </summary>
public RealWorldTerrainContainer container;
/// <summary>
/// ID of the building
/// </summary>
public string id;
/// <summary>
/// Indicates that roof normals is inverted.
/// </summary>
public bool invertRoof;
/// <summary>
/// Indicates that walls normals is inverted.
/// </summary>
public bool invertWall;
/// <summary>
/// Height of roof.
/// </summary>
public float roofHeight;
/// <summary>
/// Type of roof.
/// </summary>
public RealWorldTerrainRoofType roofType;
/// <summary>
/// Whether to generate the wall?
/// </summary>
public bool generateWall;
/// <summary>
/// Material of the roof.
/// </summary>
public Material roofMaterial;
/// <summary>
/// The scale of the roof texture's UV coordinates.
/// </summary>
public Vector2 roofUVScale = Vector2.one;
/// <summary>
/// The starting height for the building.
/// </summary>
public float startHeight = 0;
/// <summary>
/// Size of a tile texture in meters.
/// </summary>
public Vector2 tileSize = new Vector2(30, 30);
/// <summary>
/// Offset of the UV coordinates.
/// </summary>
public Vector2 uvOffset = Vector2.zero;
/// <summary>
/// Material of the wall.
/// </summary>
public Material wallMaterial;
private MeshFilter _meshFilter;
/// <summary>
/// Reference to MeshFilter of the building.
/// </summary>
public MeshFilter meshFilter
{
get
{
if (_meshFilter == null) _meshFilter = GetComponent<MeshFilter>();
return _meshFilter;
}
}
/// <summary>
/// Reference to MeshFilter of roof.
/// </summary>
[Obsolete("Use meshFilter instead.")]
public MeshFilter roof
{
get { return meshFilter; }
}
/// <summary>
/// Reference to MeshFilter of wall.
/// </summary>
[Obsolete("Use meshFilter instead.")]
public MeshFilter wall
{
get { return meshFilter; }
}
private void CreateRoofDome(List<Vector3> vertices, List<int> triangles)
{
Vector3 roofTopPoint = Vector3.zero;
roofTopPoint = vertices.Aggregate(roofTopPoint, (current, point) => current + point) / vertices.Count;
roofTopPoint.y = (baseHeight + roofHeight) * container.scale.y;
int vIndex = vertices.Count;
for (int i = 0; i < vertices.Count; i++)
{
int p1 = i;
int p2 = i + 1;
if (p2 >= vertices.Count) p2 -= vertices.Count;
triangles.AddRange(new[] { p1, p2, vIndex });
}
vertices.Add(roofTopPoint);
}
private void CreateRoofMesh(List<Vector3> vertices, out List<Vector2> uv, out List<int> triangles)
{
List<Vector2> roofPoints = CreateRoofVertices(vertices);
triangles = CreateRoofTriangles(vertices, roofPoints);
if (invertRoof) triangles.Reverse();
float minX = float.MaxValue;
float minZ = float.MaxValue;
float maxX = float.MinValue;
float maxZ = float.MinValue;
float maxDistance = 0;
int maxDistanceIndex = -1;
int nextIndex = -1;
for (int i = 0; i < vertices.Count; i++)
{
Vector3 v = vertices[i];
if (v.x < minX) minX = v.x;
if (v.z < minZ) minZ = v.z;
if (v.x > maxX) maxX = v.x;
if (v.z > maxZ) maxZ = v.z;
nextIndex = i + 1;
if (nextIndex >= vertices.Count) nextIndex = 0;
float distance = (v - vertices[nextIndex]).sqrMagnitude;
if (distance > maxDistance)
{
maxDistance = distance;
maxDistanceIndex = i;
}
}
nextIndex = maxDistanceIndex + 1;
if (nextIndex >= vertices.Count) nextIndex = 0;
Vector3 v1 = vertices[maxDistanceIndex];
Vector3 v2 = vertices[nextIndex];
float angle = 360 - RealWorldTerrainMath.Angle2D(v1, v2);
float centerX = (minX + maxX) / 2;
float centerZ = (minZ + maxZ) / 2;
Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(centerX, 0, centerZ), Quaternion.Euler(0, -angle, 0), Vector3.one);
Bounds bounds = new Bounds();
foreach (Vector3 v in vertices)
{
Vector3 v1t = matrix.MultiplyPoint(v);
bounds.Encapsulate(v1t);
}
Vector2 roofScale = roofUVScale;
if (roofScale.x == 0) roofScale.x = 0.001f;
if (roofScale.y == 0) roofScale.y = 0.001f;
uv = new List<Vector2>();
foreach (Vector3 v in vertices)
{
Vector3 v1t = matrix.MultiplyPoint(v);
Vector2 uv1 = new Vector2(v1t.x / roofUVScale.x, v1t.z / roofUVScale.y);
uv.Add(uv1);
}
}
private List<int> CreateRoofTriangles(List<Vector3> vertices, List<Vector2> roofPoints)
{
List<int> triangles = new List<int>();
if (roofType == RealWorldTerrainRoofType.flat)
{
int[] trs = RealWorldTerrainTriangulator.Triangulate(roofPoints);
if (trs != null) triangles.AddRange(trs);
}
else if (roofType == RealWorldTerrainRoofType.dome)
{
CreateRoofDome(vertices, triangles);
}
return triangles;
}
private List<Vector2> CreateRoofVertices(List<Vector3> vertices)
{
Vector3[] targetVertices = new Vector3[baseVertices.Length];
Array.Copy(baseVertices, targetVertices, baseVertices.Length);
if (container.prefs.buildingBottomMode == RealWorldTerrainBuildingBottomMode.followTerrain)
{
Vector3 tp = transform.position;
RealWorldTerrainItem terrainItem = container.GetItemByWorldPosition(baseVertices[0] + tp);
if (terrainItem != null)
{
TerrainData t = terrainItem.terrainData;
Vector3 offset = tp - terrainItem.transform.position;
for (int i = 0; i < targetVertices.Length; i++)
{
Vector3 v = targetVertices[i];
Vector3 localPos = offset + v;
float y = t.GetInterpolatedHeight(localPos.x / t.size.x, localPos.z / t.size.z);
v.y = terrainItem.transform.position.y + y - tp.y;
targetVertices[i] = v;
}
}
}
List<Vector2> roofPoints = new List<Vector2>();
float topPoint = targetVertices.Max(v => v.y) + baseHeight * container.scale.y;
foreach (Vector3 p in targetVertices)
{
Vector3 tv = new Vector3(p.x, topPoint, p.z);
Vector2 rp = new Vector2(p.x, p.z);
vertices.Add(tv);
roofPoints.Add(rp);
}
return roofPoints;
}
private void CreateWallMesh(List<Vector3> vertices, List<Vector2> uv, out List<int> triangles)
{
List<Vector3> wv = new List<Vector3>();
List<Vector2> wuv = new List<Vector2>();
bool reversed = CreateWallVertices(wv, wuv);
if (invertWall) reversed = !reversed;
triangles = CreateWallTriangles(wv, vertices.Count, reversed);
vertices.AddRange(wv);
uv.AddRange(wuv);
}
private List<int> CreateWallTriangles(List<Vector3> vertices, int offset, bool reversed)
{
List<int> triangles = new List<int>();
for (int i = 0; i < vertices.Count / 4; i++)
{
int p1 = i * 4;
int p2 = i * 4 + 2;
int p3 = i * 4 + 3;
int p4 = i * 4 + 1;
if (p2 >= vertices.Count) p2 -= vertices.Count;
if (p3 >= vertices.Count) p3 -= vertices.Count;
p1 += offset;
p2 += offset;
p3 += offset;
p4 += offset;
if (reversed)
{
triangles.AddRange(new[] { p1, p4, p3, p1, p3, p2 });
}
else
{
triangles.AddRange(new[] { p2, p3, p1, p3, p4, p1 });
}
}
return triangles;
}
private bool CreateWallVertices(List<Vector3> vertices, List<Vector2> uv)
{
Vector3[] targetVertices = new Vector3[baseVertices.Length];
Array.Copy(baseVertices, targetVertices, baseVertices.Length);
if (container.prefs.buildingBottomMode == RealWorldTerrainBuildingBottomMode.followTerrain)
{
Vector3 tp = transform.position;
RealWorldTerrainItem terrainItem = container.GetItemByWorldPosition(baseVertices[0] + tp);
if (terrainItem != null)
{
TerrainData t = terrainItem.terrainData;
Vector3 offset = tp - terrainItem.transform.position;
for (int i = 0; i < targetVertices.Length; i++)
{
Vector3 v = targetVertices[i];
Vector3 localPos = offset + v;
float y = t.GetInterpolatedHeight(localPos.x / t.size.x, localPos.z / t.size.z);
v.y = terrainItem.transform.position.y + y - tp.y;
targetVertices[i] = v;
}
}
}
float topPoint = targetVertices.Max(v => v.y) + baseHeight * container.scale.y;
float startY = startHeight * container.scale.y;
float offsetY = startY < 0 ? startY : 0;
for (int i = 0; i < targetVertices.Length; i++)
{
Vector3 p1 = targetVertices[i];
Vector3 p2 = i < targetVertices.Length - 1 ? targetVertices[i + 1] : targetVertices[0];
if (p1.y < startY) p1.y = startY;
if (p2.y < startY) p2.y = startY;
p1.y += offsetY;
p2.y += offsetY;
vertices.Add(p1);
vertices.Add(new Vector3(p1.x, topPoint, p1.z));
vertices.Add(p2);
vertices.Add(new Vector3(p2.x, topPoint, p2.z));
}
float totalDistance = 0;
float bottomPoint = float.MaxValue;
for (int i = 0; i < vertices.Count / 4; i++)
{
int i1 = Mathf.RoundToInt(Mathf.Repeat(i * 4, vertices.Count));
int i2 = Mathf.RoundToInt(Mathf.Repeat((i + 1) * 4, vertices.Count));
Vector3 v1 = vertices[i1];
Vector3 v2 = vertices[i2];
v1.y = v2.y = 0;
totalDistance += (v1 - v2).magnitude;
if (bottomPoint > targetVertices[i].y) bottomPoint = targetVertices[i].y;
}
Vector3 lv1 = vertices[vertices.Count - 4];
Vector3 lv2 = vertices[0];
lv1.y = lv2.y = 0;
totalDistance += (lv1 - lv2).magnitude;
float currentDistance = 0;
float nextU = 0;
float uMul = totalDistance / tileSize.x;
float vMax = topPoint / tileSize.y;
float vMinMul = container.scale.y * tileSize.y;
for (int i = 0; i < vertices.Count / 4; i++)
{
int i1 = Mathf.RoundToInt(Mathf.Repeat(i * 4, vertices.Count));
int i2 = Mathf.RoundToInt(Mathf.Repeat((i + 1) * 4, vertices.Count));
float curU = nextU;
uv.Add(new Vector2(curU * uMul + uvOffset.x, (vertices[i * 4].y - bottomPoint) / vMinMul + uvOffset.y));
uv.Add(new Vector2(curU * uMul + uvOffset.x, vMax + uvOffset.y));
Vector3 v1 = vertices[i1];
Vector3 v2 = vertices[i2];
v1.y = v2.y = 0;
currentDistance += (v1 - v2).magnitude;
nextU = currentDistance / totalDistance;
uv.Add(new Vector2(nextU * uMul + uvOffset.x, (vertices[i * 4 + 2].y - bottomPoint) / vMinMul + uvOffset.y));
uv.Add(new Vector2(nextU * uMul + uvOffset.x, vMax + uvOffset.y));
}
int southIndex = -1;
float southZ = float.MaxValue;
for (int i = 0; i < targetVertices.Length; i++)
{
if (targetVertices[i].z < southZ)
{
southZ = targetVertices[i].z;
southIndex = i;
}
}
int prevIndex = southIndex - 1;
if (prevIndex < 0) prevIndex = targetVertices.Length - 1;
int nextIndex = southIndex + 1;
if (nextIndex >= targetVertices.Length) nextIndex = 0;
float angle1 = RealWorldTerrainMath.Angle2D(targetVertices[southIndex], targetVertices[nextIndex]);
float angle2 = RealWorldTerrainMath.Angle2D(targetVertices[southIndex], targetVertices[prevIndex]);
return angle1 < angle2;
}
/// <summary>
/// Generates the building mesh.
/// </summary>
public void Generate()
{
Mesh mesh;
if (meshFilter.sharedMesh != null) mesh = meshFilter.sharedMesh;
else
{
mesh = new Mesh();
mesh.name = "Building " + id;
mesh.subMeshCount = 2;
meshFilter.sharedMesh = mesh;
}
List<Vector3> vertices = new List<Vector3>();
List<Vector2> uv;
List<int> roofTriangles;
List<int> wallTriangles = null;
CreateRoofMesh(vertices, out uv, out roofTriangles);
if (generateWall) CreateWallMesh(vertices, uv, out wallTriangles);
mesh.SetVertices(vertices);
mesh.SetUVs(0, uv);
mesh.SetTriangles(roofTriangles, 0);
if (generateWall) mesh.SetTriangles(wallTriangles, 1);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
GetComponent<MeshRenderer>().materials = new[]
{
roofMaterial,
wallMaterial,
};
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3c16844aceaeec04999e14ee80b7b8e2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,169 @@
/* INFINITY CODE */
/* https://infinity-code.com */
using System;
using System.Linq;
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
/// <summary>
/// This class is added to the resulting container.\n
/// It contains all information about terrains.
/// </summary>
[Serializable]
[AddComponentMenu("")]
public class RealWorldTerrainContainer : RealWorldTerrainMonoBase
{
/// <summary>
/// Billboard start.
/// </summary>
public float billboardStart = 50;
/// <summary>
/// Detail density.
/// </summary>
public float detailDensity = 1;
/// <summary>
/// Detail distance.
/// </summary>
public float detailDistance = 80;
/// <summary>
/// The folder in the project where located terrains.
/// </summary>
public string folder;
/// <summary>
/// Count of terrains.
/// </summary>
public RealWorldTerrainVector2i terrainCount;
/// <summary>
/// Title
/// </summary>
public string title;
/// <summary>
/// Tree distance.
/// </summary>
public float treeDistance = 2000;
/// <summary>
/// The array of elements that belong to the current process of generation.
/// </summary>
public RealWorldTerrainItem[] terrains;
/// <summary>
/// Gets all instances of RealWorldTerrainContainer.
/// </summary>
/// <returns>Instances of RealWorldTerrainContainer</returns>
public static RealWorldTerrainContainer[] GetInstances()
{
return RealWorldTerrainUtils.FindObjectsOfType<RealWorldTerrainContainer>();
}
public override RealWorldTerrainItem GetItemByWorldPosition(Vector3 worldPosition)
{
for (int i = 0; i < terrains.Length; i++)
{
RealWorldTerrainItem item = terrains[i];
if (item == null) continue;
Bounds b = new Bounds(item.bounds.center, item.bounds.size);
if (b.min.x <= worldPosition.x && b.min.z <= worldPosition.z && b.max.x >= worldPosition.x && b.max.z >= worldPosition.z)
{
return item;
}
}
return null;
}
public override bool GetWorldPosition(double lng, double lat, out Vector3 worldPosition)
{
worldPosition = new Vector3();
if (!Contains(lng, lat))
{
Debug.Log("Wrong coordinates");
return false;
}
if (terrains == null || terrains.Length == 0) return false;
double mx, my;
RealWorldTerrainGeo.LatLongToMercat(lng, lat, out mx, out my);
double lX = RealWorldTerrainMath.Clamp((mx - leftMercator) / (rightMercator - leftMercator), 0, 1);
double lZ = RealWorldTerrainMath.Clamp(1 - (my - topMercator) / (bottomMercator - topMercator), 0, 1);
Bounds cb = new Bounds(bounds.center, bounds.size);
double x = cb.size.x * lX + cb.min.x;
double z = cb.size.z * lZ + cb.min.z;
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
Terrain terrain = null;
for (int i = 0; i < terrains.Length; i++)
{
RealWorldTerrainItem item = terrains[i];
Bounds b = new Bounds(item.bounds.center, item.bounds.size);
if (b.min.x <= x && b.min.z <= z && b.max.x >= x && b.max.z >= z)
{
terrain = item.terrain;
break;
}
}
if (terrain == null) return false;
double ix = (x - terrain.gameObject.transform.position.x) / terrain.terrainData.size.x;
double iz = (z - terrain.gameObject.transform.position.z) / terrain.terrainData.size.z;
double y = terrain.terrainData.GetInterpolatedHeight((float)ix, (float)iz) + terrain.gameObject.transform.position.y;
worldPosition.x = (float)x;
worldPosition.y = (float)y;
worldPosition.z = (float)z;
}
else if (prefs.resultType == RealWorldTerrainResultType.mesh)
{
bool success = false;
for (int i = 0; i < terrains.Length; i++)
{
RealWorldTerrainItem item = terrains[i];
Bounds b = new Bounds(item.bounds.center, item.bounds.size);
if (b.min.x <= x && b.min.z <= z && b.max.x >= x && b.max.z >= z)
{
float y = 0;
RaycastHit[] hits = Physics.RaycastAll(new Vector3((float)x, item.bounds.max.y + 10, (float)z), Vector3.down, float.MaxValue);
foreach (RaycastHit hit in hits)
{
if (hit.transform.gameObject.GetComponentInParent<RealWorldTerrainItem>() != null)
{
y = hit.point.y;
break;
}
}
worldPosition.x = (float)x;
worldPosition.y = y;
worldPosition.z = (float)z;
success = true;
break;
}
}
if (!success) return false;
}
return true;
}
public override bool GetWorldPosition(Vector2 coordinates, out Vector3 worldPosition)
{
return GetWorldPosition(coordinates.x, coordinates.y, out worldPosition);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 35746522d0c34a74e98f963412f0defe
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
/* INFINITY CODE */
/* https://infinity-code.com */
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
//[CreateAssetMenu(fileName = "Documentation.asset", menuName = "Create Documentation")]
public class RealWorldTerrainDocumentation : ScriptableObject
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 09989ac6b1998df44bfdcd195082f28d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
/* INFINITY CODE */
/* https://infinity-code.com */
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
[ExecuteInEditMode]
public class RealWorldTerrainDynamicBuilding : RealWorldTerrainBuilding
{
private void Awake()
{
if (baseVertices != null) Generate();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dab7fa385164831489cb84458fd83811
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
/* INFINITY CODE 2013-2019 */
/* http://www.infinity-code.com */
using InfinityCode.RealWorldTerrain.Webservices.Results;
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
[AddComponentMenu("")]
public class RealWorldTerrainGeocodingObject:MonoBehaviour
{
public RealWorldTerrainGoogleGeocodingResult info;
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9430c68e8cd249549a66febd545c986f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,227 @@
/* INFINITY CODE */
/* https://infinity-code.com */
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace InfinityCode.RealWorldTerrain
{
/// <summary>
/// This class is added to each created terrains.\n
/// It contains all information about the terrain.
/// </summary>
[Serializable]
[AddComponentMenu("")]
public class RealWorldTerrainItem : RealWorldTerrainMonoBase
{
/// <summary>
/// Reference to RealWorldTerrainContainer instance.
/// </summary>
public RealWorldTerrainContainer container;
/// <summary>
/// X index.
/// </summary>
public int x;
/// <summary>
/// Y index.
/// </summary>
public int y;
/// <summary>
/// Reversed Y index (ry = countY - y - 1).
/// </summary>
public int ry;
public bool needUpdate = false;
/// <summary>
/// Reference to MeshFilter, if result is mesh.
/// </summary>
public MeshFilter meshFilter;
/// <summary>
/// Reference to Terrain, if result is terrain.
/// </summary>
public Terrain terrain;
/// <summary>
/// Refetence to texture
/// </summary>
public Texture2D texture
{
get
{
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
#if !RTP
if (terrainData == null || terrainData.terrainLayers.Length == 0) return null;
TerrainLayer sp = terrainData.terrainLayers[0];
return sp != null? sp.diffuseTexture: null;
#else
ReliefTerrain reliefTerrain = GetComponent<ReliefTerrain>();
if (reliefTerrain == null)
{
if (terrainData == null || terrainData.terrainLayers.Length == 0) return null;
TerrainLayer sp = terrainData.terrainLayers[0];
return sp.diffuseTexture;
}
return reliefTerrain.ColorGlobal;
#endif
}
MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
if (meshRenderer == null)
{
meshRenderer = GetComponentInChildren<MeshRenderer>();
if (meshRenderer == null) return null;
}
return meshRenderer.sharedMaterial != null? meshRenderer.sharedMaterial.mainTexture as Texture2D: null;
}
set
{
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
#if !RTP
if (terrainData == null) return;
TerrainLayer[] tls = terrainData.terrainLayers;
if (tls.Length == 0) return;
if (tls[0] == null)
{
tls[0] = new TerrainLayer
{
tileSize = new Vector2(terrainData.size.x, terrainData.size.z)
};
#if UNITY_EDITOR
string path = container.folder + terrain.name + ".terrainlayer";
AssetDatabase.CreateAsset(tls[0], path);
AssetDatabase.Refresh();
tls[0] = AssetDatabase.LoadAssetAtPath<TerrainLayer>(path);
#endif
}
tls[0].diffuseTexture = value;
terrainData.terrainLayers = tls;
#else
ReliefTerrain reliefTerrain = GetComponent<ReliefTerrain>();
if (reliefTerrain == null) return;
reliefTerrain.ColorGlobal = value;
#endif
}
else
{
MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
if (meshRenderer != null) meshRenderer.sharedMaterial.mainTexture = value;
else
{
foreach (MeshRenderer mr in GetComponentsInChildren<MeshRenderer>())
{
mr.sharedMaterial.mainTexture = value;
}
}
}
}
}
/// <summary>
/// Gets TerrainData.
/// </summary>
public TerrainData terrainData
{
get
{
return terrain != null? terrain.terrainData: null;
}
}
public float GetHeightmapValueByMercator(double mx, double my)
{
float rx = (float) ((mx - leftMercator) / (rightMercator - leftMercator));
float ry = (float) ((my - topMercator) / (bottomMercator - topMercator));
return terrainData.GetInterpolatedHeight(rx, 1 - ry);
}
public override RealWorldTerrainItem GetItemByWorldPosition(Vector3 worldPosition)
{
return container.GetItemByWorldPosition(worldPosition);
}
public override bool GetWorldPosition(double lng, double lat, out Vector3 worldPosition)
{
worldPosition = new Vector3();
if (!Contains(lng, lat))
{
Debug.Log("Wrong coordinates");
return false;
}
Bounds b = new Bounds(bounds.center, bounds.size);
double mx, my;
RealWorldTerrainGeo.LatLongToMercat(lng, lat, out mx, out my);
double lX = RealWorldTerrainMath.Clamp((mx - leftMercator) / width, 0, 1);
double lZ = RealWorldTerrainMath.Clamp(1 - (my - topMercator) / height, 0, 1);
double px = b.size.x * lX + b.min.x;
double pz = b.size.z * lZ + b.min.z;
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
Terrain tr = terrain;
if (tr == null) return false;
TerrainData tData = terrainData;
Vector3 tSize = tData.size;
Vector3 position = transform.position;
if (position.x > px || position.z > pz || position.x + tSize.x < px || position.z + tSize.z < pz)
{
return false;
}
double ix = (px - terrain.gameObject.transform.position.x) / tData.size.x;
double iz = (pz - terrain.gameObject.transform.position.z) / tData.size.z;
double py = tData.GetInterpolatedHeight((float)ix, (float)iz) + position.y;
worldPosition.x = (float)px;
worldPosition.y = (float)py;
worldPosition.z = (float)pz;
}
else
{
if (b.min.x <= px && b.min.z <= pz && b.max.x >= px && b.max.z >= pz)
{
float y = 0;
RaycastHit[] hits = Physics.RaycastAll(new Vector3((float)px, bounds.max.y + 10, (float)pz), Vector3.down, float.MaxValue);
foreach (RaycastHit hit in hits)
{
if (hit.transform.gameObject.GetComponentInParent<RealWorldTerrainItem>() != null)
{
y = hit.point.y;
break;
}
}
worldPosition.x = (float)px;
worldPosition.y = y;
worldPosition.z = (float)pz;
}
else return false;
}
return true;
}
public override bool GetWorldPosition(Vector2 coordinates, out Vector3 worldPosition)
{
return GetWorldPosition(coordinates.x, coordinates.y, out worldPosition);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: fc9fccbe3f9587140a1e1601f0e73d70
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,474 @@
/* INFINITY CODE */
/* https://infinity-code.com */
using System;
using System.Collections.Generic;
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
/// <summary>
/// This class contains all the information about the terrain and Real World Terrain settings.
/// </summary>
public abstract class RealWorldTerrainMonoBase : MonoBehaviour
{
/// <summary>
/// Specifies whether to generate grass on the terrain.
/// </summary>
public bool generateGrass;
/// <summary>
/// Specifies whether rivers have been generated on the terrain.
/// </summary>
public bool generatedRivers;
/// <summary>
/// Specifies whether to generate roads on the terrain.
/// </summary>
public bool generateRoads;
/// <summary>
/// Specifies whether to create textures
/// </summary>
public bool generateTextures;
/// <summary>
/// Specifies whether to generate trees on the terrain.
/// </summary>
public bool generateTrees;
/// <summary>
/// Specifies whether to create buildings
/// </summary>
public bool generatedBuildings;
/// <summary>
/// Specifies whether to create grass
/// </summary>
public bool generatedGrass;
/// <summary>
/// Specifies whether to create textures
/// </summary>
public bool generatedTextures;
/// <summary>
/// Specifies whether to create trees
/// </summary>
public bool generatedTrees;
/// <summary>
/// Maximal value of elevation
/// </summary>
public double maxElevation;
/// <summary>
/// Minimal value of elevation
/// </summary>
public double minElevation;
/// <summary>
/// Reference to the preferences
/// </summary>
public RealWorldTerrainPrefsBase prefs;
/// <summary>
/// Scale of terrains
/// </summary>
public Vector3 scale;
/// <summary>
/// Size of terrains in world units
/// </summary>
public Vector3 size;
/// <summary>
/// Top latitude
/// </summary>
public double topLatitude;
/// <summary>
/// Top latitude in Mercator projection (0-1)
/// </summary>
public double topMercator;
/// <summary>
/// Left longitude
/// </summary>
public double leftLongitude;
/// <summary>
/// Left longitude in Mercator projection (0-1)
/// </summary>
public double leftMercator;
/// <summary>
/// Bottom latitude
/// </summary>
public double bottomLatitude;
/// <summary>
/// Bottom latitude in Mercator projection (0-1)
/// </summary>
public double bottomMercator;
/// <summary>
/// Right longitude
/// </summary>
public double rightLongitude;
/// <summary>
/// Right longitude in Mercator projection (0-1)
/// </summary>
public double rightMercator;
/// <summary>
/// Width. Right longitude - left longitude
/// </summary>
public double width;
/// <summary>
/// Height. Top latitude - bottom latitude
/// </summary>
public double height;
#if BUILDR2
public List<RealWorldTerrainBuildR2Material> buildR2Facades;
#endif
private Dictionary<string, object> customFields;
/// <summary>
/// The width of the terrain in Mercator projection units.
/// </summary>
public double mercatorWidth;
/// <summary>
/// The height of the terrain in Mercator projection units.
/// </summary>
public double mercatorHeight;
/// <summary>
/// Gets or sets the value associated with the specified key in the custom fields.
/// </summary>
/// <param name="key">The key of the value to get or set.</param>
/// <returns>The value associated with the specified key.</returns>
public object this[string key]
{
get
{
if (customFields == null) return null;
object value;
if (!customFields.TryGetValue(key, out value)) return null;
return value;
}
set
{
if (customFields == null) customFields = new Dictionary<string, object>();
if (value != null) customFields[key] = value;
else customFields.Remove(key);
}
}
/// <summary>
/// Gets the bounds of the terrain.
/// </summary>
public Bounds bounds
{
get
{
return new Bounds(transform.position + size / 2, size);
}
}
/// <summary>
/// Clear custom fields.
/// </summary>
public void ClearCustomFields()
{
customFields = null;
}
/// <summary>
/// Checks whether the coordinate in terrain area.
/// </summary>
/// <param name="coordinates">Coordinate</param>
/// <returns>True - coordinate in area, False - otherwise.</returns>
public bool Contains(Vector2 coordinates)
{
return Contains(coordinates.x, coordinates.y);
}
/// <summary>
/// Checks whether the coordinate in terrain area.
/// </summary>
/// <param name="lng">Longitude</param>
/// <param name="lat">Latitude</param>
/// <returns>True - coordinate in area, False - otherwise.</returns>
public bool Contains(double lng, double lat)
{
return leftLongitude <= lng && rightLongitude >= lng && topLatitude >= lat && bottomLatitude <= lat;
}
/// <summary>
/// Get altitude by location (coordinates).
/// </summary>
/// <param name="lng">Longitude</param>
/// <param name="lat">Latitude</param>
/// <returns>Altitude (meters)</returns>
public double GetAltitudeByCoordinates(double lng, double lat)
{
if (!Contains(lng, lat)) return 0;
Vector3 worldPosition;
GetWorldPosition(lng, lat, out worldPosition);
Bounds b = new Bounds(bounds.center, bounds.size);
Vector3 offset = worldPosition - b.min;
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
RealWorldTerrainItem currentItem = GetItemByWorldPosition(worldPosition);
return offset.y / currentItem.terrainData.size.y * (currentItem.maxElevation - currentItem.minElevation);
}
return worldPosition.y / b.size.y * (maxElevation - minElevation) + minElevation;
}
/// <summary>
/// Get altitude by location (coordinates).
/// </summary>
/// <param name="lng">Longitude</param>
/// <param name="lat">Latitude</param>
/// <returns>Altitude (meters)</returns>
[Obsolete("Use GetAltitudeByCoordinates")]
public double GetAltitudeByLocation(double lng, double lat)
{
return GetAltitudeByCoordinates(lng, lat);
}
/// <summary>
/// Get altitude by Unity World Position.
/// </summary>
/// <param name="worldPosition">Unity World Position</param>
/// <returns>Altitude (meters)</returns>
public double GetAltitudeByWorldPosition(Vector3 worldPosition)
{
Bounds b = new Bounds(bounds.center, bounds.size);
Vector3 offset = worldPosition - b.min;
if (offset.x < 0 || offset.z < 0) return 0;
if (offset.x > b.size.x || offset.z > b.size.z) return 0;
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
RealWorldTerrainItem currentItem = GetItemByWorldPosition(worldPosition);
return offset.y / currentItem.terrainData.size.y * (currentItem.maxElevation - currentItem.minElevation);
}
return worldPosition.y / b.size.y * (maxElevation - minElevation) + minElevation;
}
/// <summary>
/// Get coordinates under mouse cursor
/// </summary>
/// <param name="coordinates">Geographical coordinates</param>
/// <param name="cam">Camera</param>
/// <returns>True - success, False - otherwise</returns>
public bool GetCoordinatesUnderCursor(out Vector2 coordinates, Camera cam = null)
{
return GetCoordinatesByScreenPosition(Input.mousePosition, out coordinates, cam);
}
/// <summary>
/// Converts the screen coordinates into geographic coordinates.
/// </summary>
/// <param name="screenPosition">Position in screen space</param>
/// <param name="coordinates">Geographic coordinates</param>
/// <param name="cam">Camera</param>
/// <returns>True - screen coordinates on terrains, False - otherwise</returns>
public bool GetCoordinatesByScreenPosition(Vector2 screenPosition, out Vector2 coordinates, Camera cam = null)
{
if (cam == null) cam = Camera.main;
coordinates = Vector2.zero;
RaycastHit[] hits = Physics.RaycastAll(cam.ScreenPointToRay(screenPosition));
for (int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];
if (hit.collider is TerrainCollider || hit.collider is MeshCollider)
{
RealWorldTerrainItem item = hit.transform.GetComponent<RealWorldTerrainItem>();
if (item != null) return GetCoordinatesByWorldPosition(hit.point, out coordinates);
}
}
return false;
}
/// <summary>
/// Converts the screen coordinates into geographic coordinates.
/// </summary>
/// <param name="screenPosition">Position in screen space</param>
/// <param name="longitude">Longitude</param>
/// <param name="latitude">Latitude</param>
/// <param name="altitude">Altitude</param>
/// <param name="cam">Camera</param>
/// <returns>True - screen coordinates on terrains, False - otherwise</returns>
public bool GetCoordinatesByScreenPosition(Vector2 screenPosition, out double longitude, out double latitude, out double altitude, Camera cam = null)
{
if (cam == null) cam = Camera.main;
longitude = latitude = altitude = 0;
RaycastHit[] hits = Physics.RaycastAll(cam.ScreenPointToRay(screenPosition));
for (int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];
if (hit.collider is TerrainCollider || hit.collider is MeshCollider)
{
RealWorldTerrainItem item = hit.transform.GetComponent<RealWorldTerrainItem>();
if (item != null) return GetCoordinatesByWorldPosition(hit.point, out longitude, out latitude, out altitude);
}
}
return false;
}
/// <summary>
/// Converts the world coordinates into geographic coordinates.
/// </summary>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <param name="coordinates">Geographic coordinates</param>
/// <returns>True - world coordinates on terrains, False - otherwise</returns>
public bool GetCoordinatesByWorldPosition(Vector3 worldPosition, out Vector2 coordinates)
{
coordinates = new Vector2();
double lng, lat;
bool result = GetCoordinatesByWorldPosition(worldPosition, out lng, out lat);
coordinates.x = (float)lng;
coordinates.y = (float)lat;
return result;
}
/// <summary>
/// Converts the world coordinates into geographic coordinates.
/// </summary>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <param name="longitude">Longitude</param>
/// <param name="latitude">Latitude</param>
/// <returns>True - world coordinates on terrains, False - otherwise</returns>
public bool GetCoordinatesByWorldPosition(Vector3 worldPosition, out double longitude, out double latitude)
{
Bounds b = new Bounds(bounds.center, bounds.size);
double wrx = (worldPosition.x - b.min.x) / b.size.x;
double wrz = (b.max.z - worldPosition.z) / b.size.z;
double px = (rightMercator - leftMercator) * wrx + leftMercator;
double pz = (bottomMercator - topMercator) * wrz + topMercator;
RealWorldTerrainGeo.MercatToLatLong(px, pz, out longitude, out latitude);
return b.Contains(worldPosition);
}
/// <summary>
/// Converts the world coordinates into geographic coordinates.
/// </summary>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <param name="longitude">Longitude</param>
/// <param name="latitude">Latitude</param>
/// <param name="altitude">Altitude</param>
/// <returns>True - world coordinates on terrains, False - otherwise</returns>
public bool GetCoordinatesByWorldPosition(Vector3 worldPosition, out double longitude, out double latitude, out double altitude)
{
altitude = 0;
Bounds b = new Bounds(bounds.center, bounds.size);
double wrx = (worldPosition.x - b.min.x) / b.size.x;
double wrz = (b.max.z - worldPosition.z) / b.size.z;
double px1 = (rightMercator - leftMercator) * wrx + leftMercator;
double pz = (bottomMercator - topMercator) * wrz + topMercator;
RealWorldTerrainGeo.MercatToLatLong(px1, pz, out longitude, out latitude);
if (b.min.x > worldPosition.x || b.max.x < worldPosition.x || b.min.z > worldPosition.z || b.max.z < worldPosition.z)
{
return false;
}
Vector3 offset = worldPosition - b.min;
if (prefs.resultType == RealWorldTerrainResultType.terrain)
{
RealWorldTerrainItem currentItem = GetItemByWorldPosition(worldPosition);
altitude = (offset.y + currentItem.transform.position.y) / currentItem.terrainData.size.y * (currentItem.maxElevation - currentItem.minElevation) + currentItem.minElevation;
}
else
{
altitude = worldPosition.y / b.size.y * (maxElevation - minElevation) + minElevation;
}
return true;
}
/// <summary>
/// Get RealWorldTerrainItem by Unity World Position.
/// </summary>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <returns>Instance of RealWorldTerrainItem</returns>
public abstract RealWorldTerrainItem GetItemByWorldPosition(Vector3 worldPosition);
/// <summary>
/// Get Unity World Position by geographic coordinates.
/// </summary>
/// <param name="lng">Longitude</param>
/// <param name="lat">Latitde</param>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <returns>True - success, False - otherwise</returns>
public abstract bool GetWorldPosition(double lng, double lat, out Vector3 worldPosition);
/// <summary>
/// Get Unity World Position by geographic coordinates.
/// </summary>
/// <param name="lng">Longitude</param>
/// <param name="lat">Latitude</param>
/// <param name="altitude">Altitude</param>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <returns>True - success, False - otherwise</returns>
public bool GetWorldPosition(double lng, double lat, double altitude, out Vector3 worldPosition)
{
bool result = GetWorldPosition(lng, lat, out worldPosition);
if (result) worldPosition.y = (float)(bounds.size.y * ((altitude - minElevation) / (maxElevation - minElevation)));
return result;
}
/// <summary>
/// Get Unity World Position by geographic coordinates.
/// </summary>
/// <param name="coordinates">Geographic coordinates</param>
/// <param name="worldPosition">Position in Unity World Space</param>
/// <returns></returns>
public abstract bool GetWorldPosition(Vector2 coordinates, out Vector3 worldPosition);
public void SetCoordinates(double x1, double y1, double x2, double y2, double tlx, double tly, double brx, double bry)
{
leftMercator = x1;
topMercator = y1;
rightMercator = x2;
bottomMercator = y2;
leftLongitude = tlx;
rightLongitude = brx;
topLatitude = tly;
bottomLatitude = bry;
width = rightLongitude - leftLongitude;
height = bottomLatitude - topLatitude;
mercatorWidth = rightMercator - leftMercator;
mercatorHeight = bottomMercator - topMercator;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6036b77012379cd4f817092bdac723e1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
/* INFINITY CODE 2013-2019 */
/* http://www.infinity-code.com */
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
/// <summary>
/// Class of POI instance.
/// </summary>
public class RealWorldTerrainPOIItem : MonoBehaviour
{
/// <summary>
/// The title of the POI.
/// </summary>
public string title;
/// <summary>
/// Longitude.
/// </summary>
public double x;
/// <summary>
/// Latitude.
/// </summary>
public double y;
/// <summary>
/// Altitude
/// </summary>
public float altitude;
/// <summary>
/// Sets POI prefs.
/// </summary>
/// <param name="poi">Reference to POI.</param>
public void SetPrefs(RealWorldTerrainPOI poi)
{
title = poi.title;
x = poi.x;
y = poi.y;
altitude = poi.altitude;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 374f4970e8d22fd42a12bb3c64287f73
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
/* INFINITY CODE 2013-2019 */
/* http://www.infinity-code.com */
using UnityEngine;
namespace InfinityCode.RealWorldTerrain
{
[AddComponentMenu("")]
public class RealWorldTerrainRoadArchitectNode : MonoBehaviour
{
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0dffe5af2a2b3ff44b95e808bdbab653
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: