// https://blackpawn.com/texts/pointinpoly/ bool IsSameSide(MyVector3 p1, MyVector3 p2, MyVector3 a, MyVector3 b) { var cp1 = MyVector3.Cross(b - a, p1 - a); var cp2 = MyVector3.Cross(b - a, p2 - a); return(MyVector3.Dot(cp1, cp2) >= 0); }
List <MyVector3> ProjectTrajAccording2Profile(List <MyVector2> trajpoints) { List <MyVector3> output = new List <MyVector3>(); MyVector3 profilenormal = this.topCircle.Normal; MyVector3 profilecenter = this.topCircle.Center; MyVector3 viewvector = this.camera.target; //suppose to be (0,0,1) //find a plane that is almost vertical to view vector and the normal line of profile is on the plane MyVector3 temp = profilenormal.Cross(viewvector); MyVector3 targetplanenormal = profilenormal.Cross(temp); targetplane = new MyPlane(profilecenter, targetplanenormal); output = this.Proj2dToPlane(targetplane, trajpoints); return(output); }
//calculate the x velocity resulting from the ball sliding on the floor for a time deltaTime private MyVector3 HorizontalVelocityAfterSliding(float deltaTime) { if (pureRolling) { return(velocityPreviousFrame); } MyVector3 afterSlidingVel; MyVector3 horizontal_velocityPreviousFrame = new MyVector3(velocityPreviousFrame.getX(), 0, velocityPreviousFrame.getZ()); //calculate the variation in the angular momentum and x component of the linear momentum float arbitraryConst1 = 5f; MyVector3 frictionDirection = horizontal_velocityPreviousFrame.Scale(-1).UnitVector(); MyVector3 linearMomentumVariation = frictionDirection.Scale( arbitraryConst1 * floorFriction * mass * deltaTime); MyVector3 angularMomentumVariation = MyVector3.Cross( new MyVector3(0, -radius, 0), linearMomentumVariation); afterSlidingVel = MyVector3.Add(horizontal_velocityPreviousFrame, linearMomentumVariation.Scale(1 / mass)); angularMomentumCurrentFrame = MyVector3.Add(angularMomentumCurrentFrame, angularMomentumVariation); MyVector3 contactPointTangentVel = MyVector3.Cross(AngularVelocity(angularMomentumCurrentFrame), new MyVector3(0, -radius, 0)); if (contactPointTangentVel.Magnitude() > afterSlidingVel.Magnitude()) { pureRolling = true; //calculate the rolling horizintal velocity //pure rolling law: speed = (radius) * (angular vel) float MRsquared_over_I = (mass * radius * radius) / momentOfInertia; afterSlidingVel = MyVector3.Subtract(afterSlidingVel.Scale(MRsquared_over_I), contactPointTangentVel).Scale(1 / (1 + MRsquared_over_I)); angularMomentumCurrentFrame = MyVector3.Cross(afterSlidingVel, new MyVector3(0, -1, 0)).Scale(momentOfInertia / radius); } return(afterSlidingVel); }
private static MyVector3 Get3PlanesInterPoint(ref MyPlane p1, ref MyPlane p2, ref MyPlane p3) { //P = -d1 * N2xN3 / N1.N2xN3 - d2 * N3xN1 / N2.N3xN1 - d3 * N1xN2 / N3.N1xN2 MyVector3 v = -p1.D * MyVector3.Cross(p2.Normal, p3.Normal) / MyVector3.Dot(p1.Normal, MyVector3.Cross(p2.Normal, p3.Normal)) - p2.D * MyVector3.Cross(p3.Normal, p1.Normal) / MyVector3.Dot(p2.Normal, MyVector3.Cross(p3.Normal, p1.Normal)) - p3.D * MyVector3.Cross(p1.Normal, p2.Normal) / MyVector3.Dot(p3.Normal, MyVector3.Cross(p1.Normal, p2.Normal)); return(v); }
/// <summary> /// Extracts perspective camera parameters from the frustum, doesn't work with orthographic frustums. /// </summary> /// <returns>Perspective camera parameters from the frustum</returns> public MyFrustumCameraParams GetCameraParams() { var corners = GetCorners(); var cameraParam = new MyFrustumCameraParams(); cameraParam.Position = Get3PlanesInterPoint(ref pRight, ref pTop, ref pLeft); cameraParam.LookAtDir = pNear.Normal; cameraParam.UpDir = MyVector3.Normalize(MyVector3.Cross(pRight.Normal, pNear.Normal)); cameraParam.FOV = (float)((Math.PI / 2.0 - Math.Acos(MyVector3.Dot(pNear.Normal, pTop.Normal))) * 2); cameraParam.AspectRatio = (corners[6] - corners[5]).Length() / (corners[4] - corners[5]).Length(); cameraParam.ZNear = (cameraParam.Position + (pNear.Normal * pNear.D)).Length(); cameraParam.ZFar = (cameraParam.Position + (pFar.Normal * pFar.D)).Length(); return(cameraParam); }
/// <summary> /// Creates a new frustum relaying on perspective camera parameters /// </summary> /// <param name="cameraPos">The camera pos.</param> /// <param name="lookDir">The look dir.</param> /// <param name="upDir">Up dir.</param> /// <param name="fov">The fov.</param> /// <param name="znear">The znear.</param> /// <param name="zfar">The zfar.</param> /// <param name="aspect">The aspect.</param> /// <returns>The bounding frustum calculated from perspective camera</returns> public static MyBoundingFrustum FromCamera(MyVector3 cameraPos, MyVector3 lookDir, MyVector3 upDir, float fov, float znear, float zfar, float aspect) { //http://knol.google.com/k/view-frustum lookDir = MyVector3.Normalize(lookDir); upDir = MyVector3.Normalize(upDir); MyVector3 nearCenter = cameraPos + lookDir * znear; MyVector3 farCenter = cameraPos + lookDir * zfar; float nearHalfHeight = (float)(znear * Math.Tan(fov / 2f)); float farHalfHeight = (float)(zfar * Math.Tan(fov / 2f)); float nearHalfWidth = nearHalfHeight * aspect; float farHalfWidth = farHalfHeight * aspect; MyVector3 rightDir = MyVector3.Normalize(MyVector3.Cross(upDir, lookDir)); MyVector3 Near1 = nearCenter - nearHalfHeight * upDir + nearHalfWidth * rightDir; MyVector3 Near2 = nearCenter + nearHalfHeight * upDir + nearHalfWidth * rightDir; MyVector3 Near3 = nearCenter + nearHalfHeight * upDir - nearHalfWidth * rightDir; MyVector3 Near4 = nearCenter - nearHalfHeight * upDir - nearHalfWidth * rightDir; MyVector3 Far1 = farCenter - farHalfHeight * upDir + farHalfWidth * rightDir; MyVector3 Far2 = farCenter + farHalfHeight * upDir + farHalfWidth * rightDir; MyVector3 Far3 = farCenter + farHalfHeight * upDir - farHalfWidth * rightDir; MyVector3 Far4 = farCenter - farHalfHeight * upDir - farHalfWidth * rightDir; var result = new MyBoundingFrustum(); result.pNear = new MyPlane(Near1, Near2, Near3); result.pFar = new MyPlane(Far3, Far2, Far1); result.pLeft = new MyPlane(Near4, Near3, Far3); result.pRight = new MyPlane(Far1, Far2, Near2); result.pTop = new MyPlane(Near2, Far2, Far3); result.pBottom = new MyPlane(Far4, Far1, Near1); result.pNear.Normalize(); result.pFar.Normalize(); result.pLeft.Normalize(); result.pRight.Normalize(); result.pTop.Normalize(); result.pBottom.Normalize(); result.pMatrix = MyMatrix.LookAtLH(cameraPos, cameraPos + lookDir * 10, upDir) * MyMatrix.PerspectiveFovLH(fov, aspect, znear, zfar); return(result); }
void LateUpdate() { //CONSTRAINTS for (int i = jointsPositions.Length - 2; i >= 0; i--) { if (i > 0) { ToParent = new MyVector3(joints[i - 1].position.x - joints[i].position.x, joints[i - 1].position.y - joints[i].position.y, joints[i - 1].position.z - joints[i].position.z).normalized(); ToChild = new MyVector3(joints[i + 1].position.x - joints[i].position.x, joints[i + 1].position.y - joints[i].position.y, joints[i + 1].position.z - joints[i].position.z).normalized(); axis = MyVector3.Cross(ToParent, ToChild).normalized(); float angle = Mathf.Acos(MyVector3.Dot(ToParent, ToChild) / (ToParent.magnitude() * ToChild.magnitude())) * Mathf.Rad2Deg; if (angle > maxAngle || angle < ((i == 1) ? minAngle * 4 : minAngle)) { angle = Mathf.Clamp(angle, ((i == 1) ? minAngle * 4 : minAngle), maxAngle); joints[i].rotation = joints[i - 1].rotation; joints[i].Rotate(new Vector3(axis.x, axis.y, axis.z), 180 + angle, Space.World); } } else if (i == 0) { ToParent = new MyVector3(0, -1, 0); ToChild = new MyVector3(joints[i + 1].position.x - joints[i].position.x, joints[i + 1].position.y - joints[i].position.y, joints[i + 1].position.z - joints[i].position.z).normalized(); axis = MyVector3.Cross(ToParent, ToChild).normalized(); float angle = Mathf.Acos(MyVector3.Dot(ToParent, ToChild) / (ToParent.magnitude() * ToChild.magnitude())) * Mathf.Rad2Deg; if (angle > maxAngle + maxAngle / 4 || angle < maxAngle - maxAngle / 4) { angle = Mathf.Clamp(angle, maxAngle - maxAngle / 4, maxAngle + maxAngle / 4); joints[i].rotation = Quaternion.identity; joints[i].Rotate(new Vector3(axis.x, axis.y, axis.z), 240 + angle, Space.World); } } } }
void Update() { // Copy the joints positions to work with //TODO copy[0] = new MyVector3(joints[0].position); //copy[0] = joints[0].position; for (int i = 0; i < joints.Length - 1; i++) { copy[i + 1] = new MyVector3(joints[i + 1].position); distances[i] = (copy[i + 1] - copy[i]).Module(); //copy[i + 1] = joints[i + 1].position; //distances[i] = (copy[i + 1] - copy[i]).magnitude; } // CALCULATE ALSO THE DISTANCE BETWEEN JOINTS //done = TODO done = (copy[copy.Length - 1] - new MyVector3(target.position)).Module() < tresholdCondition; //done = (copy[copy.Length - 1] - target.position).magnitude < tresholdCondition; if (!done) { float targetRootDist = (copy[0] - new MyVector3(target.position)).Module(); //float targetRootDist = Vector3.Distance(copy[0], target.position); // Update joint positions if (targetRootDist > distances.Sum()) { // The target is unreachable for (int i = 0; i < copy.Length - 1; i++) { float r = (new MyVector3(target.position) - copy[i]).Module(); //float r = (target.position - copy[i]).magnitude; float lambda = distances[i] / r; copy[i + 1] = (1 - lambda) * copy[i] + (lambda * new MyVector3(target.position)); //copy[i + 1] = (1 - lambda) * copy[i] + (lambda * target.position); } } else { MyVector3 b = copy[0]; //Vector3 b = copy[0]; // The target is reachable //while (TODO) float difference = (copy[copy.Length - 1] - new MyVector3(target.position)).Module(); //float difference = (copy[copy.Length - 1] - target.position).magnitude; while (difference > tresholdCondition) // treshold = tolerance { // numIterations++; // STAGE 1: FORWARD REACHING //TODO copy[copy.Length - 1] = new MyVector3(target.position); //copy[copy.Length - 1] = target.position; for (int i = copy.Length - 2; i > 0; i--) { float r = (copy[i + 1] - copy[i]).Module(); //float r = (copy[i + 1] - copy[i]).magnitude; float lambda = distances[i] / r; copy[i] = (1 - lambda) * copy[i + 1] + lambda * copy[i]; } // STAGE 2: BACKWARD REACHING //TODO copy[0] = b; for (int i = 0; i < copy.Length - 1; i++) { float r = (copy[i + 1] - copy[i]).Module(); //float r = (copy[i + 1] - copy[i]).magnitude; float lambda = distances[i] / r; copy[i + 1] = (1 - lambda) * copy[i] + lambda * copy[i + 1]; } difference = (copy[copy.Length - 1] - new MyVector3(target.position)).Module(); //difference = (copy[copy.Length - 1] - target.position).magnitude; } } // Update original joint rotations for (int i = 0; i <= joints.Length - 2; i++) { // float originalAngle = joints[i].rotation.w; MyQuat parentRotation = new MyQuat(joints[i + 1].rotation); MyQuat childRotation = new MyQuat(joints[i].rotation); //TODO // Rotation MyVector3 vectorA = new MyVector3(joints[i + 1].position) - new MyVector3(joints[i].position); MyVector3 vectorB = copy[i + 1] - copy[i]; //Vector3 vectorA = joints[i + 1].position - joints[i].position; //Vector3 vectorB = copy[i + 1] - copy[i]; // float angle = Mathf.Acos(Vector3.Dot(vectorA.normalized, vectorB.normalized)) * Mathf.Rad2Deg; float cosA = (MyVector3.Dot(vectorA.Normalize(), vectorB.Normalize())); float sinA = MyVector3.Cross(vectorA.Normalize(), vectorB.Normalize()).Module(); //float cosA = (Vector3.Dot(vectorA.normalized, vectorB.normalized)); //float sinA = Vector3.Cross(vectorA.normalized, vectorB.normalized).magnitude; // Atan = Cos | Atan2 = denominador y... float angle = Mathf.Atan2(sinA, cosA) * Mathf.Rad2Deg; MyVector3 axis = MyVector3.Cross(vectorA, vectorB).Normalize(); //Vector3 axis = Vector3.Cross(vectorA, vectorB).normalized; // joints[i].rotation = Quaternion.AngleAxis(angle, axis) * joints[i].rotation; joints[i].rotation = MyQuat.Multiply(MyQuat.Axis2Quad(angle, axis), childRotation).ToUnityQuat(); //joints[i].rotation = MyQuat.Multiply(MyQuat.Axis2Quad(angle, axis), childRotation).ToUnityQuat(); childRotation = new MyQuat(joints[i].rotation); float angleTest = MyQuat.Angle(parentRotation, childRotation); if (Mathf.Abs(angleTest) > maxAngleRotation) { joints[i + 1].rotation = joints[i].rotation; } joints[i + 1].position = new Vector3(copy[i + 1].x, copy[i + 1].y, copy[i + 1].z); //joints[i + 1].position = copy[i + 1]; } } }
void Update() { // Copy the joints positions to work with for (int i = 0; i < joints.Length; i++) { copy[i] = new MyVector3(joints[i].position.x, joints[i].position.y, joints[i].position.z); //Copy the joints if (i < joints.Length - 1) { distances[i] = MyVector3.Distance(joints[i + 1].position, joints[i].position); //Calculate the distances } } done = (copy[copy.Length - 1] - new MyVector3(target.position.x, target.position.y, target.position.z)).magnitude < treshold_condition; if (!done) { float targetRootDist = MyVector3.Distance(copy[0], new MyVector3(target.position.x, target.position.y, target.position.z)); // Update joint positions if (targetRootDist > distances.Sum()) { // The target is unreachable for (int i = 0; i < copy.Length - 1; i++) { float r = (new MyVector3(target.position.x, target.position.y, target.position.z) - copy[i]).magnitude; float lambda = distances[i] / r; copy[i + 1] = copy[i] * (1 - lambda) + new MyVector3(target.position.x, target.position.y, target.position.z) * lambda; } } else { MyVector3 b = copy[0]; float difA = (copy[copy.Length - 1] - new MyVector3(target.position.x, target.position.y, target.position.z)).magnitude; // The target is reachable while (difA > treshold_condition) { // STAGE 1: FORWARD REACHING copy[copy.Length - 1] = new MyVector3(target.position.x, target.position.y, target.position.z); for (int i = copy.Length - 2; i > 0; i--) { float r = (copy[i + 1] - copy[i]).magnitude; float lambda = distances[i] / r; copy[i] = copy[i + 1] * (1 - lambda) + copy[i] * lambda; } // STAGE 2: BACKWARD REACHING copy[0] = b; for (int i = 0; i < copy.Length - 1; i++) { float r = (copy[i + 1] - copy[i]).magnitude; float lambda = distances[i] / r; copy[i + 1] = copy[i] * (1 - lambda) + copy[i + 1] * lambda; } difA = (copy[copy.Length - 1] - new MyVector3(target.position.x, target.position.y, target.position.z)).magnitude; } } // Update original joint rotations for (int i = 0; i <= joints.Length - 2; i++) { MyQuaternion parentQuat = new MyQuaternion(joints[i + 1].rotation); MyQuaternion myQuat = new MyQuaternion(joints[i].rotation); MyVector3 A = new MyVector3(joints[i + 1].position - joints[i].position); MyVector3 B = copy[i + 1] - copy[i]; float cosa = MyVector3.Dot(MyVector3.Normalize(A), MyVector3.Normalize(B)); float sina = MyVector3.Cross(MyVector3.Normalize(A), MyVector3.Normalize(B)).magnitude; float alpha = Mathf.Atan2(sina, cosa) * Mathf.Rad2Deg; MyVector3 myAxis = MyVector3.Normalize(MyVector3.Cross(A, B)); //Vector3 axis = new Vector3(myAxis.x, myAxis.y, myAxis.z); myQuat = MyQuaternion.AngleAxis(alpha, ref myAxis); Quaternion quat = new Quaternion(myQuat.x, myQuat.y, myQuat.z, myQuat.w); joints[i].rotation = quat * joints[i].rotation; //joints[i].rotation = Quaternion.AngleAxis(alpha, axis) * joints[i].rotation; myQuat = new MyQuaternion(joints[i].rotation); float localAngle = MyQuaternion.Angle(parentQuat, myQuat); if (Mathf.Abs(localAngle) > maxRotation) { joints[i + 1].rotation = joints[i].rotation; } joints[i + 1].position = new Vector3(copy[i + 1].x, copy[i + 1].y, copy[i + 1].z); } } }
private void RayTracein3DPlane(List <MyVector3> points, MyVector3 curp, MyVector3 curdire, MyVector3 sectionPlaneNormal, out int norInsec, out int notNorInsec) { // Param double insecPs_Dist_theshold = 0.01; double insecP_DistBetweenRay_theshold = 20; MyVector3 cutNormal = sectionPlaneNormal.Cross(curdire).Normalize(); ray = new Line3(curp, cutNormal); norInsec = -1; // Normal side notNorInsec = -1; // Not Normal side double dist_left = double.MaxValue; double dist_right = double.MaxValue; for (int i = 0; i < points.Count; i++) { double dist_temp = ray.DistanceToLine(points[i]); if ((points[i] - curp).Dot(cutNormal) > 0) { // Normal side if (dist_left > dist_temp) { dist_left = dist_temp; norInsec = i; } } else { // Not Normal side if (dist_right > dist_temp) { dist_right = dist_temp; notNorInsec = i; } } } if (norInsec == -1) { norInsec = notNorInsec; System.Console.WriteLine("Warining: norInsec == -1"); return; } else if (notNorInsec == -1) { notNorInsec = norInsec; System.Console.WriteLine("Warining: notNorInsec == -1"); return; } else if (norInsec == -1 && notNorInsec == -1) { System.Console.WriteLine("Error: Ray Tracein3DPlane, no intersection points"); return; } if (MyVector3.Distance(points[norInsec], points[notNorInsec]) < insecPs_Dist_theshold) { // this two intersection is too close, so let them become same one.s System.Console.WriteLine("Warining: two intersection is too close"); norInsec = notNorInsec; return; } if (ray.DistanceToLine(points[norInsec]) > insecP_DistBetweenRay_theshold || ray.DistanceToLine(points[notNorInsec]) > insecP_DistBetweenRay_theshold) { System.Console.WriteLine("Warining: two intersection is too far"); // this two intersection is too far, so let them become same one.s norInsec = notNorInsec; return; } }
public void CylinderSnapping() { // Get Boundary2 if (boundaryPoints_2d == null) { boundaryPoints_2d = GetBoundaryPoints(mark); } List <MyVector2> boundary2 = ExtractOutline(edgeImage, boundaryPoints_2d); // Project 2D edge points //topCircle = new MyCircle(topCircle.Center, topCircle.Radius, -topCircle.Normal); MyVector3 normal = topCircle.Normal.Cross(this.camera.target).Cross(topCircle.Normal); MyPlane sectionPlane = new MyPlane(topCircle.Center, normal); boundary3 = Proj2dToPlane(sectionPlane, boundary2); topCircle = CiriFixTopCircle(topCircle, boundary3); // UpdateCircleNormal // foreach (var pbondary3 in pbondary3) // { // } // if (topCircle.Center) //{ //} // Algorithm Init Params double offset = topCircle.Radius / 50; cur_p = topCircle.Center - offset * topCircle.Normal; cur_dire = 1.0 * topCircle.Normal; MyVector3 cur_dire_new = new MyVector3(cur_dire); MyVector3 cur_p_new = new MyVector3(-1 * cur_p); Insection1 = new MyVector3(1, 1, 1); Insection2 = new MyVector3(0, 0, 0); int norInsec = -1; int notNorInsec = -1; MyVector3 tangential1 = new MyVector3(1, 1, 1); MyVector3 tangential2 = new MyVector3(1, 1, 1); List <MyCircle> CircleLists = new List <MyCircle>(); CircleLists.Add(topCircle); // Fix first circle int iter = 0; double r = double.MaxValue; System.Console.WriteLine(Insection1.Dot(tangential2)); System.Console.WriteLine(Math.Cos(2.0 / 3.0 * Math.PI)); int MaxInter = 1000; GeneratedCenters = new List <MyVector3>(); List <double> radius = new List <double>(); List <double> weights = new List <double>(); List <MyVector3> dires = new List <MyVector3>(); while (--MaxInter > 0) // { if (Insection1 == Insection2) // 交点一直保持相同 { System.Console.WriteLine("Warning: Insection is same!"); // 半径过小 break; } if (cur_dire.Dot(cur_dire_new) < 0) // 移动方向反向 { System.Console.WriteLine("Warning: Move Direction!"); break; } if (cur_p + offset * cur_dire == cur_p_new) // 中心点没有移动 { System.Console.WriteLine("Warning: Center not move!"); break; } RayTracein3DPlane(boundary3, cur_p_new, cur_dire_new.Cross(sectionPlane.Normal()), sectionPlane.Normal(), out norInsec, out notNorInsec); System.Console.WriteLine("{0} , {1}", MyVector3.Distance(boundary3[norInsec], cur_p_new), MyVector3.Distance(boundary3[notNorInsec], cur_p_new)); test1 = new Line3(boundary3[norInsec], cur_p_new - boundary3[norInsec]); test2 = new Line3(boundary3[notNorInsec], cur_p_new - boundary3[notNorInsec]); if (MyVector3.Distance(boundary3[norInsec], cur_p_new) < topCircle.Radius / 20 || // close to bottom MyVector3.Distance(boundary3[notNorInsec], cur_p_new) < topCircle.Radius / 20) { System.Console.WriteLine("Warning: Close to bottom!"); break; } if (tangential1.Dot(tangential2) < Math.Cos(2.0 / 3.0 * Math.PI)) //切线相向 { System.Console.WriteLine("Warning: tangential get oppsite direction!"); break; } if (r < 0.0001) { System.Console.WriteLine("Warning: Radius is too small!"); // 半径过小 break; } //if (MyVector3.Distance(cur_p, cur_p_new) ) //{ // System.Console.WriteLine("Warning: Radius is too small!"); // 半径过小 // break; //} if (iter != 0) { //offset = 1 / MyVector3.Distance(cur_p, cur_p_new) * 0.000001 + 0.5 * offset; offset = topCircle.Radius / 20; //System.Console.WriteLine("{0}", offset); cur_dire = cur_dire_new; cur_p = cur_p_new + offset * cur_dire; CircleLists.Add(new MyCircle(cur_p, r, cur_dire)); // Get Data for Fit double weight = Math.Abs(cur_dire_new.Dot(cur_dire)); GeneratedCenters.Add(cur_p_new); weights.Add(weight); radius.Add(r); dires.Add(cur_dire); } // Step1: Get IntersectionPoitn RayTracein3DPlane(boundary3, cur_p, cur_dire, sectionPlane.Normal(), out norInsec, out notNorInsec); // Step2 : Get Two Local Tangential Insection1 = boundary3[norInsec]; Insection2 = boundary3[notNorInsec]; tangential1 = GetLocalTangential(norInsec, boundary3, cur_dire); tangential2 = GetLocalTangential(notNorInsec, boundary3, cur_dire); // Visualization setdirecLine = new Line3(cur_p, cur_dire); setLine1 = new Line3(Insection1, tangential1); setLine2 = new Line3(Insection2, tangential2); // Step3 : Get New Cur Direction and Cur Point cur_dire_new = (tangential1 + tangential2) / 2; RayTracein3DPlane(boundary3, cur_p, cur_dire_new, sectionPlane.Normal(), out norInsec, out notNorInsec); cur_p_new = (boundary3[norInsec] + boundary3[notNorInsec]) / 2; r = 0.5 * MyVector3.Distance(boundary3[norInsec], boundary3[notNorInsec]); iter++; this.view.Refresh(); } // Fit centers and radius; GeneratedCenters = FittingCentersCurve(GeneratedCenters, weights); int inter = 1; while (inter-- > 0) { radius = FittRadius(radius); } // ReBuild Object CircleLists.Clear(); CircleLists.Add(topCircle); // Fix first circle for (int i = 0; i < GeneratedCenters.Count; i++) { CircleLists.Add(new MyCircle(GeneratedCenters[i], radius[i], dires[i])); } CurveCyliner = new SweepMesh(CircleLists); }
void Update() { if (target.position.y > 1.25f) { for (int i = 0; i < joints.Length; i++) { jointsPositions[i] = new MyVector3(joints[i].position.x, joints[i].position.y, joints[i].position.z); } targetPosition = new MyVector3(target.position.x, target.position.y, target.position.z); // Copy the joints positions to work with // and calculate all the distances for (int i = 0; i < copy.Length; i++) { copy[i] = jointsPositions[i]; if (i < distances.Length) { distances[i] = (jointsPositions[i + 1] - jointsPositions[i]).magnitude(); } } done = (targetPosition - jointsPositions[jointsPositions.Length - 1]).magnitude() < threshold_distance; if (!done) { float targetRootDist = MyVector3.Distance(copy[0], targetPosition); // Update joint positions if (targetRootDist > distances.Sum()) { // The target is unreachable for (int i = 0; i < copy.Length - 1; i++) { float dist = (targetPosition - copy[i]).magnitude(); float lam = distances[i] / dist; copy[i + 1] = (1 - lam) * copy[i] + lam * targetPosition; } } else { // The target is reachable iter = 0; while (!done /*|| iter < maxIter*/) { // STAGE 1: FORWARD REACHING copy[copy.Length - 1] = targetPosition; for (int i = copy.Length - 1; i > 0; i--) { MyVector3 temp = (copy[i - 1] - copy[i]).normalized(); temp = temp * distances[i - 1]; copy[i - 1] = temp + copy[i]; } // STAGE 2: BACKWARD REACHING copy[0] = jointsPositions[0]; for (int i = 0; i < copy.Length - 2; i++) { MyVector3 temp = (copy[i + 1] - copy[i]).normalized(); temp = temp * distances[i]; copy[i + 1] = temp + copy[i]; } done = (targetPosition - copy[copy.Length - 1]).magnitude() < threshold_distance; iter++; } } // Update original joint rotations for (int i = 0; i <= joints.Length - 2; i++) { MyVector3 a = jointsPositions[i + 1] - jointsPositions[i]; MyVector3 b = copy[i + 1] - copy[i]; MyVector3 axis = MyVector3.Cross(a, b).normalized(); float cosa = MyVector3.Dot(a, b) / (a.magnitude() * b.magnitude()); float sina = MyVector3.Cross(a.normalized(), b.normalized()).magnitude(); float angle = Mathf.Atan2(sina, cosa); MyQuaternion q = new MyQuaternion(Mathf.Cos(angle / 2), axis.x * Mathf.Sin(angle / 2), axis.y * Mathf.Sin(angle / 2), axis.z * Mathf.Sin(angle / 2)); MyQuaternion actualRot = new MyQuaternion(joints[i].rotation.w, joints[i].rotation.x, joints[i].rotation.y, joints[i].rotation.z); MyQuaternion newRot = MyQuaternion.multiply(q, actualRot); jointsPositions[i] = copy[i]; joints[i].position = new Vector3(jointsPositions[i].x, jointsPositions[i].y, jointsPositions[i].z); joints[i].rotation = new Quaternion(newRot.x, newRot.y, newRot.z, newRot.w); for (int j = i; j < joints.Length; j++) //Actualizar posiciones de los hijos despues de rotar { jointsPositions[j] = new MyVector3(joints[j].position.x, joints[j].position.y, joints[j].position.z); } } } } }
private void FixedUpdate() { //simulation start upon press of the spacebar if (Input.GetKeyDown(KeyCode.Space) == true) { startSimulation = true; } if (!startSimulation) { return; } if (fullStop) { return; //simulation ended } float t = Time.fixedDeltaTime; if (stopBouncing) { if (pureRolling) {//case 1: the ball is rolling on the floor without sliding float dumping = 1 - (5 - 4 / (1 + mass)) * (floorFriction / (4 * floorFriction + 6)) * (1 + 49 / (1 + 10 * Mathf.Abs(velocityPreviousFrame.Magnitude()))) * t; //arbitrary dumping factor. No real physical meaning. velocityCurrentFrame = velocityPreviousFrame.Scale(dumping); if (velocityCurrentFrame.Magnitude() < 0.01f) {//the velocity is low enough to be neglectable velocityCurrentFrame = MyVector3.Zero(); fullStop = true; } //calculate the avarage velocity between two consecutive frames and use it to calculate the new position MyVector3 avgVelocity = MyVector3.Lerp(velocityPreviousFrame, velocityCurrentFrame, 0.5f); MyVector3 displacement = avgVelocity.Scale(t); position = MyVector3.Add(position, displacement); MoveGameObject(); angularMomentumCurrentFrame = MyVector3.Cross(velocityCurrentFrame, new MyVector3(0, -1, 0)).Scale(momentOfInertia / radius); RotateGameObject(t); velocityPreviousFrame = velocityCurrentFrame; angularMomentumPreviousFrame = angularMomentumCurrentFrame; } else {//case 2: the ball is rolling on the floor with sliding velocityCurrentFrame = HorizontalVelocityAfterSliding(t); //calculate the avarage velocity between two consecutive frames and use it to calculate the new position MyVector3 avgVelocity = MyVector3.Lerp(velocityPreviousFrame, velocityCurrentFrame, 0.5f); MyVector3 displacement = avgVelocity.Scale(t); position = MyVector3.Add(position, displacement); MoveGameObject(); //angularMomentumCurrentFrame set in the X_VelocityAfterSliding() function RotateGameObject(t); velocityPreviousFrame = velocityCurrentFrame; angularMomentumPreviousFrame = angularMomentumCurrentFrame; } } else {//the ball is still bouncing MyVector3 deltaVel = gravity.Scale(t); velocityCurrentFrame = MyVector3.Add(velocityPreviousFrame, deltaVel); //calculate the avarage velocity between two consecutive frames and use it to calculate the new position MyVector3 avgVelocity = MyVector3.Lerp(velocityPreviousFrame, velocityCurrentFrame, 0.5f); MyVector3 displacement = avgVelocity.Scale(t); MyVector3 newPosition = MyVector3.Add(position, displacement); float distanceFromGround = newPosition.DistanceFromPlane(ground) - radius; if (distanceFromGround < 0) { //case 3: the ball is bouncing and has partially fallen balow the plane of the ground float impactVel_y = Y_ImpactVelocity(); float velocityCurrentFrame_y = impactVel_y * restitution; //upwards speed after bounce if (velocityCurrentFrame_y < tresholdStopBouncing) { //the speed after the bounce is small enough to be ignored stopBouncing = true; velocityCurrentFrame_y = 0; } MyVector3 horzVelocityCurrentFrame = HorizontalVelocityAfterSliding(t + 0.001f * impactVel_y + 8 * t * (1 - 1 / Mathf.Sqrt(1 + mass))); //position ball on top of the ground position = MyVector3.Add(newPosition, ground.Normal().Scale(-distanceFromGround)); MoveGameObject(); //angularMomentumCurrentFrame set in the X_VelocityAfterSliding() function RotateGameObject(t); angularMomentumPreviousFrame = angularMomentumCurrentFrame; velocityPreviousFrame = new MyVector3(horzVelocityCurrentFrame.getX(), velocityCurrentFrame_y, horzVelocityCurrentFrame.getZ()); } else {//case 4: the ball is bouncing and is in mid-air velocityPreviousFrame = velocityCurrentFrame; position = newPosition; MoveGameObject(); RotateGameObject(t); } } }
public static MyVector3 Cross(MyVector2 a, MyVector2 b) { return(MyVector3.Cross(a, b)); }
// Running the solver - all the joints are iterated through once every frame void Update() { // if the target hasn't been reached if (!done) { // if the Max number of tries hasn't been reached if (tries <= Mtries) { // starting from the second last joint (the last being the end effector) // going back up to the root for (int i = joints.Length - 2; i >= 0; i--) { // The vector from the ith joint to the end effector MyVector3 r1 = new MyVector3(joints[joints.Length - 1].position - joints[i].position); // The vector from the ith joint to the target MyVector3 r2 = tpos - new MyVector3(joints[i].position); // to avoid dividing by tiny numbers if (r1.magnitude * r2.magnitude <= 0.001f) { cos[i] = 1.0f; sin[i] = 0.0f; } else { // find the components using dot and cross product cos[i] = MyVector3.Dot(r1, r2) / (r1.magnitude * r2.magnitude); sin[i] = MyVector3.Cross(r1, r2).magnitude / (r1.magnitude * r2.magnitude); } // The axis of rotation MyVector3 axis = MyVector3.Cross(r1, r2); // find the angle between r1 and r2 (and clamp values if needed avoid errors) theta[i] = Mathf.Acos(cos[i]); //Optional. correct angles if needed, depending on angles invert angle if sin component is negative if (sin[i] < 0) { theta[i] *= -1; } // obtain an angle value between -pi and pi, and then convert to degrees theta[i] *= Mathf.Rad2Deg; // rotate the ith joint along the axis by theta degrees in the world space. MyQuaternion quat = MyQuaternion.AngleAxis(theta[i], ref axis); Quaternion fQuat = new Quaternion(quat.x, quat.y, quat.z, quat.w); joints[i].rotation = fQuat * joints[i].rotation; } // increment tries tries++; } } // find the difference in the positions of the end effector and the target float dif = (tpos - new MyVector3(joints[joints.Length - 1].position)).magnitude; // if target is within reach (within epsilon) then the process is done if (dif < epsilon) { done = true; } // if it isn't, then the process should be repeated else { done = false; } // the target has moved, reset tries to 0 and change tpos if (new MyVector3(targ.position) != tpos) { tries = 0; tpos = new MyVector3(targ.position); } }