protected virtual void OnDestroy() { // In clearing the PolyMesh, its data is pooled. _polyMesh.Clear(); Pool <PolyMesh> .Recycle(_polyMesh); _unityMeshA.Clear(); Pool <Mesh> .Recycle(_unityMeshA); _unityMeshB.Clear(); Pool <Mesh> .Recycle(_unityMeshB); }
protected virtual void Awake() { _meshFilter = GetComponent <MeshFilter>(); _polyMesh = Pool <PolyMesh> .Spawn(); _polyMesh.DisableEdgeAdjacencyData(); _polyMesh.Clear(); _unityMeshA = Pool <Mesh> .Spawn(); _unityMeshA.Clear(); _unityMeshA.MarkDynamic(); _unityMeshB = Pool <Mesh> .Spawn(); _unityMeshB.Clear(); _unityMeshB.MarkDynamic(); }
/// <summary> /// Return a mesh that is the combination of both additionalVertexStreams and the originalMesh. /// - Position /// - UV0 /// - UV2 /// - UV3 /// - UV4 /// - Color /// - Tangent /// </summary> /// <returns>The new PolyMesh object</returns> private void GenerateCompositeMesh() { if (_editMesh == null) { _editMesh = polybrushMesh.polyMesh; } _editMesh.Clear(); _editMesh.name = originalMesh.name; _editMesh.vertices = GetAttribute(x => x.vertices); _editMesh.normals = GetAttribute(x => x.normals); _editMesh.colors = GetAttribute(x => x.colors32); _editMesh.tangents = GetAttribute(x => x.tangents); _editMesh.uv0 = GetAttribute(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(0, l); return(l); }); _editMesh.uv1 = GetAttribute(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(1, l); return(l); }); _editMesh.uv2 = GetAttribute(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(2, l); return(l); }); _editMesh.uv3 = GetAttribute(x => { List <Vector4> l = new List <Vector4>(); x.GetUVs(3, l); return(l); }); _editMesh.SetSubMeshes(originalMesh); }
public static void FillPolyMesh(this IPositionSpline spline, PolyMesh polyMesh, Matrix4x4?applyTransform = null, float?startT = null, float?endT = null, int?numSegments = null, float[] radii = null, float?radius = null, bool drawDebug = false) { float minT, maxT; int effNumSegments; //bool useRadiusArr = false; //float[] effRadii; float effRadius; bool useTransform; Matrix4x4 transform; RuntimeGizmos.RuntimeGizmoDrawer drawer = null; if (drawDebug) { RuntimeGizmos.RuntimeGizmoManager.TryGetGizmoDrawer(out drawer); } // Assign parameters based on optional inputs { minT = spline.minT; if (startT.HasValue) { minT = startT.Value; } maxT = spline.maxT; if (endT.HasValue) { maxT = endT.Value; } effNumSegments = 32; if (numSegments.HasValue) { effNumSegments = numSegments.Value; effNumSegments = Mathf.Max(1, effNumSegments); } //useRadiusArr = false; effRadius = 0.02f; if (radius.HasValue) { effRadius = radius.Value; } //effRadii = null; //if (radii != null) { // useRadiusArr = true; // effRadii = radii; //} useTransform = false; transform = Matrix4x4.identity; if (applyTransform.HasValue) { useTransform = true; transform = applyTransform.Value; } } // Multiple passes through the spline data will construct all the positions and // orientations we need to build the mesh. polyMesh.Clear(); var crossSection = new CircularCrossSection(effRadius, 16); float tStep = (maxT - minT) / effNumSegments; Vector3 position = Vector3.zero; Vector3 dPosition = Vector3.zero; Vector3?tangent = null; var positions = Pool <List <Vector3> > .Spawn(); positions.Clear(); var normals = Pool <List <Vector3> > .Spawn(); // to start, normals contain velocities, normals.Clear(); // but zero velocities are filtered out. var binormals = Pool <List <Vector3> > .Spawn(); binormals.Clear(); var crossSection0Positions = Pool <List <Vector3> > .Spawn(); crossSection0Positions.Clear(); var crossSection1Positions = Pool <List <Vector3> > .Spawn(); crossSection1Positions.Clear(); try { // Construct a rough list of positions and normals for each cross section. Some // of the normals may be zero, so we'll have to fix those. for (int i = 0; i <= effNumSegments; i++) { var t = minT + i * tStep; spline.ValueAndDerivativeAt(t, out position, out dPosition); if (useTransform) { positions.Add(transform.MultiplyPoint3x4(position)); normals.Add(transform.MultiplyVector(dPosition).normalized); } else { positions.Add(position); normals.Add(dPosition.normalized); } if (!tangent.HasValue && dPosition.sqrMagnitude > 0.001f * 0.001f) { tangent = (transform * dPosition.WithW(1)).ToVector3().normalized.Perpendicular(); } } // In case we never got a non-zero velocity, try to construct a tangent based on // delta positions. if (!tangent.HasValue) { if (positions[0] == positions[1]) { // No spline mesh possible; there's no non-zero length segment. return; } else { var delta = positions[1] - positions[0]; // Very specific case: Two points, each with zero velocity, use delta for // normals if (positions.Count == 2) { normals[0] = delta; normals[1] = delta; } tangent = delta.Perpendicular(); } } // Try to propagate non-zero normals into any "zero" normals. for (int i = 0; i <= effNumSegments; i++) { if (normals[i].sqrMagnitude < 0.00001f) { if (i == 0) { normals[i] = normals[i + 1]; } else if (i == effNumSegments) { normals[i] = normals[i - 1]; } else { normals[i] = Vector3.Slerp(normals[i - 1], normals[i + 1], 0.5f); } } if (normals[i].sqrMagnitude < 0.00001f) { // OK, we tried, but we still have zero normals. Error and fail. throw new System.InvalidOperationException( "Unable to build non-zero normals for this spline during PolyMesh " + "construction"); } } // With a set of normals and a starting tangent vector, we can construct all the // binormals we need to have an orientation and position for every cross-section. Vector3?lastNormal = null; Vector3?lastBinormal = null; for (int i = 0; i <= effNumSegments; i++) { var normal = normals[i]; Vector3 binormal; if (!lastBinormal.HasValue) { binormal = Vector3.Cross(normal, tangent.Value); } else { var rotFromLastNormal = Quaternion.FromToRotation(lastNormal.Value, normal); binormal = rotFromLastNormal * lastBinormal.Value; } binormals.Add(binormal); lastNormal = normal; lastBinormal = binormal; } // With positions, normals, and binormals for every cross section, add positions // and polygons for each cross section and their connections to the PolyMesh. int cs0Idx = -1, cs1Idx = -1; for (int i = 0; i + 1 <= effNumSegments; i++) { var pose0 = new Pose(positions[i], Quaternion.LookRotation(normals[i], binormals[i])); var pose1 = new Pose(positions[i + 1], Quaternion.LookRotation(normals[i + 1], binormals[i + 1])); if (drawDebug) { drawer.PushMatrix(); drawer.matrix = transform.inverse; drawer.color = LeapColor.blue; drawer.DrawRay(pose0.position, normals[i] * 0.2f); drawer.color = LeapColor.red; drawer.DrawRay(pose0.position, binormals[i] * 0.2f); drawer.PopMatrix(); } bool addFirstPositions = i == 0; // Add positions from Cross Section definition to reused buffers. if (addFirstPositions) { crossSection.FillPositions(crossSection0Positions, pose0); } crossSection.FillPositions(crossSection1Positions, pose1); // Add positions from buffers into the PolyMesh. if (addFirstPositions) { cs0Idx = polyMesh.positions.Count; polyMesh.AddPositions(crossSection0Positions); } cs1Idx = polyMesh.positions.Count; polyMesh.AddPositions(crossSection1Positions); // Add polygons to connect one cross section in the PolyMesh to the other. crossSection.AddConnectingPolygons(polyMesh, cs0Idx, cs1Idx); Utils.Swap(ref crossSection0Positions, ref crossSection1Positions); cs0Idx = cs1Idx; } } finally { positions.Clear(); Pool <List <Vector3> > .Recycle(positions); normals.Clear(); Pool <List <Vector3> > .Recycle(normals); binormals.Clear(); Pool <List <Vector3> > .Recycle(binormals); crossSection0Positions.Clear(); Pool <List <Vector3> > .Recycle(crossSection0Positions); crossSection1Positions.Clear(); Pool <List <Vector3> > .Recycle(crossSection1Positions); } }
private void refreshMesh() { if (outputToFilter == null) { return; } if (outputToFilter.sharedMesh == null) { outputToFilter.sharedMesh = new Mesh(); outputToFilter.sharedMesh.name = "PoseRibbonMesh Test"; } var mesh = outputToFilter.sharedMesh; mesh.Clear(); var pose0 = poseSource0.ToLocalPose(); var pose1 = poseSource1.ToLocalPose(); var pose2 = poseSource2.ToLocalPose(); var poses = Pool <List <Pose> > .Spawn(); poses.Clear(); try { poses.Add(pose0); poses.Add(pose1); poses.Add(pose2); if (!usePolyMeshMethod) { #region Non-PolyMesh Method var verts = Pool <List <Vector3> > .Spawn(); verts.Clear(); var indices = Pool <List <int> > .Spawn(); indices.Clear(); try { for (int i = 0; i < poses.Count; i++) { var p = poses[i]; verts.Add(left(p)); verts.Add(right(p)); } int vertsPerPose = 2; bool closeLoop = vertsPerPose != 2; for (int p = 0; p + 1 < poses.Count; p++) { for (int csi = 0; csi < vertsPerPose - (closeLoop ? 0 : 1); csi++) { var csRootIndex = p * vertsPerPose; var nextCSRootIndex = (p + 1) * vertsPerPose; var i0 = csRootIndex + csi; var i1 = nextCSRootIndex + csi; var i2 = nextCSRootIndex + ((csi + 1) % vertsPerPose); var i3 = csRootIndex + ((csi + 1) % vertsPerPose); indices.Add(i0); indices.Add(i1); indices.Add(i2); indices.Add(i0); indices.Add(i2); indices.Add(i3); } } mesh.SetVertices(verts); mesh.SetTriangles(indices, 0, true); mesh.RecalculateNormals(); } finally { verts.Clear(); Pool <List <Vector3> > .Recycle(verts); indices.Clear(); Pool <List <int> > .Recycle(indices); } #endregion } else { polyMesh.Clear(); // quad 0 polyMesh.AddPosition(left(pose0)); polyMesh.AddPosition(right(pose0)); polyMesh.AddPosition(left(pose1)); polyMesh.AddPosition(right(pose1)); var newPoly = Polygon.SpawnQuad(1, 0, 2, 3); polyMesh.AddPolygon(newPoly); // quad 1 polyMesh.AddPosition(left(pose2)); polyMesh.AddPosition(right(pose2)); var nextPoly = Polygon.SpawnQuad(3, 2, 4, 5); polyMesh.AddPolygon(nextPoly); // mark the edge between the two quads as smooth. polyMesh.MarkEdgeSmooth(new Edge(2, 3)); polyMesh.FillUnityMesh(mesh, doubleSided: true); } } finally { poses.Clear(); Pool <List <Pose> > .Recycle(poses); } }