1 回答
TA贡献1898条经验 获得超8个赞
我没有用相对较大的纹理对此进行测试,但我用它画了一张快乐的脸,我有评论解释代码中发生了什么,使用它的最佳方法是使用 Unity 菜单并创建一个 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 来解决,获取这一帧的新位置,并创建一条线,然后更新该线上的所有点。
- 1 回答
- 0 关注
- 136 浏览
添加回答
举报