Co-authored-by: azyges <aaaaaa@aaa.aaa> Co-authored-by: cake <admin@cakeandbanana.nl> Co-authored-by: defnotken <itsdefnotken@gmail.com> Reviewed-on: #131
955 lines
31 KiB
C#
955 lines
31 KiB
C#
#region License
|
|
/*
|
|
MIT License
|
|
|
|
Copyright(c) 2017-2018 Mattias Edlund
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using MeshDecimator.Math;
|
|
|
|
namespace MeshDecimator
|
|
{
|
|
/// <summary>
|
|
/// A mesh.
|
|
/// </summary>
|
|
public sealed class Mesh
|
|
{
|
|
#region Consts
|
|
/// <summary>
|
|
/// The count of supported UV channels.
|
|
/// </summary>
|
|
public const int UVChannelCount = 4;
|
|
#endregion
|
|
|
|
#region Fields
|
|
private Vector3d[] vertices = null;
|
|
private int[][] indices = null;
|
|
private Vector3[] normals = null;
|
|
private Vector4[] tangents = null;
|
|
private Vector2[][] uvs2D = null;
|
|
private Vector3[][] uvs3D = null;
|
|
private Vector4[][] uvs4D = null;
|
|
private Vector4[] colors = null;
|
|
private BoneWeight[] boneWeights = null;
|
|
|
|
private static readonly int[] emptyIndices = new int[0];
|
|
#endregion
|
|
|
|
#region Properties
|
|
/// <summary>
|
|
/// Gets the count of vertices of this mesh.
|
|
/// </summary>
|
|
public int VertexCount
|
|
{
|
|
get { return vertices.Length; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the count of submeshes in this mesh.
|
|
/// </summary>
|
|
public int SubMeshCount
|
|
{
|
|
get { return indices.Length; }
|
|
set
|
|
{
|
|
if (value <= 0)
|
|
throw new ArgumentOutOfRangeException("value");
|
|
|
|
int[][] newIndices = new int[value][];
|
|
Array.Copy(indices, 0, newIndices, 0, MathHelper.Min(indices.Length, newIndices.Length));
|
|
indices = newIndices;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the total count of triangles in this mesh.
|
|
/// </summary>
|
|
public int TriangleCount
|
|
{
|
|
get
|
|
{
|
|
int triangleCount = 0;
|
|
for (int i = 0; i < indices.Length; i++)
|
|
{
|
|
if (indices[i] != null)
|
|
{
|
|
triangleCount += indices[i].Length / 3;
|
|
}
|
|
}
|
|
return triangleCount;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the vertices for this mesh. Note that this resets all other vertex attributes.
|
|
/// </summary>
|
|
public Vector3d[] Vertices
|
|
{
|
|
get { return vertices; }
|
|
set
|
|
{
|
|
if (value == null)
|
|
throw new ArgumentNullException("value");
|
|
|
|
vertices = value;
|
|
ClearVertexAttributes();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the combined indices for this mesh. Once set, the sub-mesh count gets set to 1.
|
|
/// </summary>
|
|
public int[] Indices
|
|
{
|
|
get
|
|
{
|
|
if (indices.Length == 1)
|
|
{
|
|
return indices[0] ?? emptyIndices;
|
|
}
|
|
else
|
|
{
|
|
List<int> indexList = new List<int>(TriangleCount * 3);
|
|
for (int i = 0; i < indices.Length; i++)
|
|
{
|
|
if (indices[i] != null)
|
|
{
|
|
indexList.AddRange(indices[i]);
|
|
}
|
|
}
|
|
return indexList.ToArray();
|
|
}
|
|
}
|
|
set
|
|
{
|
|
if (value == null)
|
|
throw new ArgumentNullException("value");
|
|
else if ((value.Length % 3) != 0)
|
|
throw new ArgumentException("The index count must be multiple by 3.", "value");
|
|
|
|
SubMeshCount = 1;
|
|
SetIndices(0, value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the normals for this mesh.
|
|
/// </summary>
|
|
public Vector3[] Normals
|
|
{
|
|
get { return normals; }
|
|
set
|
|
{
|
|
if (value != null && value.Length != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex normals must be as many as the vertices. Assigned: {0} Require: {1}", value.Length, vertices.Length));
|
|
|
|
normals = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the tangents for this mesh.
|
|
/// </summary>
|
|
public Vector4[] Tangents
|
|
{
|
|
get { return tangents; }
|
|
set
|
|
{
|
|
if (value != null && value.Length != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex tangents must be as many as the vertices. Assigned: {0} Require: {1}", value.Length, vertices.Length));
|
|
|
|
tangents = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the first UV set for this mesh.
|
|
/// </summary>
|
|
public Vector2[] UV1
|
|
{
|
|
get { return GetUVs2D(0); }
|
|
set { SetUVs(0, value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the second UV set for this mesh.
|
|
/// </summary>
|
|
public Vector2[] UV2
|
|
{
|
|
get { return GetUVs2D(1); }
|
|
set { SetUVs(1, value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the third UV set for this mesh.
|
|
/// </summary>
|
|
public Vector2[] UV3
|
|
{
|
|
get { return GetUVs2D(2); }
|
|
set { SetUVs(2, value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the fourth UV set for this mesh.
|
|
/// </summary>
|
|
public Vector2[] UV4
|
|
{
|
|
get { return GetUVs2D(3); }
|
|
set { SetUVs(3, value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the vertex colors for this mesh.
|
|
/// </summary>
|
|
public Vector4[] Colors
|
|
{
|
|
get { return colors; }
|
|
set
|
|
{
|
|
if (value != null && value.Length != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex colors must be as many as the vertices. Assigned: {0} Require: {1}", value.Length, vertices.Length));
|
|
|
|
colors = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the vertex bone weights for this mesh.
|
|
/// </summary>
|
|
public BoneWeight[] BoneWeights
|
|
{
|
|
get { return boneWeights; }
|
|
set
|
|
{
|
|
if (value != null && value.Length != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex bone weights must be as many as the vertices. Assigned: {0} Require: {1}", value.Length, vertices.Length));
|
|
|
|
boneWeights = value;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Constructor
|
|
/// <summary>
|
|
/// Creates a new mesh.
|
|
/// </summary>
|
|
/// <param name="vertices">The mesh vertices.</param>
|
|
/// <param name="indices">The mesh indices.</param>
|
|
public Mesh(Vector3d[] vertices, int[] indices)
|
|
{
|
|
if (vertices == null)
|
|
throw new ArgumentNullException("vertices");
|
|
else if (indices == null)
|
|
throw new ArgumentNullException("indices");
|
|
else if ((indices.Length % 3) != 0)
|
|
throw new ArgumentException("The index count must be multiple by 3.", "indices");
|
|
|
|
this.vertices = vertices;
|
|
this.indices = new int[1][];
|
|
this.indices[0] = indices;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new mesh.
|
|
/// </summary>
|
|
/// <param name="vertices">The mesh vertices.</param>
|
|
/// <param name="indices">The mesh indices.</param>
|
|
public Mesh(Vector3d[] vertices, int[][] indices)
|
|
{
|
|
if (vertices == null)
|
|
throw new ArgumentNullException("vertices");
|
|
else if (indices == null)
|
|
throw new ArgumentNullException("indices");
|
|
|
|
for (int i = 0; i < indices.Length; i++)
|
|
{
|
|
if (indices[i] != null && (indices[i].Length % 3) != 0)
|
|
throw new ArgumentException(string.Format("The index count must be multiple by 3 at sub-mesh index {0}.", i), "indices");
|
|
}
|
|
|
|
this.vertices = vertices;
|
|
this.indices = indices;
|
|
}
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
private void ClearVertexAttributes()
|
|
{
|
|
normals = null;
|
|
tangents = null;
|
|
uvs2D = null;
|
|
uvs3D = null;
|
|
uvs4D = null;
|
|
colors = null;
|
|
boneWeights = null;
|
|
}
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
#region Recalculate Normals
|
|
/// <summary>
|
|
/// Recalculates the normals for this mesh smoothly.
|
|
/// </summary>
|
|
public void RecalculateNormals()
|
|
{
|
|
int vertexCount = vertices.Length;
|
|
Vector3[] normals = new Vector3[vertexCount];
|
|
|
|
int subMeshCount = this.indices.Length;
|
|
for (int subMeshIndex = 0; subMeshIndex < subMeshCount; subMeshIndex++)
|
|
{
|
|
int[] indices = this.indices[subMeshIndex];
|
|
if (indices == null)
|
|
continue;
|
|
|
|
int indexCount = indices.Length;
|
|
for (int i = 0; i < indexCount; i += 3)
|
|
{
|
|
int i0 = indices[i];
|
|
int i1 = indices[i + 1];
|
|
int i2 = indices[i + 2];
|
|
|
|
var v0 = (Vector3)vertices[i0];
|
|
var v1 = (Vector3)vertices[i1];
|
|
var v2 = (Vector3)vertices[i2];
|
|
|
|
var nx = v1 - v0;
|
|
var ny = v2 - v0;
|
|
Vector3 normal;
|
|
Vector3.Cross(ref nx, ref ny, out normal);
|
|
normal.Normalize();
|
|
|
|
normals[i0] += normal;
|
|
normals[i1] += normal;
|
|
normals[i2] += normal;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < vertexCount; i++)
|
|
{
|
|
normals[i].Normalize();
|
|
}
|
|
|
|
this.normals = normals;
|
|
}
|
|
#endregion
|
|
|
|
#region Recalculate Tangents
|
|
/// <summary>
|
|
/// Recalculates the tangents for this mesh.
|
|
/// </summary>
|
|
public void RecalculateTangents()
|
|
{
|
|
// Make sure we have the normals first
|
|
if (normals == null)
|
|
return;
|
|
|
|
// Also make sure that we have the first UV set
|
|
bool uvIs2D = (uvs2D != null && uvs2D[0] != null);
|
|
bool uvIs3D = (uvs3D != null && uvs3D[0] != null);
|
|
bool uvIs4D = (uvs4D != null && uvs4D[0] != null);
|
|
if (!uvIs2D && !uvIs3D && !uvIs4D)
|
|
return;
|
|
|
|
int vertexCount = vertices.Length;
|
|
|
|
var tangents = new Vector4[vertexCount];
|
|
var tan1 = new Vector3[vertexCount];
|
|
var tan2 = new Vector3[vertexCount];
|
|
|
|
Vector2[] uv2D = (uvIs2D ? uvs2D[0] : null);
|
|
Vector3[] uv3D = (uvIs3D ? uvs3D[0] : null);
|
|
Vector4[] uv4D = (uvIs4D ? uvs4D[0] : null);
|
|
|
|
int subMeshCount = this.indices.Length;
|
|
for (int subMeshIndex = 0; subMeshIndex < subMeshCount; subMeshIndex++)
|
|
{
|
|
int[] indices = this.indices[subMeshIndex];
|
|
if (indices == null)
|
|
continue;
|
|
|
|
int indexCount = indices.Length;
|
|
for (int i = 0; i < indexCount; i += 3)
|
|
{
|
|
int i0 = indices[i];
|
|
int i1 = indices[i + 1];
|
|
int i2 = indices[i + 2];
|
|
|
|
var v0 = vertices[i0];
|
|
var v1 = vertices[i1];
|
|
var v2 = vertices[i2];
|
|
|
|
float s1, s2, t1, t2;
|
|
if (uvIs2D)
|
|
{
|
|
var w0 = uv2D[i0];
|
|
var w1 = uv2D[i1];
|
|
var w2 = uv2D[i2];
|
|
s1 = w1.x - w0.x;
|
|
s2 = w2.x - w0.x;
|
|
t1 = w1.y - w0.y;
|
|
t2 = w2.y - w0.y;
|
|
}
|
|
else if (uvIs3D)
|
|
{
|
|
var w0 = uv3D[i0];
|
|
var w1 = uv3D[i1];
|
|
var w2 = uv3D[i2];
|
|
s1 = w1.x - w0.x;
|
|
s2 = w2.x - w0.x;
|
|
t1 = w1.y - w0.y;
|
|
t2 = w2.y - w0.y;
|
|
}
|
|
else
|
|
{
|
|
var w0 = uv4D[i0];
|
|
var w1 = uv4D[i1];
|
|
var w2 = uv4D[i2];
|
|
s1 = w1.x - w0.x;
|
|
s2 = w2.x - w0.x;
|
|
t1 = w1.y - w0.y;
|
|
t2 = w2.y - w0.y;
|
|
}
|
|
|
|
|
|
float x1 = (float)(v1.x - v0.x);
|
|
float x2 = (float)(v2.x - v0.x);
|
|
float y1 = (float)(v1.y - v0.y);
|
|
float y2 = (float)(v2.y - v0.y);
|
|
float z1 = (float)(v1.z - v0.z);
|
|
float z2 = (float)(v2.z - v0.z);
|
|
float r = 1f / (s1 * t2 - s2 * t1);
|
|
|
|
var sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
|
|
var tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
|
|
|
|
tan1[i0] += sdir;
|
|
tan1[i1] += sdir;
|
|
tan1[i2] += sdir;
|
|
tan2[i0] += tdir;
|
|
tan2[i1] += tdir;
|
|
tan2[i2] += tdir;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < vertexCount; i++)
|
|
{
|
|
var n = normals[i];
|
|
var t = tan1[i];
|
|
|
|
var tmp = (t - n * Vector3.Dot(ref n, ref t));
|
|
tmp.Normalize();
|
|
|
|
Vector3 c;
|
|
Vector3.Cross(ref n, ref t, out c);
|
|
float dot = Vector3.Dot(ref c, ref tan2[i]);
|
|
float w = (dot < 0f ? -1f : 1f);
|
|
tangents[i] = new Vector4(tmp.x, tmp.y, tmp.z, w);
|
|
}
|
|
|
|
this.tangents = tangents;
|
|
}
|
|
#endregion
|
|
|
|
#region Triangles
|
|
/// <summary>
|
|
/// Returns the count of triangles for a specific sub-mesh in this mesh.
|
|
/// </summary>
|
|
/// <param name="subMeshIndex">The sub-mesh index.</param>
|
|
/// <returns>The triangle count.</returns>
|
|
public int GetTriangleCount(int subMeshIndex)
|
|
{
|
|
if (subMeshIndex < 0 || subMeshIndex >= indices.Length)
|
|
throw new IndexOutOfRangeException();
|
|
|
|
return indices[subMeshIndex].Length / 3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the triangle indices of a specific sub-mesh in this mesh.
|
|
/// </summary>
|
|
/// <param name="subMeshIndex">The sub-mesh index.</param>
|
|
/// <returns>The triangle indices.</returns>
|
|
public int[] GetIndices(int subMeshIndex)
|
|
{
|
|
if (subMeshIndex < 0 || subMeshIndex >= indices.Length)
|
|
throw new IndexOutOfRangeException();
|
|
|
|
return indices[subMeshIndex] ?? emptyIndices;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the triangle indices for all sub-meshes in this mesh.
|
|
/// </summary>
|
|
/// <returns>The sub-mesh triangle indices.</returns>
|
|
public int[][] GetSubMeshIndices()
|
|
{
|
|
var subMeshIndices = new int[indices.Length][];
|
|
for (int subMeshIndex = 0; subMeshIndex < indices.Length; subMeshIndex++)
|
|
{
|
|
subMeshIndices[subMeshIndex] = indices[subMeshIndex] ?? emptyIndices;
|
|
}
|
|
return subMeshIndices;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the triangle indices of a specific sub-mesh in this mesh.
|
|
/// </summary>
|
|
/// <param name="subMeshIndex">The sub-mesh index.</param>
|
|
/// <param name="indices">The triangle indices.</param>
|
|
public void SetIndices(int subMeshIndex, int[] indices)
|
|
{
|
|
if (subMeshIndex < 0 || subMeshIndex >= this.indices.Length)
|
|
throw new IndexOutOfRangeException();
|
|
else if (indices == null)
|
|
throw new ArgumentNullException("indices");
|
|
else if ((indices.Length % 3) != 0)
|
|
throw new ArgumentException("The index count must be multiple by 3.", "indices");
|
|
|
|
this.indices[subMeshIndex] = indices;
|
|
}
|
|
#endregion
|
|
|
|
#region UV Sets
|
|
#region Getting
|
|
/// <summary>
|
|
/// Returns the UV dimension for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel"></param>
|
|
/// <returns>The UV dimension count.</returns>
|
|
public int GetUVDimension(int channel)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs2D != null && uvs2D[channel] != null)
|
|
{
|
|
return 2;
|
|
}
|
|
else if (uvs3D != null && uvs3D[channel] != null)
|
|
{
|
|
return 3;
|
|
}
|
|
else if (uvs4D != null && uvs4D[channel] != null)
|
|
{
|
|
return 4;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the UVs (2D) from a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <returns>The UVs.</returns>
|
|
public Vector2[] GetUVs2D(int channel)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs2D != null && uvs2D[channel] != null)
|
|
{
|
|
return uvs2D[channel];
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the UVs (3D) from a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <returns>The UVs.</returns>
|
|
public Vector3[] GetUVs3D(int channel)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs3D != null && uvs3D[channel] != null)
|
|
{
|
|
return uvs3D[channel];
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the UVs (4D) from a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <returns>The UVs.</returns>
|
|
public Vector4[] GetUVs4D(int channel)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs4D != null && uvs4D[channel] != null)
|
|
{
|
|
return uvs4D[channel];
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the UVs (2D) from a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void GetUVs(int channel, List<Vector2> uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
else if (uvs == null)
|
|
throw new ArgumentNullException("uvs");
|
|
|
|
uvs.Clear();
|
|
if (uvs2D != null && uvs2D[channel] != null)
|
|
{
|
|
var uvData = uvs2D[channel];
|
|
if (uvData != null)
|
|
{
|
|
uvs.AddRange(uvData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the UVs (3D) from a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void GetUVs(int channel, List<Vector3> uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
else if (uvs == null)
|
|
throw new ArgumentNullException("uvs");
|
|
|
|
uvs.Clear();
|
|
if (uvs3D != null && uvs3D[channel] != null)
|
|
{
|
|
var uvData = uvs3D[channel];
|
|
if (uvData != null)
|
|
{
|
|
uvs.AddRange(uvData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the UVs (4D) from a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void GetUVs(int channel, List<Vector4> uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
else if (uvs == null)
|
|
throw new ArgumentNullException("uvs");
|
|
|
|
uvs.Clear();
|
|
if (uvs4D != null && uvs4D[channel] != null)
|
|
{
|
|
var uvData = uvs4D[channel];
|
|
if (uvData != null)
|
|
{
|
|
uvs.AddRange(uvData);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Setting
|
|
/// <summary>
|
|
/// Sets the UVs (2D) for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void SetUVs(int channel, Vector2[] uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs != null && uvs.Length > 0)
|
|
{
|
|
if (uvs.Length != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex UVs must be as many as the vertices. Assigned: {0} Require: {1}", uvs.Length, vertices.Length));
|
|
|
|
if (uvs2D == null)
|
|
uvs2D = new Vector2[UVChannelCount][];
|
|
|
|
int uvCount = uvs.Length;
|
|
var uvSet = new Vector2[uvCount];
|
|
uvs2D[channel] = uvSet;
|
|
uvs.CopyTo(uvSet, 0);
|
|
}
|
|
else
|
|
{
|
|
if (uvs2D != null)
|
|
{
|
|
uvs2D[channel] = null;
|
|
}
|
|
}
|
|
|
|
if (uvs3D != null)
|
|
{
|
|
uvs3D[channel] = null;
|
|
}
|
|
if (uvs4D != null)
|
|
{
|
|
uvs4D[channel] = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the UVs (3D) for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void SetUVs(int channel, Vector3[] uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs != null && uvs.Length > 0)
|
|
{
|
|
int uvCount = uvs.Length;
|
|
if (uvCount != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex UVs must be as many as the vertices. Assigned: {0} Require: {1}", uvCount, vertices.Length), "uvs");
|
|
|
|
if (uvs3D == null)
|
|
uvs3D = new Vector3[UVChannelCount][];
|
|
|
|
var uvSet = new Vector3[uvCount];
|
|
uvs3D[channel] = uvSet;
|
|
uvs.CopyTo(uvSet, 0);
|
|
}
|
|
else
|
|
{
|
|
if (uvs3D != null)
|
|
{
|
|
uvs3D[channel] = null;
|
|
}
|
|
}
|
|
|
|
if (uvs2D != null)
|
|
{
|
|
uvs2D[channel] = null;
|
|
}
|
|
if (uvs4D != null)
|
|
{
|
|
uvs4D[channel] = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the UVs (4D) for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void SetUVs(int channel, Vector4[] uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs != null && uvs.Length > 0)
|
|
{
|
|
int uvCount = uvs.Length;
|
|
if (uvCount != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex UVs must be as many as the vertices. Assigned: {0} Require: {1}", uvCount, vertices.Length), "uvs");
|
|
|
|
if (uvs4D == null)
|
|
uvs4D = new Vector4[UVChannelCount][];
|
|
|
|
var uvSet = new Vector4[uvCount];
|
|
uvs4D[channel] = uvSet;
|
|
uvs.CopyTo(uvSet, 0);
|
|
}
|
|
else
|
|
{
|
|
if (uvs4D != null)
|
|
{
|
|
uvs4D[channel] = null;
|
|
}
|
|
}
|
|
|
|
if (uvs2D != null)
|
|
{
|
|
uvs2D[channel] = null;
|
|
}
|
|
if (uvs3D != null)
|
|
{
|
|
uvs3D[channel] = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the UVs (2D) for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void SetUVs(int channel, List<Vector2> uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs != null && uvs.Count > 0)
|
|
{
|
|
int uvCount = uvs.Count;
|
|
if (uvCount != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex UVs must be as many as the vertices. Assigned: {0} Require: {1}", uvCount, vertices.Length), "uvs");
|
|
|
|
if (uvs2D == null)
|
|
uvs2D = new Vector2[UVChannelCount][];
|
|
|
|
var uvSet = new Vector2[uvCount];
|
|
uvs2D[channel] = uvSet;
|
|
uvs.CopyTo(uvSet, 0);
|
|
}
|
|
else
|
|
{
|
|
if (uvs2D != null)
|
|
{
|
|
uvs2D[channel] = null;
|
|
}
|
|
}
|
|
|
|
if (uvs3D != null)
|
|
{
|
|
uvs3D[channel] = null;
|
|
}
|
|
if (uvs4D != null)
|
|
{
|
|
uvs4D[channel] = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the UVs (3D) for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void SetUVs(int channel, List<Vector3> uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs != null && uvs.Count > 0)
|
|
{
|
|
int uvCount = uvs.Count;
|
|
if (uvCount != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex UVs must be as many as the vertices. Assigned: {0} Require: {1}", uvCount, vertices.Length), "uvs");
|
|
|
|
if (uvs3D == null)
|
|
uvs3D = new Vector3[UVChannelCount][];
|
|
|
|
var uvSet = new Vector3[uvCount];
|
|
uvs3D[channel] = uvSet;
|
|
uvs.CopyTo(uvSet, 0);
|
|
}
|
|
else
|
|
{
|
|
if (uvs3D != null)
|
|
{
|
|
uvs3D[channel] = null;
|
|
}
|
|
}
|
|
|
|
if (uvs2D != null)
|
|
{
|
|
uvs2D[channel] = null;
|
|
}
|
|
if (uvs4D != null)
|
|
{
|
|
uvs4D[channel] = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the UVs (4D) for a specific channel.
|
|
/// </summary>
|
|
/// <param name="channel">The channel index.</param>
|
|
/// <param name="uvs">The UVs.</param>
|
|
public void SetUVs(int channel, List<Vector4> uvs)
|
|
{
|
|
if (channel < 0 || channel >= UVChannelCount)
|
|
throw new ArgumentOutOfRangeException("channel");
|
|
|
|
if (uvs != null && uvs.Count > 0)
|
|
{
|
|
int uvCount = uvs.Count;
|
|
if (uvCount != vertices.Length)
|
|
throw new ArgumentException(string.Format("The vertex UVs must be as many as the vertices. Assigned: {0} Require: {1}", uvCount, vertices.Length), "uvs");
|
|
|
|
if (uvs4D == null)
|
|
uvs4D = new Vector4[UVChannelCount][];
|
|
|
|
var uvSet = new Vector4[uvCount];
|
|
uvs4D[channel] = uvSet;
|
|
uvs.CopyTo(uvSet, 0);
|
|
}
|
|
else
|
|
{
|
|
if (uvs4D != null)
|
|
{
|
|
uvs4D[channel] = null;
|
|
}
|
|
}
|
|
|
|
if (uvs2D != null)
|
|
{
|
|
uvs2D[channel] = null;
|
|
}
|
|
if (uvs3D != null)
|
|
{
|
|
uvs3D[channel] = null;
|
|
}
|
|
}
|
|
#endregion
|
|
#endregion
|
|
|
|
#region To String
|
|
/// <summary>
|
|
/// Returns the text-representation of this mesh.
|
|
/// </summary>
|
|
/// <returns>The text-representation.</returns>
|
|
public override string ToString()
|
|
{
|
|
return string.Format("Vertices: {0}", vertices.Length);
|
|
}
|
|
#endregion
|
|
#endregion
|
|
}
|
|
} |