Exemple #1
0
        public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource = true)
        {
            //Profile.Start//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects1");
            //PART 1 ==== Validate
            if (_usingTemporaryTextureBakeResult && gos != null && gos.Length > 0)
            {
                _textureBakeResults = null;
                _usingTemporaryTextureBakeResult = false;
            }

            //if all objects use the same material we can create a temporary _textureBakeResults
            if (_textureBakeResults == null && gos != null && gos.Length > 0 && gos[0] != null)
            {
                if (!_CreateTemporaryTextrueBakeResult(gos))
                {
                    return(false);
                }
            }

            if (!_validate(gos, deleteGOinstanceIDs))
            {
                return(false);
            }
            _distributeAmongBakers(gos, deleteGOinstanceIDs);
            if (LOG_LEVEL >= MBLogLevel.debug)
            {
                MBLog.LogDebug("MB2_MultiMeshCombiner.AddDeleteGameObjects numCombinedMeshes: " + meshCombiners.Count + " added:" + gos + " deleted:" + deleteGOinstanceIDs + " disableRendererInSource:" + disableRendererInSource + " maxVertsPerCombined:" + _maxVertsInMesh);
            }
            return(_bakeStep1(gos, deleteGOinstanceIDs, disableRendererInSource));
        }
Exemple #2
0
        public static Vector2[] GetMeshUV3orUV4(Mesh m, bool get3, MBLogLevel LOG_LEVEL)
        {
            Vector2[] uvs;
            if (get3)
            {
                uvs = m.uv3;
            }
            else
            {
                uvs = m.uv4;
            }

            if (uvs.Length == 0)
            {
                if (LOG_LEVEL >= MBLogLevel.debug)
                {
                    MBLog.LogDebug("Mesh " + m + " has no uv" + (get3 ? "3" : "4") + ". Generating");
                }
                uvs = new Vector2[m.vertexCount];
                for (int i = 0; i < uvs.Length; i++)
                {
                    uvs[i] = _HALF_UV;
                }
            }
            return(uvs);
        }
Exemple #3
0
 public static Vector2[] GetMeshUV1s(Mesh m, MBLogLevel LOG_LEVEL)
 {
     Vector2[] uv;
     if (LOG_LEVEL >= MBLogLevel.warn)
     {
         MBLog.LogDebug("UV1 does not exist in Unity 5+");
     }
     uv = m.uv;
     if (uv.Length == 0)
     {
         if (LOG_LEVEL >= MBLogLevel.debug)
         {
             MBLog.LogDebug("Mesh " + m + " has no uv1s. Generating");
         }
         if (LOG_LEVEL >= MBLogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have uv1s. Generating uv1s.");
         }
         uv = new Vector2[m.vertexCount];
         for (int i = 0; i < uv.Length; i++)
         {
             uv[i] = _HALF_UV;
         }
     }
     return(uv);
 }
        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 >= MBLogLevel.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 >= MBLogLevel.debug)
                {
                    MBLog.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MBLogLevel.debug)
                {
                    MBLog.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MBLogLevel.debug)
                {
                    MBLog.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 >= MBLogLevel.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 >= MBLogLevel.debug)
                        {
                            MBLog.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimension);
                if (LOG_LEVEL >= MBLogLevel.debug)
                {
                    MBLog.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 >= MBLogLevel.debug)
            {
                MBLog.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 >= MBLogLevel.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 >= MBLogLevel.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 >= MBLogLevel.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 >= MBLogLevel.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 >= MBLogLevel.debug)
                    {
                        MBLog.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 >= MBLogLevel.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 >= MBLogLevel.debug)
            {
                MBLog.LogDebug("Done GetRects");
            }
            return(rs);
        }
        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 >= MBLogLevel.debug)
                    {
                        MBLog.LogDebug("Probe success efficiency w=" + usedW + " h=" + usedH + " e=" + efficiency + " sq=" + squareness + " fits=" + fitsInMaxDim);
                    }
                    return(true);
                }
            }
            Debug.LogError("Should never get here.");
            return(false);
        }
Exemple #6
0
 bool _bakeStep1(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource)
 {
     //Profile.End//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects2.2");
     //Profile.Start//Profile("MB2_MultiMeshCombiner.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(gos, true);
             if (_LOG_LEVEL >= MBLogLevel.debug)
             {
                 MBLog.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 >= MBLogLevel.debug)
             {
                 MBLog.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("MB2_MultiMeshCombiner.AddDeleteGameObjects3");
     if (LOG_LEVEL >= MBLogLevel.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;
         MBLog.LogDebug(s, LOG_LEVEL);
     }
     if (meshCombiners.Count > 0)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
Exemple #7
0
        void _distributeAmongBakers(GameObject[] gos, int[] deleteGOinstanceIDs)
        {
            if (gos == null)
            {
                gos = empty;
            }
            if (deleteGOinstanceIDs == null)
            {
                deleteGOinstanceIDs = emptyIDs;
            }

            if (resultSceneObject == null)
            {
                resultSceneObject = new GameObject("CombinedMesh-" + 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("MB2_MultiMeshCombiner.AddDeleteGameObjects1");

            //Profile.Start//Profile("MB2_MultiMeshCombiner.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 >= MBLogLevel.debug)
                    {
                        MBLog.LogDebug("MB2_MultiMeshCombiner.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 = MeshBakerUtility.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 >= MBLogLevel.debug)
                        {
                            MBLog.LogDebug("MB2_MultiMeshCombiner.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 >= MBLogLevel.debug)
                    {
                        MBLog.LogDebug("MB2_MultiMeshCombiner.Created new combinedMesh");
                    }
                }
                cm.gosToAdd.Add(go);
                cm.numVertsInListToAdd += numVerts;
                //			obj2MeshCombinerMap.Add(go,cm);
            }
        }