Простой пример рисования в Unity

Создать одноклеточный редактор рисования достаточно просто, вся суть действия происходит через RenderTexture, главное разобраться с логикой работы. Заключается она в следующем. На сцене у нас две камеры, первая, смотрит на «чистый лист», то есть объект с материалом, но без текстуры, так же, перед этой камерой создаются клоны кисти, из которых образуется рисунок, а камера в свою очередь передает изображение в рендер текстуру. Эта текстура прицеплена на материал другого объекта, который находится перед второй камерой. То есть когда мы водим мышкой по холсту (где рендер текстура), то создаем клоны кисточки там, где находится первая камера, а она возвращает нам текстуру с рисунком.

Делается это так. Создаем стандартный Quad с шейдером Unlit > Texture, размеры оставляем по умолчанию, позиция по нулям. Добавляем еще одну камеру (позиция по нулям), разворачиваем квадрат на нее. Камеру переключаем в режим Orthographic, параметр Clear Flags переключаем в Depth only. Затем настраиваем Size камеры так, чтобы квадрат помещался в рамку:

Простой пример рисования в Unity

На сцену добавляем и саму кисточку, спрайт точнее, позиция тоже по нулям. Эти три объекта, камера, квадрат и кисточка, их нужно расположить так, что кисточка была между камерой и квадратом. То бишь получиться, что камера смотрит на холст, а кисточка создает рисунок.

Далее, создаем еще один квадрат, по которому мы будем царапать мышкой, делаем его по больше и ставим перед главной камерой, не забивая убрать их в другое место, чтобы они не мешали другой камере. Вешаем куда-нибудь скрипт:

using UnityEngine;
using System.Collections;

public class Paint : MonoBehaviour {

	public SpriteRenderer brush; // спрайт кисточки
	public Color brushColor = Color.red;
	[Range(0.01f, 0.05f)] public float brushSize = 0.05f;
	public Camera cameraRT; // камера перед кисточкой и квадратом
	public int sizeRT = 1024; // размер текстуры
	public MeshRenderer canvasObject; // холст, по которому мы водим курсором мышки
	public MeshRenderer planeRT; // холст, стандартный квадрат

	private RenderTexture renderTexture;
	private Vector3 position;
	private int counter = 0, maxCount = 1000; // счетчик и макс. количество объектов
	private bool isSave;

	void Awake()
	{
		position.z = brush.transform.position.z;
		Clear();
	}

	void Update()
	{
		if(Input.GetMouseButton(0) && !isSave)
		{
			brush.gameObject.SetActive(true);
			Draw();
		}
		else if(Input.GetMouseButtonDown(1))
		{
			Clear();
		}
		else if(isSave)
		{
			brush.gameObject.SetActive(false);
			Save();
		}
		else 
		{
			brush.gameObject.SetActive(false);
		}

	}

	// сохранение текущего рисунка и очистка счетчика
	// будет создана текстура и помещена в холст, перед рендер текстурой
	// это необходимо для оптимизации, чтобы не создавать слишком много объектов
	void Save() 
	{
		counter = 0;
		RenderTexture.active = renderTexture;
		Texture2D tex = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGB24, false);		
		tex.ReadPixels(new Rect (0, 0, renderTexture.width, renderTexture.height), 0, 0);
		tex.Apply();
		RenderTexture.active = null;
		planeRT.material.mainTexture = tex;
		foreach(Transform child in planeRT.transform) 
		{
			Destroy(child.gameObject);
		}
		isSave = false;
	}

	void Clear() // очистить всё
	{
		counter = 0;
		foreach(Transform child in planeRT.transform) 
		{
			Destroy(child.gameObject);
		}
		Destroy(planeRT.material.mainTexture);
		Destroy(renderTexture);
		renderTexture = new RenderTexture(sizeRT, sizeRT, 24, RenderTextureFormat.ARGB32);
		cameraRT.targetTexture = renderTexture;
		canvasObject.material.mainTexture = renderTexture;
	}

	void Draw() // рисование (клонирование кисти)
	{
		RaycastHit hit;
		Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if(Physics.Raycast(ray, out hit))
		{
			SpriteRenderer s = Instantiate(brush) as SpriteRenderer;
			Vector2 uv = new Vector2(hit.textureCoord.x, hit.textureCoord.y);
			position.x = uv.x - cameraRT.orthographicSize;
			position.y = uv.y - cameraRT.orthographicSize;
			s.color = brushColor;
			s.transform.localPosition = position;
			s.transform.localScale = Vector3.one * brushSize;
			s.transform.parent = planeRT.transform;
			counter++;

			if(counter > maxCount)
			{
				isSave = true;
			}
		}
	}
}

Настраиваем переменные и можно тестить.

Скачать демо:

У вас нет доступа!

Комментариев 4

Офлайн
Sershum 8 января 2017
Здравствуйте, с Новым Годом Вас и Рождеством! Вопрос не по теме, но все же. Допустим перс заходит в дом и дом становится полупрозрачным, я понимаю, что можно это сделать двумя материалами (при входе и выходе в триггер тупо менять их) , хотелось бы как-нибудь поизящней))) например как менять параметры материала (шейдера) из скрипта
Офлайн
Light 9 января 2017
Sershum, чтобы поменять параметр шейдера, для начала создаем переменную, где указываем нужным меш:

[SerializeField] private MeshRenderer mesh;
[SerializeField] private Color color;

Затем надо посмотреть, название параметра в коде шейдера, встроенные стандартные шейдеры можно скачать здесь, в меню "дополнительные загрузки".

Находим там шейдер по умолчанию, файл Standard.shader и открываем его с помощью, например, редактора Notepad++

Допустим я хочу регулировать параметр Emission;


Ищем в коде шейдера строку: _EmissionColor("Color", Color) = (0,0,0) тут нам нужен параметр _EmissionColor, этот параметр типа Color.

И через ранее объявленную переменную, получаем доступ:

mesh.material.SetColor("_EmissionColor", color);

Если материалов несколько на меше:


В этом случаи используем немного другой код:

mesh.materials[0].SetColor("_EmissionColor", color);

Где 0 это идентификатор материала в массиве.
Офлайн
Sershum 9 января 2017
О, ДА! Это именно то, что было нужно! Огромное СПАСИБО!
Офлайн
Light,
А что такое [SerializeField] и для чего он нужен ?
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика