Exemplo n.º 1
0
 public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource = true)
 {
     //Profile.Start//Profile("SA2MultiMeshCombiner.AddDeleteGameObjects1");
     //PART 1 ==== Validate
     if (!_validate(gos, deleteGOinstanceIDs))
     {
         return(false);
     }
     _distributeAmongBakers(gos, deleteGOinstanceIDs);
     if (LOG_LEVEL >= SA2LogLevel.debug)
     {
         SA2Log.LogDebug("SA2MultiMeshCombiner.AddDeleteGameObjects numCombinedMeshes: " + meshCombiners.Count + " added:" + gos + " deleted:" + deleteGOinstanceIDs + " disableRendererInSource:" + disableRendererInSource + " maxVertsPerCombined:" + _maxVertsInMesh);
     }
     return(_bakeStep1(gos, deleteGOinstanceIDs, disableRendererInSource));
 }
Exemplo n.º 2
0
 bool _bakeStep1(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource)
 {
     //Profile.End//Profile("SA2MultiMeshCombiner.AddDeleteGameObjects2.2");
     //Profile.Start//Profile("SA2MultiMeshCombiner.AddDeleteGameObjects3");
     //PART 3 ==== Add delete meshes from combined
     for (int i = 0; i < meshCombiners.Count; i++)
     {
         CombinedMesh cm = meshCombiners[i];
         if (cm.combinedMesh.targetRenderer == null)
         {
             cm.combinedMesh.resultSceneObject = _resultSceneObject;
             cm.combinedMesh.BuildSceneMeshObject(true);
             if (_LOG_LEVEL >= SA2LogLevel.debug)
             {
                 SA2Log.LogDebug("BuildSO combiner {0} goID {1} targetRenID {2} meshID {3}", i, cm.combinedMesh.targetRenderer.gameObject.GetInstanceID(), cm.combinedMesh.targetRenderer.GetInstanceID(), cm.combinedMesh.GetMesh().GetInstanceID());
             }
         }
         else
         {
             if (cm.combinedMesh.targetRenderer.transform.parent != resultSceneObject.transform)
             {
                 Debug.LogError("targetRender objects must be children of resultSceneObject");
                 return(false);
             }
         }
         if (cm.gosToAdd.Count > 0 || cm.gosToDelete.Count > 0)
         {
             cm.combinedMesh.AddDeleteGameObjectsByID(cm.gosToAdd.ToArray(), cm.gosToDelete.ToArray(), disableRendererInSource);
             if (_LOG_LEVEL >= SA2LogLevel.debug)
             {
                 SA2Log.LogDebug("Baked combiner {0} obsAdded {1} objsRemoved {2} goID {3} targetRenID {4} meshID {5}", i, cm.gosToAdd.Count, cm.gosToDelete.Count, cm.combinedMesh.targetRenderer.gameObject.GetInstanceID(), cm.combinedMesh.targetRenderer.GetInstanceID(), cm.combinedMesh.GetMesh().GetInstanceID());
             }
         }
         Renderer r = cm.combinedMesh.targetRenderer;
         Mesh     m = cm.combinedMesh.GetMesh();
         if (r is MeshRenderer)
         {
             MeshFilter mf = r.gameObject.GetComponent <MeshFilter>();
             mf.sharedMesh = m;
         }
         else
         {
             SkinnedMeshRenderer smr = (SkinnedMeshRenderer)r;
             smr.sharedMesh = m;
         }
     }
     for (int i = 0; i < meshCombiners.Count; i++)
     {
         CombinedMesh cm = meshCombiners[i];
         for (int j = 0; j < cm.gosToDelete.Count; j++)
         {
             obj2MeshCombinerMap.Remove(cm.gosToDelete[j]);
         }
     }
     for (int i = 0; i < meshCombiners.Count; i++)
     {
         CombinedMesh cm = meshCombiners[i];
         for (int j = 0; j < cm.gosToAdd.Count; j++)
         {
             obj2MeshCombinerMap.Add(cm.gosToAdd[j].GetInstanceID(), cm);
         }
         if (cm.gosToAdd.Count > 0 || cm.gosToDelete.Count > 0)
         {
             cm.gosToDelete.Clear();
             cm.gosToAdd.Clear();
             cm.numVertsInListToDelete = 0;
             cm.numVertsInListToAdd    = 0;
             cm.isDirty = true;
         }
     }
     //Profile.End//Profile("SA2MultiMeshCombiner.AddDeleteGameObjects3");
     if (LOG_LEVEL >= SA2LogLevel.debug)
     {
         string s = "Meshes in combined:";
         for (int i = 0; i < meshCombiners.Count; i++)
         {
             s += " mesh" + i + "(" + meshCombiners[i].combinedMesh.GetObjectsInCombined().Count + ")\n";
         }
         s += "children in result: " + resultSceneObject.transform.childCount;
         SA2Log.LogDebug(s, LOG_LEVEL);
     }
     if (meshCombiners.Count > 0)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
Exemplo n.º 3
0
    void _distributeAmongBakers(GameObject[] gos, int[] deleteGOinstanceIDs)
    {
        if (gos == null)
        {
            gos = empty;
        }
        if (deleteGOinstanceIDs == null)
        {
            deleteGOinstanceIDs = emptyIDs;
        }

        if (resultSceneObject == null)
        {
            resultSceneObject = new GameObject("SAMMesh-" + name);
        }

        //PART 2 ==== calculate which bakers to add objects to
        for (int i = 0; i < meshCombiners.Count; i++)
        {
            meshCombiners[i].extraSpace = _maxVertsInMesh - meshCombiners[i].combinedMesh.GetMesh().vertexCount;
        }
        //Profile.End//Profile("SA2MultiMeshCombiner.AddDeleteGameObjects1");

        //Profile.Start//Profile("SA2MultiMeshCombiner.AddDeleteGameObjects2.1");
        //first delete game objects from the existing combinedMeshes keep track of free space
        for (int i = 0; i < deleteGOinstanceIDs.Length; i++)
        {
            CombinedMesh c = null;
            if (obj2MeshCombinerMap.TryGetValue(deleteGOinstanceIDs[i], out c))
            {
                if (LOG_LEVEL >= SA2LogLevel.debug)
                {
                    SA2Log.LogDebug("SA2MultiMeshCombiner.Removing " + deleteGOinstanceIDs[i] + " from meshCombiner " + meshCombiners.IndexOf(c));
                }
                c.numVertsInListToDelete += c.combinedMesh.GetNumVerticesFor(deleteGOinstanceIDs[i]);  //m.vertexCount;
                c.gosToDelete.Add(deleteGOinstanceIDs[i]);
            }
            else
            {
                Debug.LogWarning("Object " + deleteGOinstanceIDs[i] + " in the list of objects to delete is not in the combined mesh.");
            }
        }
        for (int i = 0; i < gos.Length; i++)
        {
            GameObject   go       = gos[i];
            int          numVerts = SAUtility.GetMesh(go).vertexCount;
            CombinedMesh cm       = null;
            for (int j = 0; j < meshCombiners.Count; j++)
            {
                if (meshCombiners[j].extraSpace + meshCombiners[j].numVertsInListToDelete - meshCombiners[j].numVertsInListToAdd > numVerts)
                {
                    cm = meshCombiners[j];
                    if (LOG_LEVEL >= SA2LogLevel.debug)
                    {
                        SA2Log.LogDebug("SA2MultiMeshCombiner.Added " + gos[i] + " to combinedMesh " + j, LOG_LEVEL);
                    }
                    break;
                }
            }
            if (cm == null)
            {
                cm = new CombinedMesh(maxVertsInMesh, _resultSceneObject, _LOG_LEVEL);
                _setMBValues(cm.combinedMesh);
                meshCombiners.Add(cm);
                if (LOG_LEVEL >= SA2LogLevel.debug)
                {
                    SA2Log.LogDebug("SA2MultiMeshCombiner.Created new combinedMesh");
                }
            }
            cm.gosToAdd.Add(go);
            cm.numVertsInListToAdd += numVerts;
            //			obj2MeshCombinerMap.Add(go,cm);
        }
    }
Exemplo n.º 4
0
    Rect[] _GetRects(List <Vector2> imgWidthHeights, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, out int outW, out int outH, int recursionDepth)
    {
        if (LOG_LEVEL >= SA2LogLevel.debug)
        {
            Debug.Log(String.Format("_GetRects numImages={0}, maxDimension={1}, padding={2}, minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}, recursionDepth={7}",
                                    imgWidthHeights.Count, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
        }
        if (recursionDepth > 10)
        {
            Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
            outW = 0;
            outH = 0;
            return(new Rect[0]);
        }
        float area = 0;
        int   maxW = 0;
        int   maxH = 0;

        Image[] imgsToAdd = new Image[imgWidthHeights.Count];
        for (int i = 0; i < imgsToAdd.Length; i++)
        {
            Image im = imgsToAdd[i] = new Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding, minImageSizeX, minImageSizeY);
            area += im.w * im.h;
            maxW  = Mathf.Max(maxW, im.w);
            maxH  = Mathf.Max(maxH, im.h);
        }

        if ((float)maxH / (float)maxW > 2)
        {
            if (LOG_LEVEL >= SA2LogLevel.debug)
            {
                SA2Log.LogDebug("Using height Comparer");
            }
            Array.Sort(imgsToAdd, new ImageHeightComparer());
        }
        else if ((float)maxH / (float)maxW < .5)
        {
            if (LOG_LEVEL >= SA2LogLevel.debug)
            {
                SA2Log.LogDebug("Using width Comparer");
            }
            Array.Sort(imgsToAdd, new ImageWidthComparer());
        }
        else
        {
            if (LOG_LEVEL >= SA2LogLevel.debug)
            {
                SA2Log.LogDebug("Using area Comparer");
            }
            Array.Sort(imgsToAdd, new ImageAreaComparer());
        }

        //explore the space to find a resonably efficient packing
        int sqrtArea = (int)Mathf.Sqrt(area);
        int idealAtlasW;
        int idealAtlasH;

        if (doPowerOfTwoTextures)
        {
            idealAtlasW = idealAtlasH = RoundToNearestPositivePowerOfTwo(sqrtArea);
            if (maxW > idealAtlasW)
            {
                idealAtlasW = CeilToNearestPowerOfTwo(idealAtlasW);
            }
            if (maxH > idealAtlasH)
            {
                idealAtlasH = CeilToNearestPowerOfTwo(idealAtlasH);
            }
        }
        else
        {
            idealAtlasW = sqrtArea;
            idealAtlasH = sqrtArea;
            if (maxW > sqrtArea)
            {
                idealAtlasW = maxW;
                idealAtlasH = Mathf.Max(Mathf.CeilToInt(area / maxW), maxH);
            }
            if (maxH > sqrtArea)
            {
                idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / maxH), maxW);
                idealAtlasH = maxH;
            }
        }
        if (idealAtlasW == 0)
        {
            idealAtlasW = 1;
        }
        if (idealAtlasH == 0)
        {
            idealAtlasH = 1;
        }
        int stepW = (int)(idealAtlasW * .15f);
        int stepH = (int)(idealAtlasH * .15f);

        if (stepW == 0)
        {
            stepW = 1;
        }
        if (stepH == 0)
        {
            stepH = 1;
        }
        int numWIterations = 2;
        int steppedWidth   = idealAtlasW;
        int steppedHeight  = idealAtlasH;

        while (numWIterations >= 1 && steppedHeight < sqrtArea * 1000)
        {
            bool successW = false;
            numWIterations = 0;
            steppedWidth   = idealAtlasW;
            while (!successW && steppedWidth < sqrtArea * 1000)
            {
                ProbeResult pr = new ProbeResult();
                if (LOG_LEVEL >= SA2LogLevel.trace)
                {
                    Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);
                }
                if (Probe(imgsToAdd, steppedWidth, steppedHeight, area, maxDimension, pr))
                {
                    successW = true;
                    if (bestRoot == null)
                    {
                        bestRoot = pr;
                    }
                    else if (pr.GetScore(doPowerOfTwoTextures) > bestRoot.GetScore(doPowerOfTwoTextures))
                    {
                        bestRoot = pr;
                    }
                }
                else
                {
                    numWIterations++;
                    steppedWidth = StepWidthHeight(steppedWidth, stepW, maxDimension);
                    if (LOG_LEVEL >= SA2LogLevel.debug)
                    {
                        SA2Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                    }
                }
            }
            steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimension);
            if (LOG_LEVEL >= SA2LogLevel.debug)
            {
                SA2Log.LogDebug("increasing Height h=" + steppedHeight + " w=" + steppedWidth);
            }
        }

        outW = 0;
        outH = 0;
        if (doPowerOfTwoTextures)
        {
            outW = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.w), maxDimension);
            outH = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.h), maxDimension);
            if (outH < outW / 2)
            {
                outH = outW / 2;                  //smaller dim can't be less than half larger
            }
            if (outW < outH / 2)
            {
                outW = outH / 2;
            }
        }
        else
        {
            outW = bestRoot.w;
            outH = bestRoot.h;
        }
        if (bestRoot == null)
        {
            return(null);
        }
        if (LOG_LEVEL >= SA2LogLevel.debug)
        {
            SA2Log.LogDebug("Best fit found: atlasW=" + outW + " atlasH" + outH + " w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.fitsInMaxSize);
        }

        List <Image> images = new List <Image>();

        flattenTree(bestRoot.root, images);
        images.Sort(new ImgIDComparer());
        if (images.Count != imgsToAdd.Length)
        {
            Debug.LogError("Result images not the same lentgh as source");
        }

        //scale images if too large
        int   newMinSizeX = minImageSizeX;
        int   newMinSizeY = minImageSizeY;
        bool  redoPacking = false;
        float padX        = (float)padding / (float)outW;

        if (bestRoot.w > maxDimension)
        {
            //float minSizeX = ((float)minImageSizeX + 1) / maxDimension;
            padX = (float)padding / (float)maxDimension;
            float scaleFactor = (float)maxDimension / (float)bestRoot.w;
            if (LOG_LEVEL >= SA2LogLevel.warn)
            {
                Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor);
            }
            for (int i = 0; i < images.Count; i++)
            {
                Image im = images[i];
                if (im.w * scaleFactor < masterImageSizeX)
                { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size
                    if (LOG_LEVEL >= SA2LogLevel.debug)
                    {
                        Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeX.");
                    }
                    redoPacking = true;
                    newMinSizeX = Mathf.CeilToInt(minImageSizeX / scaleFactor);
                }
                int right = (int)((im.x + im.w) * scaleFactor);
                im.x = (int)(scaleFactor * im.x);
                im.w = right - im.x;
            }
            outW = maxDimension;
        }

        float padY = (float)padding / (float)outH;

        if (bestRoot.h > maxDimension)
        {
            //float minSizeY = ((float)minImageSizeY + 1) / maxDimension;
            padY = (float)padding / (float)maxDimension;
            float scaleFactor = (float)maxDimension / (float)bestRoot.h;
            if (LOG_LEVEL >= SA2LogLevel.warn)
            {
                Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor);
            }
            for (int i = 0; i < images.Count; i++)
            {
                Image im = images[i];
                if (im.h * scaleFactor < masterImageSizeY)
                { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size
                    if (LOG_LEVEL >= SA2LogLevel.debug)
                    {
                        Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeY.");
                    }
                    redoPacking = true;
                    newMinSizeY = Mathf.CeilToInt(minImageSizeY / scaleFactor);
                }
                int bottom = (int)((im.y + im.h) * scaleFactor);
                im.y = (int)(scaleFactor * im.y);
                im.h = bottom - im.y;
            }
            outH = maxDimension;
        }

        Rect[] rs;
        if (!redoPacking)
        {
            rs = new Rect[images.Count];
            for (int i = 0; i < images.Count; i++)
            {
                Image im = images[i];
                Rect  r  = rs[i] = new Rect((float)im.x / (float)outW + padX,
                                            (float)im.y / (float)outH + padY,
                                            (float)im.w / (float)outW - padX * 2f,
                                            (float)im.h / (float)outH - padY * 2f);
                if (LOG_LEVEL >= SA2LogLevel.debug)
                {
                    SA2Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                    " y=" + r.y * outH + " w=" + r.width * outW +
                                    " h=" + r.height * outH + " padding=" + padding);
                }
            }
        }
        else
        {
            if (LOG_LEVEL >= SA2LogLevel.debug)
            {
                Debug.Log("==================== REDOING PACKING ================");
            }
            bestRoot = null;
            rs       = _GetRects(imgWidthHeights, maxDimension, padding, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, out outW, out outH, recursionDepth + 1);
        }

        if (LOG_LEVEL >= SA2LogLevel.debug)
        {
            SA2Log.LogDebug("Done GetRects");
        }
        return(rs);
    }
Exemplo n.º 5
0
    bool Probe(Image[] imgsToAdd, int idealAtlasW, int idealAtlasH, float imgArea, int maxAtlasDim, ProbeResult pr)
    {
        Node root = new Node();

        root.r = new PixRect(0, 0, idealAtlasW, idealAtlasH);
        for (int i = 0; i < imgsToAdd.Length; i++)
        {
            Node n = root.Insert(imgsToAdd[i], false);
            if (n == null)
            {
                return(false);
            }
            else if (i == imgsToAdd.Length - 1)
            {
                int usedW = 0;
                int usedH = 0;
                GetExtent(root, ref usedW, ref usedH);
                float efficiency, squareness;
                bool  fitsInMaxDim;
                if (doPowerOfTwoTextures)
                {
                    int atlasW = Mathf.Min(CeilToNearestPowerOfTwo(usedW), maxAtlasDim);
                    int atlasH = Mathf.Min(CeilToNearestPowerOfTwo(usedH), maxAtlasDim);
                    if (atlasH < atlasW / 2)
                    {
                        atlasH = atlasW / 2;
                    }
                    if (atlasW < atlasH / 2)
                    {
                        atlasW = atlasH / 2;
                    }
                    fitsInMaxDim = usedW <= maxAtlasDim && usedH <= maxAtlasDim;
                    float scaleW    = Mathf.Max(1f, ((float)usedW) / maxAtlasDim);
                    float scaleH    = Mathf.Max(1f, ((float)usedH) / maxAtlasDim);
                    float atlasArea = atlasW * scaleW * atlasH * scaleH; //area if we scaled it up to something large enough to contain images
                    efficiency = 1f - (atlasArea - imgArea) / atlasArea;
                    squareness = 1f;                                     //don't care about squareness in power of two case
                }
                else
                {
                    efficiency = 1f - (usedW * usedH - imgArea) / (usedW * usedH);
                    if (usedW < usedH)
                    {
                        squareness = (float)usedW / (float)usedH;
                    }
                    else
                    {
                        squareness = (float)usedH / (float)usedW;
                    }
                    fitsInMaxDim = usedW <= maxAtlasDim && usedH <= maxAtlasDim;
                }
                pr.Set(usedW, usedH, root, fitsInMaxDim, efficiency, squareness);
                if (LOG_LEVEL >= SA2LogLevel.debug)
                {
                    SA2Log.LogDebug("Probe success efficiency w=" + usedW + " h=" + usedH + " e=" + efficiency + " sq=" + squareness + " fits=" + fitsInMaxDim);
                }
                return(true);
            }
        }
        Debug.LogError("Should never get here.");
        return(false);
    }