Beispiel #1
0
void EditorMesh::BuildLightmapUVs(float maxAngle, float adjVal, int seperationUnits)
{
    Vect maxSize = bounds.Max-bounds.Min;

    //adjVal *= MAX(maxSize.x, MAX(maxSize.y, maxSize.z));
    adjVal *= bounds.GetDiamater();

    int i, j;

    MakePolyEdges();

    maxAngle = cosf(RAD(maxAngle));

    BitList ProcessedPolys, ProcessedEdges, ProcessedVerts;
    List<UINT> UnprocessedPolys;

    ProcessedPolys.SetSize(PolyList.Num());
    ProcessedEdges.SetSize(PolyEdgeList.Num());
    ProcessedVerts.SetSize(VertList.Num());

    UnprocessedPolys.SetSize(PolyList.Num());
    for(i=0; i<UnprocessedPolys.Num(); i++)
        UnprocessedPolys[i] = i;

    List<UVSection> Sections;
    BitList         SplitVerts;

    SplitVerts.SetSize(VertList.Num());

    //go through each polygon and find neighboring polygons
    while(UnprocessedPolys.Num())
    {
        UINT curPoly = UnprocessedPolys[0];

        List<UINT> SectionPolys;
        UVSection &section = *Sections.CreateNew();
        section.mapDir = GetPolyDir(curPoly);

        List<Vect> PolyLines;

        // calling this recursively will build us up a section based upon this poly
        AddLMPolyInfo info(curPoly, maxAngle, section.mapDir, SectionPolys, PolyLines, UnprocessedPolys, ProcessedPolys, ProcessedEdges);
        AddLightmapUVPoly(info);

        section.mapDir.Norm();

        //find best mapping direction
        Vect XDir, YDir;

        BitList addedLines;
        addedLines.SetSize(PolyLines.Num());

        float bestLength = 0.0f;
        Vect bestDir;

        for(i=0; i<PolyLines.Num(); i++)
        {
            if(addedLines[i]) continue;

            addedLines.Set(i);

            Vect &line1 = PolyLines[i];
            Vect line1Norm = (line1 + (section.mapDir * -section.mapDir.Dot(line1))).Norm();

            Vect lineTotal = line1;

            for(j=i+1; j<PolyLines.Num(); j++)
            {
                if(addedLines[j]) continue;

                Vect &line2 = PolyLines[j];
                Vect line2Norm = (line2 + (section.mapDir * -section.mapDir.Dot(line2))).Norm();

                if(line1Norm.Dot(line2Norm) > 0.9f) //about 10 degrees
                {
                    lineTotal += line2;
                    addedLines.Set(j);
                }
            }

            float length = lineTotal.Len();
            if(length > bestLength)
            {
                bestDir = lineTotal.Norm();
                bestLength = length;
            }
        }

        if(section.mapDir.CloseTo(bestDir) || (-section.mapDir).CloseTo(bestDir))
        {
            if(bestDir.x > bestDir.y)
            {
                if(bestDir.x > bestDir.z)
                    *(DWORD*)&bestDir.x |= 0x80000000;
                else
                    *(DWORD*)&bestDir.z |= 0x80000000;
            }
            else
            {
                if(bestDir.y > bestDir.z)
                    *(DWORD*)&bestDir.y |= 0x80000000;
                else
                    *(DWORD*)&bestDir.z |= 0x80000000;
            }
        }

        YDir = bestDir.Cross(section.mapDir).Norm();
        XDir = YDir.Cross(section.mapDir).Norm();

        /*if(section.mapDir.GetAbs().CloseTo(Vect(0.0f, 1.0f, 0.0f)))
        {
            float fOne = (*(DWORD*)&section.mapDir.y & 0x80000000) ? -1.0f : 1.0f;

            XDir.Set(fOne, 0.0f, 0.0f);
            YDir.Set(0.0f, 0.0f, fOne);
        }
        else
        {
            XDir = Vect(0.0f, 1.0f, 0.0f).Cross(section.mapDir).Norm();
            YDir = XDir.Cross(section.mapDir).Norm();
        }*/

        float top, bottom, left, right;

        //project UVs onto this section
        for(i=0; i<SectionPolys.Num(); i++)
        {
            PolyFace &poly = PolyList[SectionPolys[i]];
            for(j=0; j<poly.Faces.Num(); j++)
            {
                UINT faceID = poly.Faces[j];
                Face &f = FaceList[faceID];

                section.Faces << faceID;

                for(int k=0; k<3; k++)
                {
                    UINT vert = f.ptr[k];

                    Vect &v = VertList[vert];

                    Vect2 uv;
                    uv.x = XDir.Dot(v);
                    uv.y = YDir.Dot(v);

                    if(!section.ProjectedVerts.Num())
                    {
                        left = right = uv.x;
                        top = bottom = uv.y;
                    }
                    else
                    {
                        if(uv.x < left) left = uv.x;
                        else if(uv.x > right) right = uv.x;

                        if(uv.y < top) top = uv.y;
                        else if(uv.y > bottom) bottom = uv.y;
                    }

                    section.Verts << vert;
                    section.ProjectedVerts << uv;
                }
            }
        }

        section.width  = (right-left)+(adjVal*2.0f);
        section.height = (bottom-top)+(adjVal*2.0f);

        for(i=0; i<section.Verts.Num(); i++)
        {
            section.ProjectedVerts[i].x -= left-adjVal;
            section.ProjectedVerts[i].y -= top-adjVal;
        }

        //find any verts that might need splitting
        section.SplitVerts.SetSize(section.Verts.Num());

        for(i=0; i<section.Verts.Num(); i++)
        {
            BOOL bFoundVert = FALSE;
            UINT vert = section.Verts[i];

            if(SplitVerts[vert])
                bFoundVert = TRUE;
            else 
            {
                for(j=0; j<Sections.Num()-1; j++)
                {
                    UVSection &prevSection = Sections[j];

                    if(prevSection.Verts.HasValue(vert))
                    {
                        SplitVerts.Set(vert);
                        bFoundVert = TRUE;
                        break;
                    }
                }
            }

            if(bFoundVert)
                section.SplitVerts.Set(i);
        }
    }

    //split verts where the lightmap coordinates are
    for(i=1; i<Sections.Num(); i++)
    {
        UVSection &section = Sections[i];
        for(j=0; j<section.SplitVerts.Num(); j++)
        {
            if(section.SplitVerts[j])
            {
                UINT faceID  = j/3;
                UINT faceVert = j%3;
                UINT vertID = section.Verts[j];

                UINT newVertID = VertList.Num();
                Face &f = FaceList[faceID];

                f.ptr[faceVert] = newVertID;

                VertList.Add(VertList[vertID]);
                UVList.Add(UVList[vertID]);
                NormalList.Add(NormalList[vertID]);
                if(TangentList.Num())
                    TangentList.Add(TangentList[vertID]);
            }
        }
    }

    LMUVList.SetSize(VertList.Num());

    //find the most optimal way to put sections together
    BestStorageInfo info(Sections, seperationUnits);
    FindBestUVStorage(info);

    float curSizeI = 1.0f/MAX(info.curSize.x, info.curSize.y);

    for(i=0; i<info.CurStorage.Num(); i++)
    {
        StorageData &data = info.CurStorage[i];
        UVSection &section = Sections[data.item];
        for(j=0; j<section.Verts.Num(); j++)
        {
            UINT vertID = section.Verts[j];
            if(ProcessedVerts[vertID]) continue;

            Vect2 &v = section.ProjectedVerts[j];
            Vect2 newPos;

            if(data.bRot)
            {
                newPos.x = section.height-v.y;
                newPos.y = v.x;
            }
            else
                newPos = v;

            LMUVList[vertID] = (data.pos+newPos)*curSizeI;

            ProcessedVerts.Set(vertID);
        }
    }

    //free data
    for(i=0; i<Sections.Num(); i++)
        Sections[i].FreeData();
    Sections.Clear();

    FreePolyEdges();
}