using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Objects.Geometry
{
///
/// Base definition for all rendered stream objects. Any Speckle object that needs to be
/// displayed with a game object should inherit from this class.
///
public abstract class UnityGeometry
{
///
/// The gameobject that will be displayed. The Transform parent will be assigned
/// by the SpeckleUnityReceiver.
///
public GameObject gameObject;
///
///
///
public Renderer renderer;
///
///
///
public UnityGeometry()
{
gameObject = new GameObject();
}
}
///
/// A stream object represented as a gameobject with a MeshRenderer. Also adds a
/// MeshCollider to the object. The material is assigned by the SpeckleUnityReceiver.
///
public class UnityMesh : UnityGeometry
{
///
///
///
public static bool RecentreMeshTransforms = false;
///
///
///
public UnityEngine.Mesh mesh;
///
///
///
public MeshRenderer meshRenderer;
///
///
///
///
///
///
public UnityMesh(string type, Vector3[] verts, int[] tris) : base()
{
gameObject.name = type;
mesh = gameObject.AddComponent().mesh;
renderer = meshRenderer = gameObject.AddComponent();
if (verts.Length >= 65535)
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
// center transform pivot according to the bounds of the model
if (RecentreMeshTransforms)
{
Bounds meshBounds = new Bounds();
meshBounds.center = verts[0];
for (int i = 1; i < verts.Length; i++)
{
meshBounds.Encapsulate(verts[i]);
}
gameObject.transform.position = meshBounds.center;
// offset mesh vertices
for (int i = 0; i < verts.Length; i++)
{
verts[i] -= meshBounds.center;
}
}
// assign mesh properties
mesh.vertices = verts;
mesh.triangles = tris;
mesh.RecalculateNormals();
mesh.RecalculateTangents();
//generate uvs doesn't work as intended. Leaving out for now
//GenerateUVs (ref mesh);
//Add mesh collider
MeshCollider mc = gameObject.AddComponent();
mc.sharedMesh = mesh;
}
///
///
///
///
///
protected void GenerateUVs(ref UnityEngine.Mesh mesh)
{
Vector3 p = Vector3.up;
Vector3 u = Vector3.Cross(p, Vector3.forward);
if (Vector3.Dot(u, u) < 0.001f)
{
u = Vector3.right;
}
else
{
u = Vector3.Normalize(u);
}
Vector3 v = Vector3.Normalize(Vector3.Cross(p, u));
Vector3[] vertexs = mesh.vertices;
int[] tris = mesh.triangles;
Vector2[] uvs = new Vector2[vertexs.Length];
for (int i = 0; i < tris.Length; i += 3)
{
Vector3 a = vertexs[tris[i]];
Vector3 b = vertexs[tris[i + 1]];
Vector3 c = vertexs[tris[i + 2]];
Vector3 side1 = b - a;
Vector3 side2 = c - a;
Vector3 N = Vector3.Cross(side1, side2);
N = new Vector3(Mathf.Abs(N.normalized.x), Mathf.Abs(N.normalized.y), Mathf.Abs(N.normalized.z));
if (N.x > N.y && N.x > N.z)
{
uvs[tris[i]] = new Vector2(vertexs[tris[i]].z, vertexs[tris[i]].y);
uvs[tris[i + 1]] = new Vector2(vertexs[tris[i + 1]].z, vertexs[tris[i + 1]].y);
uvs[tris[i + 2]] = new Vector2(vertexs[tris[i + 2]].z, vertexs[tris[i + 2]].y);
}
else if (N.y > N.x && N.y > N.z)
{
uvs[tris[i]] = new Vector2(vertexs[tris[i]].x, vertexs[tris[i]].z);
uvs[tris[i + 1]] = new Vector2(vertexs[tris[i + 1]].x, vertexs[tris[i + 1]].z);
uvs[tris[i + 2]] = new Vector2(vertexs[tris[i + 2]].x, vertexs[tris[i + 2]].z);
}
else if (N.z > N.x && N.z > N.y)
{
uvs[tris[i]] = new Vector2(vertexs[tris[i]].x, vertexs[tris[i]].y);
uvs[tris[i + 1]] = new Vector2(vertexs[tris[i + 1]].x, vertexs[tris[i + 1]].y);
uvs[tris[i + 2]] = new Vector2(vertexs[tris[i + 2]].x, vertexs[tris[i + 2]].y);
}
}
mesh.uv = uvs;
}
}
///
/// Used to display lines, curves, or polylines as a game object with a LineRenderer.
/// The material is assigned by the SpeckleUnityReceiver.
///
public class UnityPolyline : UnityGeometry
{
///
///
///
public static float LineWidth = 1;
///
///
///
public LineRenderer lineRenderer;
///
///
///
///
///
public UnityPolyline(string type, Vector3[] points) : base()
{
gameObject.name = type;
//create line renderer
renderer = lineRenderer = gameObject.AddComponent();
lineRenderer.positionCount = points.Length;
lineRenderer.SetPositions(points);
lineRenderer.numCornerVertices = lineRenderer.numCapVertices = 8;
lineRenderer.startWidth = lineRenderer.endWidth = LineWidth;
}
}
///
/// Display Point. Uses a line renderer for display. The material is assigned by the
/// SpeckleUnityReceiver.
///
public class UnityPoint : UnityGeometry
{
///
///
///
public static float PointDiameter = 1;
///
///
///
public Vector3 point;
///
///
///
public LineRenderer lineRenderer;
///
///
///
///
///
public UnityPoint(string type, Vector3 point) : base()
{
gameObject.name = type;
this.point = point;
//create line renderer
renderer = lineRenderer = gameObject.AddComponent();
lineRenderer.SetPositions(new Vector3[2] { point, point });
lineRenderer.numCornerVertices = lineRenderer.numCapVertices = 8;
lineRenderer.startWidth = lineRenderer.endWidth = PointDiameter;
}
}
}