Experimenting with texture-coordinate conversion

This commit is contained in:
JR-Morgan
2021-12-02 13:23:29 +00:00
parent 2e73558cde
commit b8cb1ca97a
3 changed files with 95 additions and 61 deletions
@@ -4,13 +4,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Objects.Other;
using Objects.Primitive;
using Speckle.ConnectorUnity;
using Speckle.Core.Models;
using UnityEditor;
using UnityEngine;
using Mesh = Objects.Geometry.Mesh;
using Object = UnityEngine.Object;
using SColor = System.Drawing.Color;
namespace Objects.Converter.Unity
{
@@ -57,14 +57,14 @@ namespace Objects.Converter.Unity
/// </summary>
/// <param name="arr"></param>
/// <returns></returns>
public Vector3[] ArrayToPoints(IEnumerable<double> arr, string units)
public Vector3[] ArrayToPoints(IList<double> arr, string units)
{
if (arr.Count() % 3 != 0) throw new Exception("Array malformed: length%3 != 0.");
if (arr.Count % 3 != 0) throw new Exception("Array malformed: length%3 != 0.");
Vector3[] points = new Vector3[arr.Count() / 3];
var asArray = arr.ToArray();
for (int i = 2, k = 0; i < arr.Count(); i += 3)
points[k++] = VectorByCoordinates(asArray[i - 2], asArray[i - 1], asArray[i], units);
Vector3[] points = new Vector3[arr.Count / 3];
for (int i = 2, k = 0; i < arr.Count; i += 3)
points[k++] = VectorByCoordinates(arr[i - 2], arr[i - 1], arr[i], units);
return points;
@@ -109,53 +109,62 @@ namespace Objects.Converter.Unity
/// <summary>
/// Converts a Speckle mesh to a GameObject with a mesh renderer
/// Converts the <see cref="MeshFilter"/> component on <paramref name="go"/> into a Speckle <see cref="Mesh"/>
/// </summary>
/// <param name="speckleMesh"></param>
/// <returns></returns>
/// <param name="go">The Unity <see cref="GameObject"/> to convert</param>
/// <returns>The converted <see cref="Mesh"/>, <see langword="null"/> if no <see cref="MeshFilter"/> on <paramref name="go"/> exists</returns>
public Mesh MeshToSpeckle(GameObject go)
{
//TODO: support multiple filters?
var filter = go.GetComponent<MeshFilter>();
if (filter == null)
if (filter == null) return null;
var nativeMesh = filter.mesh;
var nTriangles = nativeMesh.triangles;
List<int> sFaces = new List<int>(nTriangles.Length * 4);
for (int i = 2; i < nTriangles.Length; i += 3)
{
return null;
sFaces.Add(0); //Triangle cardinality indicator
sFaces.Add(nTriangles[i]);
sFaces.Add(nTriangles[i - 1]);
sFaces.Add(nTriangles[i - 2]);
}
//convert triangle array into speckleMesh faces
List<int> faces = new List<int>();
int i = 0;
//store them here, makes it like 1000000x faster?
var triangles = filter.mesh.triangles;
while (i < triangles.Length)
var nVertices = nativeMesh.vertices;
List<double> sVertices = new List<double>(nVertices.Length * 3);
foreach (var vertex in nVertices)
{
faces.Add(0);
var p = go.transform.TransformPoint(vertex);
sVertices.Add(p.x);
sVertices.Add(p.y);
sVertices.Add(p.z);
}
var nColors = nativeMesh.colors;
List<int> sColors = new List<int>(nColors.Length);
sColors.AddRange(nColors.Select(c => c.ToIntColor()));
faces.Add(triangles[i + 0]);
faces.Add(triangles[i + 2]);
faces.Add(triangles[i + 1]);
i += 3;
var nTexCoords = nativeMesh.uv;
List<double> sTexCoords = new List<double>(nTexCoords.Length * 2);
foreach (var uv in nTexCoords)
{
sTexCoords.Add(uv.x);
sTexCoords.Add(uv.y);
}
var mesh = new Mesh();
// get the speckle data from the go here
// so that if the go comes from speckle, typed props will get overridden below
AttachUnityProperties(mesh, go);
mesh.vertices = sVertices;
mesh.faces = sFaces;
mesh.colors = sColors;
mesh.textureCoordinates = sTexCoords;
mesh.units = ModelUnits;
var vertices = filter.mesh.vertices;
foreach (var vertex in vertices)
{
var p = go.transform.TransformPoint(vertex);
var sp = PointToSpeckle(p);
mesh.vertices.Add(sp.x);
mesh.vertices.Add(sp.y);
mesh.vertices.Add(sp.z);
}
mesh.faces = faces;
return mesh;
}
#endregion
@@ -181,7 +190,7 @@ namespace Objects.Converter.Unity
}
/// <summary>
/// Converts a Speckle point to a GameObject with a line renderer
/// Converts a Speckle <paramref name="point"/> to a <see cref="GameObject"/> with a <see cref="LineRenderer"/>
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
@@ -189,13 +198,13 @@ namespace Objects.Converter.Unity
{
Vector3 newPt = VectorByCoordinates(point.x, point.y, point.z, point.units);
var go = NewPointBasedGameObject(new Vector3[2] { newPt, newPt }, point.speckle_type);
var go = NewPointBasedGameObject(new Vector3[] { newPt, newPt }, point.speckle_type);
return go;
}
/// <summary>
/// Converts a Speckle line to a GameObject with a line renderer
/// Converts a Speckle <paramref name="line"/> to a <see cref="GameObject"/> with a <see cref="LineRenderer"/>
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
@@ -208,31 +217,31 @@ namespace Objects.Converter.Unity
}
/// <summary>
/// Converts a Speckle polyline to a GameObject with a line renderer
/// Converts a Speckle <paramref name="polyline"/> to a <see cref="GameObject"/> with a <see cref="LineRenderer"/>
/// </summary>
/// <param name="polyline"></param>
/// <returns></returns>
public GameObject PolylineToNative(Polyline polyline)
{
var points = polyline.points.Select(x => VectorFromPoint(x));
var points = polyline.GetPoints().Select(VectorFromPoint);
var go = NewPointBasedGameObject(points.ToArray(), polyline.speckle_type);
return go;
}
/// <summary>
/// Converts a Speckle curve to a GameObject with a line renderer
/// Converts a Speckle <paramref name="curve"/> to a <see cref="GameObject"/> with a <see cref="LineRenderer"/>
/// </summary>
/// <param name="curve"></param>
/// <returns></returns>
public GameObject CurveToNative(Curve curve)
{
var points = ArrayToPoints(curve.points, curve.units);
var go = NewPointBasedGameObject(points.ToArray(), curve.speckle_type);
var go = NewPointBasedGameObject(points, curve.speckle_type);
return go;
}
public GameObject MeshToNative(Base speckleMeshObject)
{
if (!(speckleMeshObject["displayMesh"] is Mesh))
@@ -242,11 +251,11 @@ namespace Objects.Converter.Unity
speckleMeshObject["renderMaterial"] as RenderMaterial, speckleMeshObject.GetMembers());
}
/// <summary>
/// Converts a Speckle mesh to a GameObject with a mesh renderer
/// Converts <paramref name="speckleMesh"/> to a <see cref="GameObject"/> with a <see cref="MeshRenderer"/>
/// </summary>
/// <param name="speckleMesh">Mesh to convert</param>
/// <param name="renderMaterial">If provided will override the renderMaterial on the mesh itself</param>
/// <param name="properties">If provided will override the properties on the mesh itself</param>
/// <param name="renderMaterial">If provided, will override the renderMaterial on the mesh itself</param>
/// <param name="properties">If provided, will override the properties on the mesh itself</param>
/// <returns></returns>
public GameObject MeshToNative(
Mesh speckleMesh, RenderMaterial renderMaterial = null,
@@ -257,10 +266,10 @@ namespace Objects.Converter.Unity
{
return null;
}
var recenterMeshTransforms = true; //TODO: figure out how best to change this?
speckleMesh.AlignVerticesWithTexCoordsByIndex();
var verts = ArrayToPoints(speckleMesh.vertices, speckleMesh.units);
@@ -270,15 +279,17 @@ namespace Objects.Converter.Unity
// TODO: Check if this is causing issues with normals for mesh
while (i < speckleMesh.faces.Count)
{
if (speckleMesh.faces[i] == 0)
int n = speckleMesh.faces[i];
if (n < 3) n += 3; // 0 -> 3, 1 - > 4
if (n == 3)
{
//Triangles
tris.Add(speckleMesh.faces[i + 1]);
tris.Add(speckleMesh.faces[i + 3]);
tris.Add(speckleMesh.faces[i + 2]);
i += 4;
}
else
else if (n == 4)
{
//Quads to triangles
tris.Add(speckleMesh.faces[i + 1]);
@@ -288,12 +299,16 @@ namespace Objects.Converter.Unity
tris.Add(speckleMesh.faces[i + 1]);
tris.Add(speckleMesh.faces[i + 4]);
tris.Add(speckleMesh.faces[i + 3]);
i += 5;
}
else
{
//TODO n-gon triangulation, for now n-gon faces will be ignored
}
i += n + 1;
}
var go = new GameObject { name = speckleMesh.speckle_type };
var mesh = new UnityEngine.Mesh { name = speckleMesh.speckle_type };
@@ -322,18 +337,37 @@ namespace Objects.Converter.Unity
verts[l] -= meshBounds.center;
}
}
mesh.SetVertices(verts);
mesh.SetTriangles(tris, 0);
if (speckleMesh.bbox != null)
//Set texture coordinates
bool hasValidUVs = speckleMesh.TextureCoordinatesCount == speckleMesh.VerticesCount;
if(speckleMesh.textureCoordinates.Count > 0 && !hasValidUVs) Debug.LogWarning($"Expected number of UV coordinates to equal vertices. Got {speckleMesh.TextureCoordinatesCount} expected {speckleMesh.VerticesCount}. \nID = {speckleMesh.id}", mesh);
if (hasValidUVs)
{
var uv = new List<Vector2>(speckleMesh.TextureCoordinatesCount);
for (int j = 0; j < speckleMesh.TextureCoordinatesCount; j++)
{
var (u, v) = speckleMesh.GetTextureCoordinate(j);
uv.Add(new Vector2((float)u,(float)v));
}
mesh.SetUVs(0, uv);
}
else if (speckleMesh.bbox != null)
{
//Attempt to generate some crude UV coordinates using bbox
var uv = GenerateUV(verts, (float)speckleMesh.bbox.xSize.Length, (float)speckleMesh.bbox.ySize.Length).ToList();
mesh.SetUVs(0, uv);
}
//Set vertex colors
if (speckleMesh.colors.Count == speckleMesh.VerticesCount)
{
static Color ToUnityColor(SColor color) => new Color(color.R, color.G, color.B, color.A);
var colors = speckleMesh.colors.Select(c => ToUnityColor(SColor.FromArgb(c))).ToList();
mesh.SetColors(colors);
}
// BUG: causing some funky issues with meshes
Binary file not shown.
Binary file not shown.