public static bool Connected(GroupedFaceUV a, GroupedFaceUV b) { float dot = Vector3.Dot(a.Normal, b.Normal); if (dot < DOT_THRESHOLD) // non-coplanar faces return false; int commonEdgeCnt = 0; for (int i = 0; i < 3; ++i) { VtxHash ae0 = a.vtxHash[e0LUT[i]]; VtxHash ae1 = a.vtxHash[e1LUT[i]]; for (int j = 0; j < 3; ++j) { VtxHash be0 = b.vtxHash[e0LUT[j]]; VtxHash be1 = b.vtxHash[e1LUT[j]]; if( (ae0.Equals(be0) && ae1.Equals(be1)) || (ae0.Equals(be1) && ae1.Equals(be0))) ++commonEdgeCnt; } } return commonEdgeCnt > 0; }
public override List<Mesh> Unwrap(Mesh mesh, int packSize, float worldScale) { List<GroupedFaceUV> faceuvs = new List<GroupedFaceUV>(); BeginEvent(); int fcnt = mesh.FaceCount; for (int i = 0; i < fcnt; ++i) { Vector3 p0, p1, p2, e1, e2; // computer the face normal mesh.Positions.GetFace(out p0, out p1, out p2, i); e1 = p1 - p0; e1.Normalize(); e2 = p2 - p0; e2.Normalize(); Vector3 n = Vector3.Cross(e1, e2); n.Normalize(); // get major axis & assign texcoord TC tc = GetMajorAxis(ref n); GroupedFaceUV fuv = new GroupedFaceUV(); fuv.Texcrd[0] = tc(p0, worldScale); fuv.Texcrd[1] = tc(p1, worldScale); fuv.Texcrd[2] = tc(p2, worldScale); fuv.Normal = n; fuv.ComputeVtxHash(p0, p1, p2, Precision); faceuvs.Add(fuv); } EndEvent("Generate faceuvs"); // group the faces BeginEvent(); int gCnt = CreateGroups(faceuvs); Console.WriteLine("{0} faces created {1} groups", fcnt, gCnt); List<Group> groups = new List<Group>(); EndEvent("Group faceuvs"); // packing BeginEvent(); PackSettings packSettings = new PackSettings(); List<PackOutputList> packOutputs = new List<PackOutputList>(); List<PackInput> packInputs = new List<PackInput>(); for (int i = 0; i < gCnt; ++i) { Group gp = new Group(); gp.Count = GroupedFaceUV.Bounding(out gp.Min, out gp.Max, faceuvs, i); groups.Add(gp); PackInput pi = new PackInput(); pi.Size.Width = (int)Math.Ceiling(gp.Max.X - gp.Min.X); pi.Size.Height = (int)Math.Ceiling(gp.Max.Y - gp.Min.Y); packInputs.Add(pi); if (debug) { Console.Write("gp{0}: ", i); GroupedFaceUV.Dump(faceuvs, i); } } EndEvent("Prepare pack inputs"); BeginEvent(); bool ok = false; do { packSettings.Size.Width = packSize; packSettings.Size.Height = packSize; packSettings.Border = Border; packOutputs.Clear(); JimScottPacker packer = new JimScottPacker(); packer.debug = debug; packer.Pack(packSettings, packInputs, packOutputs); if (SingleMeshOutput) { ok = packOutputs.Count == 1; if (!ok) packSize = packSize * 2; } } while (SingleMeshOutput && !ok); EndEvent("Packing"); BeginEvent(); Vector2 scale = new Vector2(1.0f / packSize, 1.0f / packSize); // convert pack outputs back to faceuv foreach (PackOutputList polist in packOutputs) { foreach (PackOutput po in polist) { Group gp = groups[po.Input]; foreach (GroupedFaceUV fuv in faceuvs) { if (fuv.GroupId != po.Input) continue; fuv.Translate(new Vector2(po.X, po.Y) - gp.Min); fuv.Scale(scale); } } } // create output meshes List<Mesh> output = new List<Mesh>(); foreach (PackOutputList polist in packOutputs) { Mesh omesh = new Mesh(); int ofcnt = 0; for (int i = 0; i < polist.Count; ++i) ofcnt += groups[polist[i].Input].Count; omesh.Init(ofcnt * 3); int dst = 0; for (int i = 0; i < polist.Count; ++i) { for (int src = 0; src < fcnt; ++src) { GroupedFaceUV fuv = faceuvs[src]; if (fuv.GroupId != polist[i].Input) continue; mesh.Positions.CopyFaceTo(omesh.Positions, src, dst); mesh.Normals.CopyFaceTo(omesh.Normals, src, dst); mesh.Texcrds0.CopyFaceTo(omesh.Texcrds0, src, dst); omesh.Texcrds1.SetFace(dst, fuv.Texcrd[0], fuv.Texcrd[1], fuv.Texcrd[2]); if(debug) omesh.FaceProps[dst] = src; else omesh.FaceProps[dst] = mesh.FaceProps[src]; ++dst; } } output.Add(omesh); } OutputSize = packSize; EndEvent("Prepare pack outputs"); return output; }