private void lineSketchObjectTest() { foreach (Transform controlPoint in controlPointParent.transform) { strokeSketchObject.AddControlPoint(controlPoint.position); strokeSketchObject2.AddControlPoint(controlPoint.position); } strokeSketchObject.SetStrokeCrossSection(CircularCrossSection.GenerateVertices(16), CircularCrossSection.GenerateVertices(16, 1f), .5f); //lineSketchObject.setLineDiameter(.7f); StartCoroutine(changeDiameter()); //StartCoroutine(deactivateSelection(selection)); }
// Start is called before the first frame update void Start() { //Create a SketchWorld, many commands require a SketchWorld to be present SketchWorld = Instantiate(Defaults.SketchWorldPrefab).GetComponent <SketchWorld>(); //Create a LineSketchObject LineSketchObject = Instantiate(Defaults.LineSketchObjectPrefab).GetComponent <LineSketchObject>(); Invoker = new CommandInvoker(); Invoker.ExecuteCommand(new AddControlPointCommand(this.LineSketchObject, new Vector3(1, 2, 3))); Invoker.ExecuteCommand(new AddControlPointCommand(this.LineSketchObject, new Vector3(1, 4, 2))); Invoker.ExecuteCommand(new AddControlPointCommand(this.LineSketchObject, new Vector3(1, 5, 3))); Invoker.ExecuteCommand(new AddControlPointCommand(this.LineSketchObject, new Vector3(1, 5, 2))); Invoker.Undo(); Invoker.Redo(); LineBrush brush = this.LineSketchObject.GetBrush() as LineBrush; brush.CrossSectionVertices = CircularCrossSection.GenerateVertices(3); brush.CrossSectionNormals = CircularCrossSection.GenerateVertices(3, 1); Invoker.ExecuteCommand(new SetBrushCommand(this.LineSketchObject, brush)); //oder ohne Command //this.LineSketchObject.SetBrush(brush); //oder nur //this.LineSketchObject.SetLineCrossSection(... //Create a RibbonSketchObject RibbonSketchObject = Instantiate(Defaults.RibbonSketchObjectPrefab).GetComponent <RibbonSketchObject>(); Invoker.ExecuteCommand(new AddPointAndRotationCommand(RibbonSketchObject, new Vector3(1, 1, 1), Quaternion.identity)); Invoker.ExecuteCommand(new AddPointAndRotationCommand(RibbonSketchObject, new Vector3(1.5f, 1.1f, 1), Quaternion.Euler(0, 0, 0))); Invoker.ExecuteCommand(new AddPointAndRotationCommand(RibbonSketchObject, new Vector3(2f, 1.2f, 1), Quaternion.Euler(22, 0, 0))); Invoker.ExecuteCommand(new AddPointAndRotationCommand(RibbonSketchObject, new Vector3(2.5f, 1.3f, 1), Quaternion.Euler(45, 0, 0))); Invoker.ExecuteCommand(new AddPointAndRotationCommand(RibbonSketchObject, new Vector3(3f, 1.4f, 1), Quaternion.Euler(60, 0, 0))); //Create a PatchSketchObject PatchSketchObject = Instantiate(Defaults.PatchSketchObjectPrefab).GetComponent <PatchSketchObject>(); PatchSketchObject.Width = 3; Invoker.ExecuteCommand(new AddSegmentCommand(PatchSketchObject, new List <Vector3> { new Vector3(0, 0, 1), new Vector3(0, 1, 2), new Vector3(0, 0, 3) })); Invoker.ExecuteCommand(new AddSegmentCommand(PatchSketchObject, new List <Vector3> { new Vector3(1, 1, 1), new Vector3(1, 0, 2), new Vector3(1, 1, 3) })); Invoker.ExecuteCommand(new AddSegmentCommand(PatchSketchObject, new List <Vector3> { new Vector3(2, 0, 1), new Vector3(2, 1, 2), new Vector3(2, 0, 3) })); //Add the LineSketchObject to the SketchWorld Invoker.ExecuteCommand(new AddObjectToSketchWorldRootCommand(LineSketchObject, SketchWorld)); //Create a SketchObjectGroup and add objects to it SketchObjectGroup = Instantiate(Defaults.SketchObjectGroupPrefab).GetComponent <SketchObjectGroup>(); Invoker.ExecuteCommand(new AddToGroupCommand(SketchObjectGroup, RibbonSketchObject)); Invoker.ExecuteCommand(new AddToGroupCommand(SketchObjectGroup, PatchSketchObject)); //Add the SketchObjectGroup to the SketchWorld Invoker.ExecuteCommand(new AddObjectToSketchWorldRootCommand(SketchObjectGroup, SketchWorld)); //Serialize the SketchWorld to a XML file SavePath = System.IO.Path.Combine(Application.dataPath, "YourSketch.xml"); SketchWorld.SaveSketchWorld(SavePath); //Create another SketchWorld and load the serialized SketchWorld DeserializedSketchWorld = Instantiate(Defaults.SketchWorldPrefab).GetComponent <SketchWorld>(); DeserializedSketchWorld.LoadSketchWorld(SavePath); DeserializedSketchWorld.transform.position += new Vector3(5, 0, 0); //Export the SketchWorld as an OBJ file //SketchWorld.ExportSketchWorldToDefaultPath(); //Select the SketchObjectGroup SketchObjectSelection = Instantiate(Defaults.SketchObjectSelectionPrefab).GetComponent <SketchObjectSelection>(); Invoker.ExecuteCommand(new AddToSelectionAndHighlightCommand(SketchObjectSelection, SketchObjectGroup)); Invoker.ExecuteCommand(new ActivateSelectionCommand(SketchObjectSelection)); }
private void SketchWorldSerializationTest() { strokeSketchObject.AddControlPoint(new Vector3(-2, 1, 0)); strokeSketchObject.AddControlPoint(Vector3.one); strokeSketchObject.AddControlPoint(new Vector3(2, 2, 0)); strokeSketchObject.AddControlPoint(new Vector3(2, 1, 0)); //lineSketchObject.gameObject.GetComponent<MeshRenderer>().material = twoSidedMaterial; strokeSketchObject.gameObject.GetComponent <MeshRenderer>().material = ropeMaterial; strokeSketchObject.SetStrokeCrossSection(CircularCrossSection.GenerateVertices(4), CircularCrossSection.GenerateVertices(4, 1f), .4f); //lineSketchObject.setLineDiameter(.7f); //StartCoroutine(changeDiameter()); strokeSketchObject2.AddControlPoint(new Vector3(1, 0, 0)); strokeSketchObject2.AddControlPoint(new Vector3(2, 1, 1)); strokeSketchObject2.AddControlPoint(new Vector3(3, 2, 0)); strokeSketchObject2.AddControlPoint(new Vector3(4, 4, 4)); strokeSketchObject2.DeleteControlPoint(); strokeSketchObject2.DeleteControlPoint(); strokeSketchObject2.DeleteControlPoint(); strokeSketchObject2.DeleteControlPoint(); strokeSketchObject2.DeleteControlPoint(); strokeSketchObject2.AddControlPoint(new Vector3(1, 0, 0)); strokeSketchObject2.AddControlPoint(new Vector3(2, 1, 1)); strokeSketchObject2.AddControlPoint(new Vector3(3, 2, 0)); strokeSketchObject2.AddControlPoint(new Vector3(4, 4, 4)); strokeSketchObject2.GetComponent <MeshRenderer>().material.color = Color.blue; strokeSketchObject2.gameObject.GetComponent <MeshRenderer>().material = ropeMaterial; patchSketchObject.transform.position += new Vector3(3, 0, 0); patchSketchObject.Width = 3; patchSketchObject.AddPatchSegment(new List <Vector3> { new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(2, 0, 0) }); patchSketchObject.AddPatchSegment(new List <Vector3> { new Vector3(0, 0, 1), new Vector3(1, 2, 1), new Vector3(2, 0, 1) }); patchSketchObject.AddPatchSegment(new List <Vector3> { new Vector3(0, 0, 2), new Vector3(1, 0, 2), new Vector3(2, 0, 2) }); (List <Vector3> points, List <Quaternion> rotations) = RibbonTest.GetPointTransformation(ControlPointParent); ribbonSketchObject.SetControlPoints(points, rotations); SketchWorld.AddObject(ribbonSketchObject); //lineSketchObject2.minimumControlPointDistance = 2f; //lineSketchObject2.addControlPointContinuous(new Vector3(3, 1, 0)); GameObject groupGO = new GameObject("sketchObjectGroup", typeof(SketchObjectGroup)); SketchObjectGroup group = groupGO.GetComponent <SketchObjectGroup>(); group.defaults = this.defaults; SketchWorld.AddObject(strokeSketchObject); group.AddToGroup(strokeSketchObject2); group.AddToGroup(patchSketchObject); group.transform.position += new Vector3(2.568f, 5.555f, 1.123f); SketchWorld.AddObject(group); string worldXmlPath = System.IO.Path.Combine(Application.dataPath, "SketchWorldTest.xml"); SketchWorld.SaveSketchWorld(worldXmlPath); SketchWorld2.LoadSketchWorld(worldXmlPath); SerializeBrushCollection(); //SketchObjectGroupData groupData = group.GetData(); //string xmlFilePath = Serializer.WriteTestXmlFile<SketchObjectGroupData>(groupData); //Serializer.DeserializeFromXmlFile<SketchObjectGroupData>(out SketchObjectGroupData readGrouptData, xmlFilePath); //Debug.Log(readGrouptData.SketchObjects[0].GetType()); //SketchObjectGroup deserGroup = Instantiate(defaults.SketchObjectGroupPrefab).GetComponent<SketchObjectGroup>(); //deserGroup.ApplyData(readGrouptData); //deserGroup.transform.position += new Vector3(3, 0, 0); }
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); } }