public static SoftBody CreateRope(SoftBodyWorldInfo worldInfo, Vector3 from, Vector3 to, int resolution, int fixedTips) { // Create nodes int numLinks = resolution + 2; var positions = new Vector3[numLinks]; var masses = new double[numLinks]; for (int i = 0; i < numLinks; i++) { Vector3.Lerp(ref from, ref to, i / (double)(numLinks - 1), out positions[i]); masses[i] = 1; } var body = new SoftBody(worldInfo, numLinks, positions, masses); if ((fixedTips & 1) != 0) { body.SetMass(0, 0); } if ((fixedTips & 2) != 0) { body.SetMass(numLinks - 1, 0); } // Create links for (int i = 1; i < numLinks; i++) { body.AppendLink(i - 1, i); } return(body); }
public static SoftBody CreateRope(SoftBodyWorldInfo worldInfo, Vector3 from, Vector3 to, int res, int fixeds) { // Create nodes int r = res + 2; Vector3[] x = new Vector3[r]; float[] m = new float[r]; for (int i = 0; i < r; i++) { Vector3.Lerp(ref from, ref to, i / (float)(r - 1), out x[i]); m[i] = 1; } SoftBody psb = new SoftBody(worldInfo, r, x, m); if ((fixeds & 1) != 0) { psb.SetMass(0, 0); } if ((fixeds & 2) != 0) { psb.SetMass(r - 1, 0); } // Create links for (int i = 1; i < r; i++) { psb.AppendLink(i - 1, i); } return(psb); }
void InitSticks() { const int n = 16; const int sg = 4; const float sz = 5; const float hg = 4; const float inf = 1 / (float)(n - 1); for (int y = 0; y < n; ++y) { for (int x = 0; x < n; ++x) { Vector3 org = new Vector3(-sz + sz * 2 * x * inf, -10, -sz + sz * 2 * y * inf); SoftBody psb = SoftBodyHelpers.CreateRope(softBodyWorldInfo, org, org + new Vector3(hg * 0.001f, hg, 0), sg, 1); psb.Cfg.DP = 0.005f; psb.Cfg.Chr = 0.1f; for (int i = 0; i < 3; ++i) { psb.GenerateBendingConstraints(2 + i); } psb.SetMass(1, 0); psb.SetTotalMass(0.01f); SoftWorld.AddSoftBody(psb); } } CreateBigBall(new Vector3(0, 13, 0)); }
internal override bool _BuildCollisionObject() { if (meshSettings.numPointsInRope < 2) { Debug.LogError("There must be at least two points in the rope"); return(false); } if (SoftBodySettings.totalMass <= 0f) { Debug.LogError("The rope must have a positive mass"); return(false); } SoftBody m_BSoftBody = SoftBodyHelpers.CreateRope(World.WorldInfo, meshSettings.startPoint.ToBullet(), meshSettings.endPoint.ToBullet(), meshSettings.numPointsInRope, 0); m_collisionObject = m_BSoftBody; verts = new Vector3[m_BSoftBody.Nodes.Count]; norms = new Vector3[m_BSoftBody.Nodes.Count]; for (int i = 0; i < m_BSoftBody.Nodes.Count; i++) { verts[i] = m_BSoftBody.Nodes[i].Position.ToUnity(); norms[i] = m_BSoftBody.Nodes[i].Normal.ToUnity(); } //Set SB settings SoftBodySettings.ConfigureSoftBody(m_BSoftBody); foreach (RopeAnchor anchor in ropeAnchors) { //anchorNode point 0 to 1, rounds to node # int node = (int)Mathf.Floor(Mathf.Lerp(0, m_BSoftBody.Nodes.Count - 1, anchor.anchorNodePoint)); if (anchor.body != null) { m_BSoftBody.AppendAnchor(node, (BulletSharp.RigidBody)anchor.body.GetCollisionObject()); } else { m_BSoftBody.SetMass(node, 0); //setting node mass to 0 fixes it in space apparently } } //TODO: lr, Doesnt always work in editor LineRenderer lr = GetComponent <LineRenderer>(); lr.useWorldSpace = false; lr.SetVertexCount(verts.Length); lr.SetWidth(meshSettings.width, meshSettings.width); lr.SetColors(meshSettings.startColor, meshSettings.endColor); //Set SB position to GO position //m_BSoftBody.Rotate(transform.rotation.ToBullet()); //m_BSoftBody.Translate(transform.position.ToBullet()); //m_BSoftBody.Scale(transform.localScale.ToBullet()); UpdateMesh(); return(true); }
public static SoftBody CreatePatch(SoftBodyWorldInfo worldInfo, Vector3 corner00, Vector3 corner10, Vector3 corner01, Vector3 corner11, int resolutionX, int resolutionY, int fixedCorners, bool generateDiagonals) { // Create nodes if ((resolutionX < 2) || (resolutionY < 2)) { return(null); } int rx = resolutionX; int ry = resolutionY; int total = rx * ry; var positions = new Vector3[total]; var masses = new double[total]; for (int y = 0; y < ry; y++) { double ty = y / (double)(ry - 1); Vector3 py0, py1; Vector3.Lerp(ref corner00, ref corner01, ty, out py0); Vector3.Lerp(ref corner10, ref corner11, ty, out py1); for (int ix = 0; ix < rx; ix++) { double tx = ix / (double)(rx - 1); int index = rx * y + ix; Vector3.Lerp(ref py0, ref py1, tx, out positions[index]); masses[index] = 1; } } var body = new SoftBody(worldInfo, total, positions, masses); if ((fixedCorners & 1) != 0) { body.SetMass(0, 0); } if ((fixedCorners & 2) != 0) { body.SetMass(rx - 1, 0); } if ((fixedCorners & 4) != 0) { body.SetMass(rx * (ry - 1), 0); } if ((fixedCorners & 8) != 0) { body.SetMass(rx * (ry - 1) + rx - 1, 0); } // Create links and faces for (int y = 0; y < ry; ++y) { for (int x = 0; x < rx; ++x) { int ixy = rx * y + x; int ix1y = ixy + 1; int ixy1 = rx * (y + 1) + x; bool mdx = (x + 1) < rx; bool mdy = (y + 1) < ry; if (mdx) { body.AppendLink(ixy, ix1y); } if (mdy) { body.AppendLink(ixy, ixy1); } if (mdx && mdy) { int ix1y1 = ixy1 + 1; if (((x + y) & 1) != 0) { body.AppendFace(ixy, ix1y, ix1y1); body.AppendFace(ixy, ix1y1, ixy1); if (generateDiagonals) { body.AppendLink(ixy, ix1y1); } } else { body.AppendFace(ixy1, ixy, ix1y); body.AppendFace(ixy1, ix1y, ix1y1); if (generateDiagonals) { body.AppendLink(ix1y, ixy1); } } } } } return(body); }
public static SoftBody CreatePatch(SoftBodyWorldInfo worldInfo, Vector3 corner00, Vector3 corner10, Vector3 corner01, Vector3 corner11, int resx, int resy, int fixeds, bool gendiags) { // Create nodes if ((resx < 2) || (resy < 2)) { return(null); } int rx = resx; int ry = resy; int tot = rx * ry; Vector3[] x = new Vector3[tot]; float[] m = new float[tot]; for (int iy = 0; iy < ry; iy++) { float ty = iy / (float)(ry - 1); Vector3 py0, py1; Vector3.Lerp(ref corner00, ref corner01, ty, out py0); Vector3.Lerp(ref corner10, ref corner11, ty, out py1); for (int ix = 0; ix < rx; ix++) { float tx = ix / (float)(rx - 1); int index = rx * iy + ix; Vector3.Lerp(ref py0, ref py1, tx, out x[index]); m[index] = 1; } } SoftBody psb = new SoftBody(worldInfo, tot, x, m); if ((fixeds & 1) != 0) { psb.SetMass(0, 0); } if ((fixeds & 2) != 0) { psb.SetMass(rx - 1, 0); } if ((fixeds & 4) != 0) { psb.SetMass(rx * (ry - 1), 0); } if ((fixeds & 8) != 0) { psb.SetMass(rx * (ry - 1) + rx - 1, 0); } // Create links and faces for (int iy = 0; iy < ry; ++iy) { for (int ix = 0; ix < rx; ++ix) { int ixy = rx * iy + ix; int ix1y = ixy + 1; int ixy1 = rx * (iy + 1) + ix; bool mdx = (ix + 1) < rx; bool mdy = (iy + 1) < ry; if (mdx) { psb.AppendLink(ixy, ix1y); } if (mdy) { psb.AppendLink(ixy, ixy1); } if (mdx && mdy) { int ix1y1 = ixy1 + 1; if (((ix + iy) & 1) != 0) { psb.AppendFace(ixy, ix1y, ix1y1); psb.AppendFace(ixy, ix1y1, ixy1); if (gendiags) { psb.AppendLink(ixy, ix1y1); } } else { psb.AppendFace(ixy1, ixy, ix1y); psb.AppendFace(ixy1, ix1y, ix1y1); if (gendiags) { psb.AppendLink(ix1y, ixy1); } } } } } return(psb); }
// Create a sequence of flag objects and add them to the world. void CreateFlag(int width, int height, out AlignedSoftBodyArray flags) { flags = new AlignedSoftBodyArray(); // First create a triangle mesh to represent a flag // Allocate a simple mesh consisting of a vertex array and a triangle index array IndexedMesh mesh = new IndexedMesh(); mesh.NumVertices = width * height; mesh.NumTriangles = 2 * (width - 1) * (height - 1); Vector3Array vertexArray = new Vector3Array(mesh.NumVertices); mesh.Vertices = vertexArray; mesh.VertexStride = Vector3.SizeInBytes; IntArray triangleVertexIndexArray = new IntArray(3 * mesh.NumTriangles); mesh.TriangleIndices = triangleVertexIndexArray; mesh.TriangleIndexStride = sizeof(int) * 3; // Generate normalised object space vertex coordinates for a rectangular flag Matrix defaultScale = Matrix.Scaling(5, 20, 1); for (int y = 0; y < height; ++y) { float yCoordinate = y * 2.0f / (float)height - 1.0f; for (int x = 0; x < width; ++x) { float xCoordinate = x * 2.0f / (float)width - 1.0f; Vector3 vertex = new Vector3(xCoordinate, yCoordinate, 0.0f); vertexArray[y * width + x] = Vector3.TransformCoordinate(vertex, defaultScale); } } // Generate vertex indices for triangles for (int y = 0; y < (height - 1); ++y) { for (int x = 0; x < (width - 1); ++x) { // Triangle 0 // Top left of square on mesh { int vertex0 = y * width + x; int vertex1 = vertex0 + 1; int vertex2 = vertex0 + width; int triangleIndex = 2 * (y * (width - 1) + x); triangleVertexIndexArray[(mesh.TriangleIndexStride * triangleIndex) / sizeof(int)] = vertex0; triangleVertexIndexArray[(mesh.TriangleIndexStride * triangleIndex + 1) / sizeof(int) + 1] = vertex1; triangleVertexIndexArray[(mesh.TriangleIndexStride * triangleIndex + 2) / sizeof(int) + 2] = vertex2; } // Triangle 1 // Bottom right of square on mesh { int vertex0 = y * width + x + 1; int vertex1 = vertex0 + width; int vertex2 = vertex1 - 1; int triangleIndex = 2 * y * (width - 1) + 2 * x + 1; triangleVertexIndexArray[(mesh.TriangleIndexStride * triangleIndex) / sizeof(int)] = vertex0; triangleVertexIndexArray[(mesh.TriangleIndexStride * triangleIndex) / sizeof(int) + 1] = vertex1; triangleVertexIndexArray[(mesh.TriangleIndexStride * triangleIndex) / sizeof(int) + 2] = vertex2; } } } Matrix defaultRotateAndScale = Matrix.RotationX(0.5f); // Construct the sequence flags applying a slightly different translation to each one to arrange them // appropriately in the scene. for (int i = 0; i < numFlags; ++i) { float zTranslate = flagSpacing * (i - numFlags / 2); Vector3 defaultTranslate = new Vector3(0, 20, zTranslate); Matrix transform = defaultRotateAndScale * Matrix.Translation(defaultTranslate); SoftBody softBody = CreateFromIndexedMesh(vertexArray, triangleVertexIndexArray, true); for (int j = 0; j < mesh.NumVertices; ++j) { softBody.SetMass(j, 10.0f / mesh.NumVertices); } softBody.SetMass((height - 1) * width, 0); softBody.SetMass((height - 1) * width + width - 1, 0); softBody.SetMass((height - 1) * width + width / 2, 0); softBody.Cfg.Collisions = FCollisions.CLSS | FCollisions.CLRS; softBody.Cfg.LF = 0.0005f; softBody.Cfg.VCF = 0.001f; softBody.Cfg.DP = 0.0f; softBody.Cfg.DG = 0.0f; flags.Add(softBody); softBody.Transform(transform); SoftWorld.AddSoftBody(softBody); } //delete [] vertexArray; //delete [] triangleVertexIndexArray; }
private void OnSceneGUI() { if (!EditorApplication.isPlaying) { Handles.BeginGUI(); GUILayout.Label("Viewing nodes only supported while playing."); Handles.EndGUI(); return; } SoftBody softBody = bSoftBodyTarget.GetCollisionObject() as SoftBody; if (softBody == null) { Handles.BeginGUI(); GUILayout.Label("Seems like the CollisionObject has not been generated."); Handles.EndGUI(); return; } bool clickedNode = false; AlignedNodeArray nodes = softBody.Nodes; float highestMass = 0; for (int i = 0; i < nodes.Count; i++) { float invMass = nodes[i].InverseMass; if (invMass > 0 && 1 / invMass > highestMass) { highestMass = 1 / invMass; } } for (int i = 0; i < nodes.Count; i++) { float mass = softBody.GetMass(i); if (_currentSelectedNode == i) { Handles.BeginGUI(); EditorGUI.BeginChangeCheck(); EditorGUILayout.LabelField(string.Format("id: {0}", i)); mass = EditorGUILayout.Slider("Mass", mass, 0, Mathf.Clamp(mass * 10, 1, 100), GUILayout.Width(500)); if (EditorGUI.EndChangeCheck()) { softBody.SetMass(i, mass); nodes[i].Velocity = BulletSharp.Math.Vector3.Zero; nodes[i].Force = BulletSharp.Math.Vector3.Zero; } Handles.EndGUI(); Handles.color = Color.green; } else { Color usedColor; if (mass > 0) { usedColor = Color.Lerp(Color.white, Color.gray, mass / highestMass); } else { usedColor = Color.blue; } Handles.color = usedColor; } Vector3 position = nodes[i].Position.ToUnity(); float size = HandleUtility.GetHandleSize(position) * 0.5f; if (Handles.Button(position, Quaternion.identity, size, size, Handles.SphereHandleCap)) { clickedNode = true; _currentSelectedNode = i; } } if (!clickedNode && Input.GetMouseButton(0)) { _currentSelectedNode = -1; } }