std::map<std::string, ResModelLoader::ObjTankObject> ResModelLoader::m_LoadObjTankObjects( const std::vector<std::string>::iterator first, const std::vector<std::string>::iterator last) { std::map<std::string, ObjTankObject> result; VertexesBag v_bag; FacesBag f_bag; std::string previous_name; FLOATING x, y, z, s, t; unsigned v0, t0, n0, v1, t1, n1, v2, t2, n2; auto lineIt = first; while (lineIt != last) { std::string current_name; if (IsObject(*lineIt, current_name)) { if (!previous_name.empty()) { result[previous_name] = m_BuildObjTankObject(v_bag, f_bag); f_bag.Clear(); } previous_name = current_name; } else if (IsVertex(*lineIt, x, y, z)) { v_bag.vertexes.emplace_back(x, y, z); } else if (IsNormal(*lineIt, x, y, z)) { v_bag.normals.emplace_back(x, y, z); } else if (IsTexCoord(*lineIt, s, t)) { v_bag.tex_coords.emplace_back(s, t); } else if (IsFace3(*lineIt, v0, t0, n0, v1, t1, n1, v2, t2, n2)) { f_bag.faces3.emplace_back(v0, t0, n0); f_bag.faces3.emplace_back(v1, t1, n1); f_bag.faces3.emplace_back(v2, t2, n2); } else if (IsFace2(*lineIt, v0, n0, v1, n1, v2, n2)) { f_bag.faces2.emplace_back(v0, n0); f_bag.faces2.emplace_back(v1, n1); f_bag.faces2.emplace_back(v2, n2); } else if (IsSmoothing(*lineIt) || IsComment(*lineIt)) { // NULL; } ++lineIt; } // Write last object. result[previous_name] = m_BuildObjTankObject(v_bag, f_bag); return result; }
//---------------------------------------------------------------------------- void BouncingTetrahedra::Reposition (int t0, int t1, Contact& contact) { RigidTetra& tetra0 = *mTetras[t0]; RigidTetra& tetra1 = *mTetras[t1]; // Compute the centroids of the tetrahedra. Vector3f vertices0[4], vertices1[4]; tetra0.GetVertices(vertices0); tetra1.GetVertices(vertices1); Vector3f centroid0 = Vector3f::ZERO; Vector3f centroid1 = Vector3f::ZERO; int i; for (i = 0; i < 4; ++i) { centroid0 += vertices0[i]; centroid1 += vertices1[i]; } centroid0 *= 0.25f; centroid1 *= 0.25f; // Randomly perturb the tetrahedra vertices by a small amount. This is // done to help prevent the LCP solver from getting into cycles and // degenerate cases. const float reduction = 0.95f; float reduceI = reduction*Mathf::IntervalRandom(0.9999f, 1.0001f); float reduceJ = reduction*Mathf::IntervalRandom(0.9999f, 1.0001f); for (i = 0; i < 4; ++i) { vertices0[i] = centroid0 + (vertices0[i] - centroid0)*reduceI; vertices1[i] = centroid1 + (vertices1[i] - centroid1)*reduceJ; } // Compute the distance between the tetrahedra. float dist = 1.0f; int statusCode = 0; Vector3f closest[2]; LCPPolyDist3(4, vertices0, 4, mFaces, 4, vertices1, 4, mFaces, statusCode, dist, closest); ++mLCPCount; // In theory, LCPPolyDist<3> should always find a valid distance, but just // in case numerical round-off errors cause problems, let us trap it. assertion(dist >= 0.0f, "LCP polyhedron distance calculator failed.\n"); // Reposition the tetrahedra to the theoretical points of contact. closest[0] = centroid0 + (closest[0] - centroid0)/reduceI; closest[1] = centroid1 + (closest[1] - centroid1)/reduceJ; for (i = 0; i < 4; ++i) { vertices0[i] = centroid0 + (vertices0[i] - centroid0)/reduceI; vertices1[i] = centroid1 + (vertices1[i] - centroid1)/reduceJ; } // Numerical round-off errors can cause interpenetration. Move the // tetrahedra to back out of this situation. The length of diff // estimates the depth of penetration when dist > 0 was reported. Vector3f diff = closest[0] - closest[1]; // Apply the separation distance along the line containing the centroids // of the tetrahedra. Vector3f diff2 = centroid1 - centroid0; diff = diff2/diff2.Length()*diff.Length(); // Move each tetrahedron by half of kDiff when the distance was large, // but move each by twice kDiff when the distance is really small. float mult = (dist >= mTolerance ? 0.5f : 1.0f); Vector3f delta = mult*diff; // Undo the interpenetration. if (tetra0.Moved && !tetra1.Moved) { // Tetra t0 has moved but tetra t1 has not moved. tetra1.SetPosition(tetra1.GetPosition() + 2.0f*delta); tetra1.Moved = true; } else if (!tetra0.Moved && tetra1.Moved) { // Tetra t1 has moved but tetra t0 has not moved. tetra0.SetPosition(tetra0.GetPosition() - 2.0f*delta); tetra0.Moved = true; } else { // Both tetras moved or both tetras did not move. tetra0.SetPosition(tetra0.GetPosition() - delta); tetra0.Moved = true; tetra1.SetPosition(tetra1.GetPosition() + delta); tetra1.Moved = true; } // Test whether the two tetrahedra intersect in a vertex-face // configuration. contact.IsVFContact = IsVertex(vertices0, closest[0]); if (contact.IsVFContact) { contact.A = mTetras[t1]; contact.B = mTetras[t0]; CalculateNormal(vertices1, closest[1], contact); } else { contact.IsVFContact = IsVertex(vertices1, closest[1]); if (contact.IsVFContact) { contact.A = mTetras[t0]; contact.B = mTetras[t1]; CalculateNormal(vertices0, closest[0], contact); } } // Test whether the two tetrahedra intersect in an edge-edge // configuration. if (!contact.IsVFContact) { contact.A = mTetras[t0]; contact.B = mTetras[t1]; Vector3f otherVertexA = Vector3f::UNIT_X; Vector3f otherVertexB = Vector3f::ZERO; contact.EA = ClosestEdge(vertices0, closest[0], otherVertexA); contact.EB = ClosestEdge(vertices1, closest[1], otherVertexB); Vector3f normal = contact.EA.UnitCross(contact.EB); if (normal.Dot(otherVertexA - closest[0]) < 0.0f) { contact.N = normal; } else { contact.N = -normal; } } // Reposition results to correspond to relocaton of tetra. contact.PA = closest[0] - delta; contact.PB = closest[1] + delta; }