public void Apply(z_Mesh mesh) { foreach (z_AttributeLayout al in attributeLayout) { switch (al.channel) { case z_MeshChannel.UV0: case z_MeshChannel.UV2: case z_MeshChannel.UV3: case z_MeshChannel.UV4: { List <Vector4> uv = new List <Vector4>(weights[channelMap[al.channel]]); mesh.SetUVs(z_MeshChannelUtility.UVChannelToIndex(al.channel), uv); } break; case z_MeshChannel.Color: { // @todo consider storing Color array separate from Vec4 since this cast costs ~5ms mesh.colors = System.Array.ConvertAll(weights[channelMap[al.channel]], x => Vec4ToColor32(x)); break; } case z_MeshChannel.Tangent: { mesh.tangents = weights[channelMap[z_MeshChannel.Tangent]]; break; } } } }
public override void OnVerticesMoved(z_Mesh mesh) { #if DO_RENDER_OVERLAY_MESH Vector3[] v = mesh.vertices; if (wireframeMesh != null) { wireframeMesh.vertices = v; } if (drawVertexBillboards) { int len = System.Math.Min(ushort.MaxValue / 4, common.Count); if (vertexMesh != null) { Vector3[] v2 = new Vector3[len * 4]; for (int i = 0; i < len; i++) { int ind = common[i][0]; v2[i * 4 + 0] = v[ind]; v2[i * 4 + 1] = v[ind]; v2[i * 4 + 2] = v[ind]; v2[i * 4 + 3] = v[ind]; } vertexMesh.vertices = v2; } } #endif }
/** * Vertices that are common, form a seam, and should be smoothed. */ public static List <List <int> > GetSmoothSeamLookup(z_Mesh m) { Vector3[] normals = m.normals; if (normals == null) { return(null); } List <List <int> > lookup = null; if (commonNormalsCache.TryGetValue(m, out lookup)) { return(lookup); } List <List <int> > common = GetCommonVertices(m); var z = common .SelectMany(x => x.GroupBy(i => (z_RndVec3)normals[i])) .Where(n => n.Count() > 1) .Select(t => t.ToList()) .ToList(); commonNormalsCache.Add(m, z); return(z); }
/** * Builds a lookup with each vertex index and a list of all neighboring indices. */ public static Dictionary <int, List <int> > GetAdjacentVertices(z_Mesh mesh) { List <List <int> > common = GetCommonVertices(mesh); Dictionary <int, int> lookup = common.GetCommonLookup <int>(); List <z_CommonEdge> edges = GetEdges(mesh, lookup).ToList(); List <List <int> > map = new List <List <int> >(); for (int i = 0; i < common.Count(); i++) { map.Add(new List <int>()); } for (int i = 0; i < edges.Count; i++) { map[edges[i].cx].Add(edges[i].y); map[edges[i].cy].Add(edges[i].x); } Dictionary <int, List <int> > adjacent = new Dictionary <int, List <int> >(); IEnumerable <int> distinctTriangles = mesh.GetTriangles().Distinct(); foreach (int i in distinctTriangles) { adjacent.Add(i, map[lookup[i]]); } return(adjacent); }
private static HashSet <z_CommonEdge> GetEdgesDistinct(z_Mesh m, Dictionary <int, int> lookup, out List <z_CommonEdge> duplicates) { int[] tris = m.GetTriangles(); int count = tris.Length; HashSet <z_CommonEdge> edges = new HashSet <z_CommonEdge>(); duplicates = new List <z_CommonEdge>(); for (int i = 0; i < count; i += 3) { z_CommonEdge a = new z_CommonEdge(tris[i + 0], tris[i + 1], lookup[tris[i + 0]], lookup[tris[i + 1]]); z_CommonEdge b = new z_CommonEdge(tris[i + 1], tris[i + 2], lookup[tris[i + 1]], lookup[tris[i + 2]]); z_CommonEdge c = new z_CommonEdge(tris[i + 2], tris[i + 0], lookup[tris[i + 2]], lookup[tris[i + 0]]); if (!edges.Add(a)) { duplicates.Add(a); } if (!edges.Add(b)) { duplicates.Add(b); } if (!edges.Add(c)) { duplicates.Add(c); } } return(edges); }
/** * Return a mesh that is the combination of both additionalVertexStreams and the originalMesh. * - Position * - UV0 * - UV2 * - UV3 * - UV4 * - Color * - Tangent * If usingVertexStreams is false, null is returned. */ private z_Mesh GetCompositeMesh() { if (_editMesh == null) { _editMesh = new z_Mesh(); } _editMesh.Clear(); _editMesh.name = originalMesh.name; _editMesh.vertices = GetAttribute <Vector3[]>(x => { return(x.vertices); }); _editMesh.normals = GetAttribute <Vector3[]>(x => { return(x.normals); }); _editMesh.colors = GetAttribute <Color32[]>(x => { return(x.colors32); }); _editMesh.tangents = GetAttribute <Vector4[]>(x => { return(x.tangents); }); _editMesh.uv0 = GetAttribute <List <Vector4> >(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(0, l); return(l); }); _editMesh.uv1 = GetAttribute <List <Vector4> >(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(1, l); return(l); }); _editMesh.uv2 = GetAttribute <List <Vector4> >(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(2, l); return(l); }); _editMesh.uv3 = GetAttribute <List <Vector4> >(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(3, l); return(l); }); _editMesh.subMeshCount = originalMesh.subMeshCount; for (int i = 0; i < _editMesh.subMeshCount; i++) { _editMesh.SetTriangles(originalMesh.GetTriangles(i), i); } return(_editMesh); }
/** * Creates a new mesh using only the @src positions, normals, and a new color array. */ public static Mesh CreateOverlayMesh(z_Mesh src) { Mesh m = new Mesh(); m.name = "Overlay Mesh: " + src.name; m.vertices = src.vertices; m.normals = src.normals; m.colors = z_Util.Fill <Color>(new Color(0f, 0f, 0f, 0f), m.vertexCount); m.subMeshCount = src.subMeshCount; for (int i = 0; i < src.subMeshCount; i++) { if (src.GetTopology(i) == MeshTopology.Triangles) { int[] tris = src.GetIndices(i); int[] lines = new int[tris.Length * 2]; int index = 0; for (int n = 0; n < tris.Length; n += 3) { lines[index++] = tris[n + 0]; lines[index++] = tris[n + 1]; lines[index++] = tris[n + 1]; lines[index++] = tris[n + 2]; lines[index++] = tris[n + 2]; lines[index++] = tris[n + 0]; } m.SetIndices(lines, MeshTopology.Lines, i); } else { m.SetIndices(src.GetIndices(i), src.GetTopology(i), i); } } return(m); }
/** * Initialize a SplatSet with mesh and attribute layout. */ public z_SplatSet(z_Mesh mesh, z_AttributeLayout[] attributes) : this(mesh.vertexCount, attributes, false) { foreach (var kvp in channelMap) { switch (kvp.Key) { case z_MeshChannel.UV0: case z_MeshChannel.UV2: case z_MeshChannel.UV3: case z_MeshChannel.UV4: { List <Vector4> uv = mesh.GetUVs(z_MeshChannelUtility.UVChannelToIndex(kvp.Key)); weights[kvp.Value] = uv.Count == weightCount?uv.ToArray() : new Vector4[weightCount]; } break; case z_MeshChannel.Color: { Color32[] color = mesh.colors; weights[kvp.Value] = color != null && color.Length == weightCount?System.Array.ConvertAll(color, x => Color32ToVec4(x)) : new Vector4[weightCount]; } break; case z_MeshChannel.Tangent: { Vector4[] tangent = mesh.tangents; weights[kvp.Value] = tangent != null && tangent.Length == weightCount ? tangent : new Vector4[weightCount]; } break; } } }
/** * Returns all vertex indices that are on an open edge. */ public static HashSet <int> GetNonManifoldIndices(z_Mesh mesh) { List <z_CommonEdge> duplicates; HashSet <z_CommonEdge> edges = GetEdgesDistinct(mesh, out duplicates); edges.ExceptWith(duplicates); HashSet <int> hash = z_CommonEdge.ToHashSet(edges); return(hash); }
public static List <z_CommonEdge> GetEdges(z_Mesh m, Dictionary <int, int> lookup) { int[] tris = m.GetTriangles(); int count = tris.Length; List <z_CommonEdge> edges = new List <z_CommonEdge>(count); for (int i = 0; i < count; i += 3) { edges.Add(new z_CommonEdge(tris[i + 0], tris[i + 1], lookup[tris[i + 0]], lookup[tris[i + 1]])); edges.Add(new z_CommonEdge(tris[i + 1], tris[i + 2], lookup[tris[i + 1]], lookup[tris[i + 2]])); edges.Add(new z_CommonEdge(tris[i + 2], tris[i + 0], lookup[tris[i + 2]], lookup[tris[i + 0]])); } return(edges); }
public void SetMesh(z_Mesh m) { #if DO_RENDER_OVERLAY_MESH wireframeMesh = z_MeshUtility.CreateOverlayMesh(m); wireframeMesh.hideFlags = HideFlags.HideAndDontSave; w_colors = new Color[wireframeMesh.vertexCount]; if (drawVertexBillboards) { common = z_MeshUtility.GetCommonVertices(m); vertexMesh = z_MeshUtility.CreateVertexBillboardMesh(m, common); vertexMesh.hideFlags = HideFlags.HideAndDontSave; v_colors = new Color[vertexMesh.vertexCount]; } #endif }
protected void CacheBrushNormals(z_BrushTarget target) { brushNormalOnBeginApply.Clear(); for (int i = 0; i < target.raycastHits.Count; i++) { brushNormalOnBeginApply.Add(target.raycastHits[i].normal); } z_Mesh mesh = target.editableObject.editMesh; cached_normals = new Vector3[mesh.vertexCount]; if (mesh.normals != null && mesh.normals.Length == mesh.vertexCount) { System.Array.Copy(mesh.normals, 0, cached_normals, 0, mesh.vertexCount); } }
private void RebuildCaches(z_EditableObject target, z_BrushSettings settings) { z_Mesh m = target.editMesh; int vertexCount = m.vertexCount; if (m.colors != null && m.colors.Length == vertexCount) { colors_cache = z_Util.Duplicate(m.colors); } else { colors_cache = z_Util.Fill <Color32>(x => { return(Color.white); }, vertexCount); } colors = new Color32[vertexCount]; target_colors = new Color32[vertexCount]; erase_colors = new Color32[vertexCount]; RebuildColorTargets(brushColor, settings.strength); }
private void RebuildCaches(z_Mesh m, float strength) { vertexCount = m.vertexCount; triangleLookup = z_MeshUtility.GetAdjacentTriangles(m); if (meshAttributes == null) { // clear caches splat_cache = null; splat_current = null; splat_target = null; splat_erase = null; return; } splat_cache = new z_SplatSet(m, meshAttributes); splat_current = new z_SplatSet(splat_cache); splat_target = new z_SplatSet(vertexCount, meshAttributes); splat_erase = new z_SplatSet(vertexCount, meshAttributes); }
/** * Builds a lookup table for each vertex index and it's average normal with other vertices sharing a position. */ public static Dictionary <int, Vector3> GetSmoothNormalLookup(z_Mesh mesh) { Vector3[] n = mesh.normals; Dictionary <int, Vector3> normals = new Dictionary <int, Vector3>(); if (n == null || n.Length != mesh.vertexCount) { return(normals); } List <List <int> > groups = GetCommonVertices(mesh); Vector3 avg = Vector3.zero; Vector3 a = Vector3.zero; foreach (var group in groups) { avg.x = 0f; avg.y = 0f; avg.z = 0f; foreach (int i in group) { a = n[i]; avg.x += a.x; avg.y += a.y; avg.z += a.z; } avg /= (float)group.Count(); foreach (int i in group) { normals.Add(i, avg); } } return(normals); }
/** * Returns an array of weights where each index is the max of all raycast hits. */ public float[] GetAllWeights(bool rebuildCache = false) { z_Mesh mesh = editableObject.editMesh; int vertexCount = mesh.vertexCount; if (mesh == null) { return(null); } if (!rebuildCache) { return(_weights); } for (int i = 0; i < vertexCount; i++) { _weights[i] = 0f; } for (int i = 0; i < raycastHits.Count; i++) { if (raycastHits[i].weights != null) { float[] w = raycastHits[i].weights; for (int n = 0; n < vertexCount; n++) { if (w[n] > _weights[n]) { _weights[n] = w[n]; } } } } return(_weights); }
/** * Recalculates a mesh's normals while retaining smoothed common vertices. */ public static void RecalculateNormals(z_Mesh m) { List <List <int> > smooth = GetSmoothSeamLookup(m); m.RecalculateNormals(); if (smooth != null) { Vector3[] normals = m.normals; foreach (List <int> l in smooth) { Vector3 n = z_Math.Average(normals, l); foreach (int i in l) { normals[i] = n; } } m.normals = normals; } }
//commented out code was ommited here /** * Builds a list<group> with each vertex index and a list of all other vertices sharing a position. * key: Index in vertices array * value: List of other indices in positions array that share a point with this index. */ public static List <List <int> > GetCommonVertices(z_Mesh mesh) { List <List <int> > indices; if (commonVerticesCache.TryGetValue(mesh, out indices)) { // int min = mesh.vertexCount, max = 0; // for(int x = 0; x < indices.Count; x++) // { // for(int y = 0; y < indices[x].Count; y++) // { // int index = indices[x][y]; // if(index < min) min = index; // if(index > max) max = index; // } // } // if(max - min + 1 == mesh.vertexCount) return(indices); } Vector3[] v = mesh.vertices; int[] t = z_Util.Fill <int>((x) => { return(x); }, v.Length); indices = t.ToLookup(x => (z_RndVec3)v[x]).Select(y => y.ToList()).ToList(); if (!commonVerticesCache.ContainsKey(mesh)) { commonVerticesCache.Add(mesh, indices); } else { commonVerticesCache[mesh] = indices; } return(indices); }
/** * Calculates the per-vertex weight for each raycast hit and fills in brush target weights. */ public static void CalculateWeightedVertices(z_BrushTarget target, z_BrushSettings settings) { if (target.editableObject == null) { return; } bool uniformScale = z_Math.VectorIsUniform(target.transform.lossyScale); float scale = uniformScale ? 1f / target.transform.lossyScale.x : 1f; z_Mesh mesh = target.editableObject.editMesh; List <List <int> > common = z_MeshUtility.GetCommonVertices(mesh); Transform transform = target.transform; int vertexCount = mesh.vertexCount; Vector3[] vertices = mesh.vertices; if (!uniformScale) { Vector3[] world = new Vector3[vertexCount]; for (int i = 0; i < vertexCount; i++) { world[i] = transform.TransformPoint(vertices[i]); } vertices = world; } AnimationCurve curve = settings.falloffCurve; float radius = settings.radius * scale, falloff_mag = Mathf.Max((radius - radius * settings.falloff), 0.00001f); Vector3 hitPosition = Vector3.zero; z_RaycastHit hit; for (int n = 0; n < target.raycastHits.Count; n++) { hit = target.raycastHits[n]; hit.SetVertexCount(vertexCount); hitPosition = uniformScale ? hit.position : transform.TransformPoint(hit.position); int c = common.Count; for (int i = 0; i < c; i++) { int commonArrayCount = common[i].Count; Vector3 a = hitPosition, b = vertices[common[i][0]]; float x = a.x - b.x, y = a.y - b.y, z = a.z - b.z; float dist = Mathf.Sqrt(x * x + y * y + z * z); if (dist > radius) { for (int j = 0; j < commonArrayCount; j++) { hit.weights[common[i][j]] = 0f; } } else { float weight = Mathf.Clamp(curve.Evaluate(1f - Mathf.Clamp((radius - dist) / falloff_mag, 0f, 1f)), 0f, 1f); for (int j = 0; j < commonArrayCount; j++) { hit.weights[common[i][j]] = weight; } } } } target.GetAllWeights(true); }
public override void OnBrushApply(z_BrushTarget target, z_BrushSettings settings) { int rayCount = target.raycastHits.Count; Vector3[] normals = (direction == z_Direction.BrushNormal) ? target.editableObject.editMesh.normals : null; Vector3 v, t, avg, dirVec = direction.ToVector3(); Plane plane = new Plane(Vector3.up, Vector3.zero); z_Mesh mesh = target.editableObject.editMesh; int vertexCount = mesh.vertexCount; // don't use target.GetAllWeights because brush normal needs // to know which ray to use for normal for (int ri = 0; ri < rayCount; ri++) { z_RaycastHit hit = target.raycastHits[ri]; if (hit.weights == null || hit.weights.Length < vertexCount) { continue; } for (int i = 0; i < commonVertexCount; i++) { int index = commonVertices[i][0]; if (hit.weights[index] < .0001f || (ignoreNonManifoldIndices && nonManifoldIndices.Contains(index))) { continue; } v = vertices[index]; if (direction == z_Direction.VertexNormal) { avg = z_Math.Average(vertices, neighborLookup[index]); } else { avg = z_Math.WeightedAverage(vertices, neighborLookup[index], hit.weights); if (direction == z_Direction.BrushNormal) { if (brushNormalIsSticky) { dirVec = brushNormalOnBeginApply[ri]; } else { dirVec = z_Math.WeightedAverage(normals, neighborLookup[index], hit.weights).normalized; } } plane.SetNormalAndPosition(dirVec, avg); avg = v - dirVec * plane.GetDistanceToPoint(v); } t = Vector3.Lerp(v, avg, hit.weights[index]); List <int> indices = commonVertices[i]; Vector3 pos = v + (t - v) * settings.strength * SMOOTH_STRENGTH_MODIFIER; for (int n = 0; n < indices.Count; n++) { vertices[indices[n]] = pos; } } } mesh.vertices = vertices; if (tempComponent != null) { tempComponent.OnVerticesMoved(mesh); } base.OnBrushApply(target, settings); }
/** * Internal constructor. * \sa Create */ private z_EditableObject(GameObject go) { this.gameObject = go; isProBuilderObject = z_ReflectionUtil.IsProBuilderObject(go); Mesh advsMesh = null; MeshRenderer meshRenderer = this.gameObject.GetComponent <MeshRenderer>(); meshFilter = this.gameObject.GetComponent <MeshFilter>(); SkinnedMeshRenderer skinFilter = this.gameObject.GetComponent <SkinnedMeshRenderer>(); usingVertexStreams = false; this.originalMesh = meshFilter.sharedMesh; if (originalMesh == null && skinFilter != null) { this.originalMesh = skinFilter.sharedMesh; } if (z_Pref.GetBool(z_Pref.additionalVertexStreams, false) && !isProBuilderObject) { if (meshRenderer != null || skinFilter != null) { additionalVertexStreams = gameObject.GetComponent <z_AdditionalVertexStreams>(); if (additionalVertexStreams == null) { additionalVertexStreams = gameObject.AddComponent <z_AdditionalVertexStreams>(); } advsMesh = additionalVertexStreams.m_AdditionalVertexStreamMesh; if (advsMesh == null) { advsMesh = new Mesh(); advsMesh.vertices = originalMesh.vertices; advsMesh.name = string.Format("{0}({1})", originalMesh.name, additionalVertexStreams.GetInstanceID()); hadVertexStreams = false; } usingVertexStreams = true; } } if (!usingVertexStreams) { // if editing a non-scene instance mesh, make it an instance // (unity primitives are a special case - they *are* scene instances but they also aren't) string guid = INSTANCE_MESH_GUID; this.source = z_EditorUtility.GetMeshGUID(originalMesh, ref guid); if (source != z_ModelSource.Scene || UnityPrimitiveMeshNames.Contains(originalMesh.name)) { this._graphicsMesh = z_MeshUtility.DeepCopy(meshFilter.sharedMesh); } else { this._graphicsMesh = originalMesh; } } else { this._graphicsMesh = advsMesh; this.source = z_ModelSource.AdditionalVertexStreams; } // if it's a probuilder object rebuild the mesh without optimization if (isProBuilderObject) { object pb = probuilderMesh = go.GetComponent("pb_Object"); if (pb != null) { z_ReflectionUtil.ProBuilder_ToMesh(pb); z_ReflectionUtil.ProBuilder_Refresh(pb, (ushort)0xFF); } if (setVerticesMethod == null) { setVerticesMethod = pb.GetType().GetMethod( "SetVertices", BindingFlags.Public | BindingFlags.Instance, null, SetVerticesArguments, null); } if (setUvsMethod == null) { setUvsMethod = pb.GetType().GetMethod( "SetUVs", BindingFlags.Public | BindingFlags.Instance, null, SetUVsArguments, null); } if (setTangentsMethod == null) { setTangentsMethod = pb.GetType().GetMethod( "SetTangents", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(Vector4[]) }, null); } if (setColorsMethod == null) { setColorsMethod = pb.GetType().GetMethod( "SetColors", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(Color[]) }, null); } } _editMesh = GetCompositeMesh(); if (!isProBuilderObject) { SetMesh(graphicsMesh); } }
// Draw scene gizmos. Base implementation draws the brush preview. public virtual void DrawGizmos(z_BrushTarget target, z_BrushSettings settings) { foreach (z_RaycastHit hit in target.raycastHits) { z_Handles.DrawBrush(hit.position, hit.normal, settings, target.localToWorldMatrix, innerColor, outerColor); } #if Z_DEBUG #if Z_DRAW_WEIGHTS || DRAW_PER_VERTEX_ATTRIBUTES float[] w = target.GetAllWeights(); #endif #if Z_DRAW_WEIGHTS Mesh m = target.mesh; Vector3[] v = m.vertices; GUIContent content = new GUIContent("", ""); Handles.BeginGUI(); for (int i = 0; i < v.Length; i++) { if (w[i] < .0001f) { continue; } content.text = w[i].ToString("F2"); GUI.Label(HandleUtility.WorldPointToSizedRect(target.transform.TransformPoint(v[i]), content, EditorStyles.label), content); } Handles.EndGUI(); #endif #if DRAW_PER_VERTEX_ATTRIBUTES z_Mesh m = target.editableObject.editMesh; Color32[] colors = m.colors; Vector4[] tangents = m.tangents; List <Vector4> uv0 = m.uv0; List <Vector4> uv1 = m.uv1; List <Vector4> uv2 = m.uv2; List <Vector4> uv3 = m.uv3; int vertexCount = m.vertexCount; Vector3[] verts = m.vertices; GUIContent gc = new GUIContent(""); List <List <int> > common = z_MeshUtility.GetCommonVertices(m); System.Text.StringBuilder sb = new System.Text.StringBuilder(); Handles.BeginGUI(); foreach (List <int> l in common) { if (w[l[0]] < .001) { continue; } Vector3 v = target.transform.TransformPoint(verts[l[0]]); if (colors != null) { sb.AppendLine("color: " + colors[l[0]].ToString("F2")); } if (tangents != null) { sb.AppendLine("tangent: " + tangents[l[0]].ToString("F2")); } if (uv0 != null && uv0.Count == vertexCount) { sb.AppendLine("uv0: " + uv0[l[0]].ToString("F2")); } if (uv1 != null && uv1.Count == vertexCount) { sb.AppendLine("uv1: " + uv1[l[0]].ToString("F2")); } if (uv2 != null && uv2.Count == vertexCount) { sb.AppendLine("uv2: " + uv2[l[0]].ToString("F2")); } if (uv3 != null && uv3.Count == vertexCount) { sb.AppendLine("uv3: " + uv3[l[0]].ToString("F2")); } gc.text = sb.ToString(); sb.Remove(0, sb.Length); // @todo .NET 4.0 GUI.Label(HandleUtility.WorldPointToSizedRect(v, gc, EditorStyles.label), gc); } Handles.EndGUI(); #endif #endif }
public override void OnBrushApply(z_BrushTarget target, z_BrushSettings settings) { int rayCount = target.raycastHits.Count; if (rayCount < 1) { return; } Vector3 n = direction.ToVector3(); float scale = 1f / (Vector3.Scale(target.transform.lossyScale, n).magnitude); float sign = Event.current.shift ? -1f : 1f; float maxMoveDistance = settings.strength * STRENGTH_MODIFIER * sign * brushStrength; int vertexCount = target.editableObject.vertexCount; z_Mesh mesh = target.editableObject.editMesh; for (int ri = 0; ri < rayCount; ri++) { z_RaycastHit hit = target.raycastHits[ri]; if (hit.weights == null || hit.weights.Length < vertexCount) { continue; } if (direction == z_Direction.BrushNormal) { if (brushNormalIsSticky) { n = brushNormalOnBeginApply[ri]; } else { n = target.raycastHits[ri].normal; } scale = 1f / (Vector3.Scale(target.transform.lossyScale, n).magnitude); } for (int i = 0; i < commonVertexCount; i++) { int index = commonVertices[i][0]; if (hit.weights[index] < .0001f || (ignoreNonManifoldIndices && nonManifoldIndices.Contains(index))) { continue; } if (direction == z_Direction.VertexNormal) { n = normalLookup[index]; scale = 1f / (Vector3.Scale(target.transform.lossyScale, n).magnitude); } Vector3 pos = vertices[index] + n * (hit.weights[index] * maxMoveDistance * scale); List <int> indices = commonVertices[i]; for (int it = 0; it < indices.Count; it++) { vertices[indices[it]] = pos; } } } mesh.vertices = vertices; // different than setting weights on temp component, // which is what z_BrushModeMesh.OnBrushApply does. if (tempComponent != null) { tempComponent.OnVerticesMoved(mesh); } base.OnBrushApply(target, settings); }
public override void DrawGizmos(z_BrushTarget target, z_BrushSettings settings) { z_Mesh mesh = target.editableObject.editMesh; if (z_Util.IsValid(target) && paintMode == z_PaintMode.Fill) { Vector3[] vertices = mesh.vertices; int[] indices = mesh.GetTriangles(); z_Handles.PushMatrix(); z_Handles.PushHandleColor(); Handles.matrix = target.transform.localToWorldMatrix; int index = 0; foreach (z_RaycastHit hit in target.raycastHits) { if (hit.triangle > -1) { Handles.color = Color.green; index = hit.triangle * 3; Handles.DrawLine(vertices[indices[index + 0]] + hit.normal * .1f, vertices[indices[index + 1]] + hit.normal * .1f); Handles.DrawLine(vertices[indices[index + 1]] + hit.normal * .1f, vertices[indices[index + 2]] + hit.normal * .1f); Handles.DrawLine(vertices[indices[index + 2]] + hit.normal * .1f, vertices[indices[index + 0]] + hit.normal * .1f); _fillModeEdges[0].x = indices[index + 0]; _fillModeEdges[0].y = indices[index + 1]; _fillModeEdges[1].x = indices[index + 1]; _fillModeEdges[1].y = indices[index + 2]; _fillModeEdges[2].x = indices[index + 2]; _fillModeEdges[2].y = indices[index + 0]; for (int i = 0; i < 3; i++) { if (triangleLookup.TryGetValue(_fillModeEdges[i], out _fillModeAdjacentTris)) { for (int n = 0; n < _fillModeAdjacentTris.Count; n++) { index = _fillModeAdjacentTris[n] * 3; Handles.DrawLine(vertices[indices[index + 0]] + hit.normal * .1f, vertices[indices[index + 1]] + hit.normal * .1f); Handles.DrawLine(vertices[indices[index + 1]] + hit.normal * .1f, vertices[indices[index + 2]] + hit.normal * .1f); Handles.DrawLine(vertices[indices[index + 2]] + hit.normal * .1f, vertices[indices[index + 0]] + hit.normal * .1f); } } } } } z_Handles.PopHandleColor(); z_Handles.PopMatrix(); } else { base.DrawGizmos(target, settings); } }
public static List <z_CommonEdge> GetEdges(z_Mesh m) { Dictionary <int, int> lookup = GetCommonVertices(m).GetCommonLookup <int>(); return(GetEdges(m, lookup)); }
public static HashSet <z_CommonEdge> GetEdgesDistinct(z_Mesh mesh, out List <z_CommonEdge> duplicates) { Dictionary <int, int> lookup = GetCommonVertices(mesh).GetCommonLookup <int>(); return(GetEdgesDistinct(mesh, lookup, out duplicates)); }
// Called whenever the brush is moved. Note that @target may have a null editableObject. public override void OnBrushMove(z_BrushTarget target, z_BrushSettings settings) { base.OnBrushMove(target, settings); if (!z_Util.IsValid(target)) { return; } bool shift = Event.current.shift && Event.current.type != EventType.ScrollWheel; z_Mesh mesh = target.editableObject.editMesh; int vertexCount = mesh.vertexCount; float[] weights = target.GetAllWeights(); switch (paintMode) { case z_PaintMode.Flood: for (int i = 0; i < vertexCount; i++) { colors[i] = target_colors[i]; } break; case z_PaintMode.Fill: System.Array.Copy(colors_cache, colors, vertexCount); int[] indices = target.editableObject.editMesh.GetTriangles(); int index = 0; foreach (z_RaycastHit hit in target.raycastHits) { if (hit.triangle > -1) { index = hit.triangle * 3; colors[indices[index + 0]] = shift ? WHITE : target_colors[indices[index + 0]]; colors[indices[index + 1]] = shift ? WHITE : target_colors[indices[index + 1]]; colors[indices[index + 2]] = shift ? WHITE : target_colors[indices[index + 2]]; _fillModeEdges[0].x = indices[index + 0]; _fillModeEdges[0].y = indices[index + 1]; _fillModeEdges[1].x = indices[index + 1]; _fillModeEdges[1].y = indices[index + 2]; _fillModeEdges[2].x = indices[index + 2]; _fillModeEdges[2].y = indices[index + 0]; for (int i = 0; i < 3; i++) { if (triangleLookup.TryGetValue(_fillModeEdges[i], out _fillModeAdjacentTris)) { for (int n = 0; n < _fillModeAdjacentTris.Count; n++) { index = _fillModeAdjacentTris[n] * 3; colors[indices[index + 0]] = shift ? WHITE : target_colors[indices[index + 0]]; colors[indices[index + 1]] = shift ? WHITE : target_colors[indices[index + 1]]; colors[indices[index + 2]] = shift ? WHITE : target_colors[indices[index + 2]]; } } } } } break; default: { for (int i = 0; i < vertexCount; i++) { colors[i] = z_Util.Lerp(colors_cache[i], shift ? erase_colors[i] : target_colors[i], mask, weights[i]); } break; } } target.editableObject.editMesh.colors = colors; target.editableObject.ApplyMeshAttributes(z_MeshChannel.Color); }
/** * Returns a dictionary where each z_Edge is mapped to a list of triangle indices that share that edge. * To translate triangle list to vertex indices, multiply by 3 and take those indices (ex, triangles[index+{0,1,2}]) */ public static Dictionary <z_Edge, List <int> > GetAdjacentTriangles(z_Mesh m) { int len = m.GetTriangles().Length; if (len % 3 != 0 || len / 3 == m.vertexCount) { return(new Dictionary <z_Edge, List <int> >()); } Dictionary <z_Edge, List <int> > lookup = null; // @todo - should add some checks to make sure triangle structure hasn't changed if (adjacentTrianglesCache.TryGetValue(m, out lookup)) { return(lookup); } int smc = m.subMeshCount; lookup = new Dictionary <z_Edge, List <int> >(); List <int> connections; for (int n = 0; n < smc; n++) { int[] tris = m.GetIndices(n); for (int i = 0; i < tris.Length; i += 3) { int index = i / 3; z_Edge a = new z_Edge(tris[i], tris[i + 1]); z_Edge b = new z_Edge(tris[i + 1], tris[i + 2]); z_Edge c = new z_Edge(tris[i + 2], tris[i]); if (lookup.TryGetValue(a, out connections)) { connections.Add(index); } else { lookup.Add(a, new List <int>() { index }); } if (lookup.TryGetValue(b, out connections)) { connections.Add(index); } else { lookup.Add(b, new List <int>() { index }); } if (lookup.TryGetValue(c, out connections)) { connections.Add(index); } else { lookup.Add(c, new List <int>() { index }); } } } adjacentTrianglesCache.Add(m, lookup); return(lookup); }
/** * Let the temp mesh know that vertex positions have changed. */ public virtual void OnVerticesMoved(z_Mesh mesh) { }
public static Mesh CreateVertexBillboardMesh(z_Mesh src, List <List <int> > common) { int vertexCount = System.Math.Min(ushort.MaxValue / 4, common.Count()); Vector3[] positions = new Vector3[vertexCount * 4]; Vector2[] uv0 = new Vector2[vertexCount * 4]; Vector2[] uv2 = new Vector2[vertexCount * 4]; Color[] colors = new Color[vertexCount * 4]; int[] tris = new int[vertexCount * 6]; int n = 0; int t = 0; Vector3 up = Vector3.up; // * .1f; Vector3 right = Vector3.right; // * .1f; Vector3[] v = src.vertices; for (int i = 0; i < vertexCount; i++) { int tri = common[i][0]; positions[t + 0] = v[tri]; positions[t + 1] = v[tri]; positions[t + 2] = v[tri]; positions[t + 3] = v[tri]; uv0[t + 0] = Vector3.zero; uv0[t + 1] = Vector3.right; uv0[t + 2] = Vector3.up; uv0[t + 3] = Vector3.one; uv2[t + 0] = -up - right; uv2[t + 1] = -up + right; uv2[t + 2] = up - right; uv2[t + 3] = up + right; tris[n + 0] = t + 0; tris[n + 1] = t + 1; tris[n + 2] = t + 2; tris[n + 3] = t + 1; tris[n + 4] = t + 3; tris[n + 5] = t + 2; colors[t + 0] = clear; colors[t + 1] = clear; colors[t + 2] = clear; colors[t + 3] = clear; t += 4; n += 6; } Mesh m = new Mesh(); m.vertices = positions; m.uv = uv0; m.uv2 = uv2; m.colors = colors; m.triangles = tris; return(m); }