Esempio n. 1
0
        private static Vector2 RenderToTexture2D(string path, Shape shape, float pixelsPerUnit = 100)
        {
            // reset the shape's rotation
            Quaternion oldRotation = shape.transform.rotation;

            shape.transform.rotation = Quaternion.identity;

            // get the bounds of our shape and all its children
            Bounds  bounds = shape.GetShapeBounds();
            Vector2 size   = shape.GetShapePixelSize(pixelsPerUnit: pixelsPerUnit);
            int     w      = (int)size.x;
            int     h      = (int)size.y;

            // get all the shapes in draw order
            List <Shape> shapes = shape.GetShapesInDrawOrder();

            // if the shape is a UI component, we need to set up the canvas in a way
            // that the camera can point to the image only without the UI
            // components moving around based on the camera
            Canvas              canvas           = shape.GetComponentInParent <Canvas>();
            int                 oldCanvasLayer   = -1;
            RenderMode          oldRenderMode    = 0;
            List <GraphicState> modifiedGraphics = null;

            if (canvas)
            {
                oldCanvasLayer          = canvas.gameObject.layer;
                canvas.gameObject.layer = 31;
                oldRenderMode           = canvas.renderMode;
                canvas.renderMode       = RenderMode.WorldSpace;
                // without a way to selectively show just the shape we want, this is
                // the only way I can think of to do it.  even this won't work if the
                // user has a UI component not found by this function.
                modifiedGraphics = DisableUIGraphics(canvas);
            }

            // make a new render texture
            RenderTexture rt = new RenderTexture(w, h, 32, RenderTextureFormat.ARGB32);

            rt.filterMode       = FilterMode.Point;
            rt.autoGenerateMips = false;
            rt.Create();

            // set up the camera to point exactly at the object's bounds and set its
            // culling layer to show only layer 31
            // note that if the user has anything on layer 31 then it will also
            // show up in the png, but in that event they can just move it away
            Camera cam = new GameObject().AddComponent <Camera>();

            cam.backgroundColor     = new Color(1, 1, 1, 0);
            cam.clearFlags          = CameraClearFlags.SolidColor;
            cam.transform.position  = bounds.center;
            cam.transform.position -= new Vector3(0, 0, 10);
            cam.orthographic        = true;
            cam.orthographicSize    = bounds.extents.y;
            cam.aspect              = bounds.size.x / bounds.size.y;
            cam.targetTexture       = rt;
            cam.cullingMask         = 1 << 31;

            // make the render texture active so calls to Texture2D.ReadPixels() will
            // read from it
            RenderTexture oldRT = RenderTexture.active;

            RenderTexture.active = rt;

            // draw each shape with blending turned off, and layer them on top of each
            // other with blending between shapes but not between a shape and the
            // camera's background color, which is what would happen if we just let the
            // camera render all of them - the camera's background color affects the
            // color of semi-transparent pixels even if the background color has an
            // alpha value of 0.  this is because the shader's blending is trying to
            // alias against the background color, but in the png we don't want that.
            // there's no shader option I'm aware of that would be able to blend between
            // shapes but not between a shape and the background color, so that's why
            // we have to do it manually.
            Texture2D dstTex = null;

            foreach (Shape s in shapes)
            {
                if (canvas)
                {
                    Graphic g = s.GetComponent <Graphic>();
                    g.enabled = true;
                    if (s.GetComponent <Mask>() != null)
                    {
                        foreach (GraphicState gs in modifiedGraphics)
                        {
                            if (gs.graphic == g && gs.showMaskGraphic)
                            {
                                s.GetComponent <Mask>().showMaskGraphic = true;
                            }
                        }
                    }
                }
                if (dstTex == null)
                {
                    dstTex = s.DrawToTexture2D(cam, w, h);
                }
                else
                {
                    Texture2D srcTex = s.DrawToTexture2D(cam, w, h);
                    BlendTextures(dstTex, srcTex);
                    DestroyImmediate(srcTex);
                }
                if (canvas)
                {
                    if (s.GetComponent <Mask>() == null)
                    {
                        s.GetComponent <Graphic>().enabled = false;
                    }
                    else
                    {
                        s.GetComponent <Mask>().showMaskGraphic = false;
                    }
                }
            }

            // put the old render texture back
            RenderTexture.active = oldRT;

            // grab the sprite's pivot point based on the top object's location
            // relative to its children
            Vector2 pivot = shape.GetPivot();

            // restore the shape's rotation
            shape.transform.rotation = oldRotation;

            // restore the canvas
            if (canvas)
            {
                canvas.gameObject.layer = oldCanvasLayer;
                canvas.renderMode       = oldRenderMode;
                foreach (GraphicState gs in modifiedGraphics)
                {
                    gs.graphic.enabled = true;
                    if (gs.hasMask)
                    {
                        gs.graphic.GetComponent <Mask>().showMaskGraphic = gs.showMaskGraphic;
                    }
                }
            }

            // save the png
            byte[] bytes = dstTex.EncodeToPNG();
            System.IO.File.WriteAllBytes(path, bytes);

            // clean up
            DestroyImmediate(dstTex);
            DestroyImmediate(cam.gameObject);
            DestroyImmediate(rt);

            return(pivot);
        }