private Cb4aCollisionMeshSoupFace BuildCollisionFaceSoupFace(BspCollisionFaceSoupFace f, Cb4aCollisionMeshSoup soup) { var r = new Cb4aCollisionMeshSoupFace(); Vector3 n = Vector3.UnitZ; float maxLength = float.MinValue; for (int i=0; i<f.Vertices.Count-1;++i) { Vector3 edge0 = f.Vertices[i] - f.Vertices[(i + 1) % f.Vertices.Count]; Vector3 nn = Vector3.Cross(f.Vertices[(i + 1) % f.Vertices.Count] - f.Vertices[(i + 2) % f.Vertices.Count], edge0); float l = nn.LengthSquared; if (l> maxLength) { maxLength = l; n = nn; } } if (maxLength < 1) { maxLength = maxLength; //throw new ApplicationException("face is almost zero area!"); } n.Normalize(); r.startPlane = soup.Planes.Count; soup.Planes.Add(new CIwPlane() { k = (int)(Vector3.Dot(f.Vertices[0], n)) * AirplaySDKMath.IW_GEOM_ONE, v = GetVec3Fixed(n) }); int lastD = int.MinValue; CIwVec3 lastN = CIwVec3.g_Zero; for (int i = 0; i < f.Vertices.Count; ++i) { var d = Vector3.Cross(n,f.Vertices[i] - f.Vertices[(i + 1) % f.Vertices.Count]); d.Normalize(); CIwVec3 newN = GetVec3Fixed(d); CIwVec3 v3 = GetVec3(f.Vertices[i]); int newD = newN.x * v3.x + newN.y * v3.y + newN.z * v3.z;//(int)(Vector3.Dot(d, f.Vertices[i]) * AirplaySDKMath.IW_GEOM_ONE); if (newN != lastN || newD != lastD) { lastD=newD; lastN = newN; //test //for (int j = 0; j < f.Vertices.Count; ++j) //{ // if ((newN.x * f.Vertices[j].X + newN.y * f.Vertices[j].Y + newN.z * f.Vertices[j].Z) - lastD < -64) // { // //TODO: Split such faces into individual triangles. Think how to handle it in graphics // //throw new ApplicationException("wrong edge normal " + newN); // } //} soup.Planes.Add(new CIwPlane() { k = newD, v = newN }); //r.edges.Add(new Cb4aCollisionMeshSoupFaceEdge(){Normal=newN, Distance=newD}); } } r.numPlanes = soup.Planes.Count - r.startPlane-1; return r; }
private Ib4aCollider BuildCollisionFaceSoup(BspCollisionFaceSoup bspCollisionFaceSoup) { var soup = new Cb4aCollisionMeshSoup(); foreach (var f in bspCollisionFaceSoup.Faces) { soup.Faces.Add(BuildCollisionFaceSoupFace(f, soup)); } return soup; }