using System; using System.Collections.Generic; using UnityEngine; namespace UnityEngine.ProBuilder.Csg { static class VertexUtility { /// /// Allocate and fill all attribute arrays. This method will fill all arrays, regardless of whether or not real data populates the values (check what attributes a Vertex contains with HasAttribute()). /// /// /// If you are using this function to rebuild a mesh, use SetMesh instead. SetMesh handles setting null arrays where appropriate for you. /// /// /// The source vertices. /// A new array of the vertex position values. /// A new array of the vertex color values. /// A new array of the vertex uv0 values. /// A new array of the vertex normal values. /// A new array of the vertex tangent values. /// A new array of the vertex uv2 values. /// A new array of the vertex uv3 values. /// A new array of the vertex uv4 values. public static void GetArrays( IList vertices, out Vector3[] position, out Color[] color, out Vector2[] uv0, out Vector3[] normal, out Vector4[] tangent, out Vector2[] uv2, out List uv3, out List uv4) { GetArrays(vertices, out position, out color, out uv0, out normal, out tangent, out uv2, out uv3, out uv4, VertexAttributes.All); } /// /// Allocate and fill the requested attribute arrays. /// /// /// If you are using this function to rebuild a mesh, use SetMesh instead. SetMesh handles setting null arrays where appropriate for you. /// /// /// The source vertices. /// A new array of the vertex position values if requested by the attributes parameter, or null. /// A new array of the vertex color values if requested by the attributes parameter, or null. /// A new array of the vertex uv0 values if requested by the attributes parameter, or null. /// A new array of the vertex normal values if requested by the attributes parameter, or null. /// A new array of the vertex tangent values if requested by the attributes parameter, or null. /// A new array of the vertex uv2 values if requested by the attributes parameter, or null. /// A new array of the vertex uv3 values if requested by the attributes parameter, or null. /// A new array of the vertex uv4 values if requested by the attributes parameter, or null. /// A flag with the MeshAttributes requested. /// public static void GetArrays( IList vertices, out Vector3[] position, out Color[] color, out Vector2[] uv0, out Vector3[] normal, out Vector4[] tangent, out Vector2[] uv2, out List uv3, out List uv4, VertexAttributes attributes) { if (vertices == null) throw new ArgumentNullException("vertices"); int vc = vertices.Count; var first = vc < 1 ? new Vertex() : vertices[0]; bool hasPosition = ((attributes & VertexAttributes.Position) == VertexAttributes.Position) && first.hasPosition; bool hasColor = ((attributes & VertexAttributes.Color) == VertexAttributes.Color) && first.hasColor; bool hasUv0 = ((attributes & VertexAttributes.Texture0) == VertexAttributes.Texture0) && first.hasUV0; bool hasNormal = ((attributes & VertexAttributes.Normal) == VertexAttributes.Normal) && first.hasNormal; bool hasTangent = ((attributes & VertexAttributes.Tangent) == VertexAttributes.Tangent) && first.hasTangent; bool hasUv2 = ((attributes & VertexAttributes.Texture1) == VertexAttributes.Texture1) && first.hasUV2; bool hasUv3 = ((attributes & VertexAttributes.Texture2) == VertexAttributes.Texture2) && first.hasUV3; bool hasUv4 = ((attributes & VertexAttributes.Texture3) == VertexAttributes.Texture3) && first.hasUV4; position = hasPosition ? new Vector3[vc] : null; color = hasColor ? new Color[vc] : null; uv0 = hasUv0 ? new Vector2[vc] : null; normal = hasNormal ? new Vector3[vc] : null; tangent = hasTangent ? new Vector4[vc] : null; uv2 = hasUv2 ? new Vector2[vc] : null; uv3 = hasUv3 ? new List(vc) : null; uv4 = hasUv4 ? new List(vc) : null; for (int i = 0; i < vc; i++) { if (hasPosition) position[i] = vertices[i].position; if (hasColor) color[i] = vertices[i].color; if (hasUv0) uv0[i] = vertices[i].uv0; if (hasNormal) normal[i] = vertices[i].normal; if (hasTangent) tangent[i] = vertices[i].tangent; if (hasUv2) uv2[i] = vertices[i].uv2; if (hasUv3) uv3.Add(vertices[i].uv3); if (hasUv4) uv4.Add(vertices[i].uv4); } } public static Vertex[] GetVertices(this Mesh mesh) { if (mesh == null) return null; int vertexCount = mesh.vertexCount; Vertex[] v = new Vertex[vertexCount]; Vector3[] positions = mesh.vertices; Color[] colors = mesh.colors; Vector3[] normals = mesh.normals; Vector4[] tangents = mesh.tangents; Vector2[] uv0s = mesh.uv; Vector2[] uv2s = mesh.uv2; List uv3s = new List(); List uv4s = new List(); mesh.GetUVs(2, uv3s); mesh.GetUVs(3, uv4s); bool _hasPositions = positions != null && positions.Length == vertexCount; bool _hasColors = colors != null && colors.Length == vertexCount; bool _hasNormals = normals != null && normals.Length == vertexCount; bool _hasTangents = tangents != null && tangents.Length == vertexCount; bool _hasUv0 = uv0s != null && uv0s.Length == vertexCount; bool _hasUv2 = uv2s != null && uv2s.Length == vertexCount; bool _hasUv3 = uv3s.Count == vertexCount; bool _hasUv4 = uv4s.Count == vertexCount; for (int i = 0; i < vertexCount; i++) { v[i] = new Vertex(); if (_hasPositions) v[i].position = positions[i]; if (_hasColors) v[i].color = colors[i]; if (_hasNormals) v[i].normal = normals[i]; if (_hasTangents) v[i].tangent = tangents[i]; if (_hasUv0) v[i].uv0 = uv0s[i]; if (_hasUv2) v[i].uv2 = uv2s[i]; if (_hasUv3) v[i].uv3 = uv3s[i]; if (_hasUv4) v[i].uv4 = uv4s[i]; } return v; } /// /// Replace mesh values with vertex array. Mesh is cleared during this function, so be sure to set the triangles after calling. /// /// The target mesh. /// The vertices to replace the mesh attributes with. public static void SetMesh(Mesh mesh, IList vertices) { if (mesh == null) throw new ArgumentNullException("mesh"); if (vertices == null) throw new ArgumentNullException("vertices"); Vector3[] positions = null; Color[] colors = null; Vector2[] uv0s = null; Vector3[] normals = null; Vector4[] tangents = null; Vector2[] uv2s = null; List uv3s = null; List uv4s = null; GetArrays(vertices, out positions, out colors, out uv0s, out normals, out tangents, out uv2s, out uv3s, out uv4s); mesh.Clear(); Vertex first = vertices[0]; if (first.hasPosition) mesh.vertices = positions; if (first.hasColor) mesh.colors = colors; if (first.hasUV0) mesh.uv = uv0s; if (first.hasNormal) mesh.normals = normals; if (first.hasTangent) mesh.tangents = tangents; if (first.hasUV2) mesh.uv2 = uv2s; if (first.hasUV3) if (uv3s != null) mesh.SetUVs(2, uv3s); if (first.hasUV4) if (uv4s != null) mesh.SetUVs(3, uv4s); } /// /// Linearly interpolate between two vertices. /// /// Left parameter. /// Right parameter. /// The weight of the interpolation. 0 is fully x, 1 is fully y. /// A new vertex interpolated by weight between x and y. public static Vertex Mix(this Vertex x, Vertex y, float weight) { float i = 1f - weight; Vertex v = new Vertex(); v.position = x.position * i + y.position * weight; if (x.hasColor && y.hasColor) v.color = x.color * i + y.color * weight; else if (x.hasColor) v.color = x.color; else if (y.hasColor) v.color = y.color; if (x.hasNormal && y.hasNormal) v.normal = x.normal * i + y.normal * weight; else if (x.hasNormal) v.normal = x.normal; else if (y.hasNormal) v.normal = y.normal; if (x.hasTangent && y.hasTangent) v.tangent = x.tangent * i + y.tangent * weight; else if (x.hasTangent) v.tangent = x.tangent; else if (y.hasTangent) v.tangent = y.tangent; if (x.hasUV0 && y.hasUV0) v.uv0 = x.uv0 * i + y.uv0 * weight; else if (x.hasUV0) v.uv0 = x.uv0; else if (y.hasUV0) v.uv0 = y.uv0; if (x.hasUV2 && y.hasUV2) v.uv2 = x.uv2 * i + y.uv2 * weight; else if (x.hasUV2) v.uv2 = x.uv2; else if (y.hasUV2) v.uv2 = y.uv2; if (x.hasUV3 && y.hasUV3) v.uv3 = x.uv3 * i + y.uv3 * weight; else if (x.hasUV3) v.uv3 = x.uv3; else if (y.hasUV3) v.uv3 = y.uv3; if (x.hasUV4 && y.hasUV4) v.uv4 = x.uv4 * i + y.uv4 * weight; else if (x.hasUV4) v.uv4 = x.uv4; else if (y.hasUV4) v.uv4 = y.uv4; return v; } /// /// Transform a vertex into world space. /// /// The transform to apply. /// A model space vertex. /// A new vertex in world coordinate space. public static Vertex TransformVertex(this Transform transform, Vertex vertex) { var v = new Vertex(); if (vertex.HasArrays(VertexAttributes.Position)) v.position = transform.TransformPoint(vertex.position); if (vertex.HasArrays(VertexAttributes.Color)) v.color = vertex.color; if (vertex.HasArrays(VertexAttributes.Normal)) v.normal = transform.TransformDirection(vertex.normal); if (vertex.HasArrays(VertexAttributes.Tangent)) v.tangent = transform.rotation * vertex.tangent; if (vertex.HasArrays(VertexAttributes.Texture0)) v.uv0 = vertex.uv0; if (vertex.HasArrays(VertexAttributes.Texture1)) v.uv2 = vertex.uv2; if (vertex.HasArrays(VertexAttributes.Texture2)) v.uv3 = vertex.uv3; if (vertex.HasArrays(VertexAttributes.Texture3)) v.uv4 = vertex.uv4; return v; } } }