使用Unity绘制应用程序 [英] Drawing application with Unity

查看:378
本文介绍了使用Unity绘制应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

for the past week, I've been looking for a way to create an application with Unity, in which I will be able to create drawings.

类似这样的东西:

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

I've tried several ways to simulate drawing, but none of them accomplished why I expected.

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

What would you say to be the recommended way to achieve this? I tried using SetPixel & GetPixel, but since editing textures at runtime can be very slow, I'm looking for a better way, if there's any.

谢谢.

推荐答案

我没有用较大的纹理进行测试,但是我用它画了一张幸福的脸,我有评论来解释代码中发生的事情,最好的是使用此方法的方法是使用Unity菜单并创建RawImage,然后附加此脚本:

I haven't tested this with a relatively large texture but I painted a happy face with it, I have comments explaining whats going on in the code, the best way to use this is using the Unity Menu and creating a RawImage then attaching this script:

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最后一帧,在该帧中获得新位置并创建一条线,然后更新该线上的所有点来解决此问题.

I just want to point out depending on your scale, and how fast you move the mouse you may end up with dots, that is because this algorithim only updates the pixels that mouse is over per frame, if you move the mouse faster then 1 px per frame you will have gaps, this can be resolved by storing the mousePosition last frame, getting the new position this frame, and creating a line, then updating all points on that line.

这篇关于使用Unity绘制应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆