使用Unity绘制应用程序

时间:2019-04-26 11:31:41

标签: c# unity3d

在过去的一周中,我一直在寻找一种使用Unity创建应用程序的方法,在其中可以创建图形。

类似这样的东西:

drawing application

我尝试了几种模拟绘图的方法,但没有一个能达到我的预期。

您认为实现此目标的推荐方法是什么? 我尝试使用SetPixel和GetPixel,但是由于在运行时编辑纹理可能非常缓慢,因此我在寻找更好的方法(如果有的话)。

谢谢。

1 个答案:

答案 0 :(得分:1)

我还没有用较大的纹理测试过它,但是我用它画了一张快乐的脸,我有评论来解释代码中发生了什么,最好的使用方法是使用Unity Menu并创建RawImage然后附加此脚本:

using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(RawImage))]
public class PaintCanvas : MonoBehaviour
{

    RectTransform rt;
    RawImage ri;
    Vector3 bottomLeft = Vector3.zero;
    Vector3 topRight = Vector3.zero;
    Texture2D canvas;

    int width = 0;
    int height = 0;

    // Start is called before the first frame update
    void Start()
    {
        // Getting the RectTransform, since this is a RawImage, which exists on the canvas and should have a rect transform
        rt = GetComponent<RectTransform>();
        if (rt != null)
        {
            GetWorldCorners();
        }
        // RawImage that we are going to be updating for our paint application.
        ri = GetComponent<RawImage>();
        if (ri != null)
        {
            CreateTexture2D();
        }
    }

    // Update is called once per frame
    void Update()
    {
        // Make sure our stuff is valid
        if (rt != null)
        {
            if(ri != null)
            {
                HandleInput();
            }
        }
    }

    void HandleInput()
    {
        // Since we can only paint on the canvas if the mouse button is press
        // May be best to revise this so the tool has a call back for example a 
        // fill tool selected would call its own "Handle" method,

        if(Input.GetMouseButtonDown(0) || Input.GetMouseButton(0))
        {
            Vector2Int mousePos = Vector2Int.zero;
            // We have input, lets convert the mouse position to be relative to the canvas
            ConvertMousePosition(ref mousePos);
            // Checking that our mouse is in bounds, which is stored in our height and width variable and as long as it has a "positive value"
            if(MouseIsInBounds(mousePos))
            {
                // This method could be removed to be the tool method I mention above
                // you would pass in the mousePosition, and color similar to this.
                // This way each tool would be its "own" component that would be activated
                // through some form of UI.
                PaintTexture(mousePos, Color.black); // Also the color you want would be here to...
            }

            Debug.Log(mousePos);
        }
    }

    void PaintTexture(Vector2Int pos, Color color)
    {
        // In our method we don't allow transparency and we are just replacing the pixel,
        canvas.SetPixel(pos.x, pos.y, color);
        // Applying out change, we dont want to mip levels.
        // If you are doing some blending or transparency stuff that would be handled by your tool
        canvas.Apply(false);
    }

    bool MouseIsInBounds(Vector2Int mousePos)
    {
        // The position is already relative to the texture so if it is >= to 0 and less then the texture
        // width and height it is in bounds.
        if(mousePos.x >= 0 && mousePos.x < width)
        {
            if (mousePos.y >= 0 && mousePos.y < height)
            {
                return true;
            }
        }
        return false;
    }

    void ConvertMousePosition(ref Vector2Int mouseOut)
    {
        // The mouse Position, and the RawImage position are returned in the same space
        // So we can just update based off of that
        mouseOut.x = Mathf.RoundToInt(Input.mousePosition.x - bottomLeft.x);
        mouseOut.y = Mathf.RoundToInt(Input.mousePosition.y - bottomLeft.y);
    }

    void CreateTexture2D()
    {
        // Creating our "Draw" texture to be the same size as our RawImage.
        width = Mathf.RoundToInt(topRight.x - bottomLeft.x);
        height = Mathf.RoundToInt(topRight.y - bottomLeft.y);
        canvas = new Texture2D(width, height);
        ri.texture = canvas;
    }

    void GetWorldCorners()
    {
        if (rt != null)
        {
            Vector3[] corners = new Vector3[4];
            rt.GetWorldCorners(corners);

            // Setting our corners  based on the fact GetCorners returns them in clockwise order starting from BL TL TR BR.
            bottomLeft = corners[0];
            topRight = corners[2];
        }
    }
}

我只想指出一点,具体取决于您的比例以及移动鼠标的速度,最终可能会出现点,这是因为,如果您移动鼠标的速度更快,此算法只会更新每帧鼠标移过的像素那么每帧有1 px的间隙,可以通过存储mousePosition的最后一帧,获得该帧的新位置,并创建一条线,然后更新该线上的所有点来解决此问题。