К основному контенту

Unity: Рисуем на песке



В качестве прототипа, нужно было сделать рисование на песке. От первоначальной идеи отказались, но наработка немного необычная.




Есть plane/quad на ней простой материал с поддержкой прозрачности, текстура песка с включенным read/write. Когда мы нажимаем ЛКМ на текстуре в зоне луча от мыши накладывается прозрачность по шаблону кисти 1. Когда нажимаем ПКМ рисунок восстанавливается по шаблону кисти 2. Действия происходят при помощи методов GetPixels / SetPixels.

Кисть 1, Кисть 2


PS: Плохокод, собрано за несколько часов, но авось пригодиться.


using UnityEngine;

public class DrawSand : MonoBehaviour
{
    public Collider myCollider;
    public Renderer myRenderer;
    public Texture2D eraser;
    public Texture2D painter;

    private Texture2D org;
    private Texture2D tex;

    void Start()
    {
        org = myRenderer.material.mainTexture as Texture2D;
        tex = new Texture2D(org.width, org.height);
        tex.SetPixels(0, 0, org.width, org.height, org.GetPixels(0, 0, org.width, org.height));
        tex.Apply();
        myRenderer.material.mainTexture = tex;
    }

    void Update()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
        {
            if (Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
                Color[] tcls = new Color[eraser.width * eraser.height];
                Color[] ocls = new Color[eraser.width * eraser.height];
                Color[] acls = eraser.GetPixels();
                Color[] pcls = painter.GetPixels();
                // Find the u,v coordinate of the Texture
                Vector2 uv;
                uv.x = (hit.point.x - hit.collider.bounds.min.x) / hit.collider.bounds.size.x;
                uv.y = (hit.point.y - hit.collider.bounds.min.y) / hit.collider.bounds.size.y;
                // Paint it
                tcls = tex.GetPixels((int)(uv.x * tex.width), (int)(uv.y * tex.height), eraser.width, eraser.height);
                ocls = org.GetPixels((int)(uv.x * tex.width), (int)(uv.y * tex.height), eraser.width, eraser.height);
                for (int i = 0; i < tcls.Length; i++)
                {
                    if (Input.GetMouseButton(0))
                        tcls[i].a = Mathf.Min(tcls[i].a, acls[i].a);
                    if (Input.GetMouseButton(1))
                        tcls[i].a = Mathf.Max(tcls[i].a, pcls[i].a);
                }
                tex.SetPixels((int)(uv.x * tex.width), (int)(uv.y * tex.height), eraser.width, eraser.height, tcls);
                tex.Apply();
            }
        }
    }

}

Комментарии