Следы от пуль / пятна крови на персонаже

Тема достаточно интересная, попробуем в ней разобраться. Чаще можно встретить примеры реализации следов от пуль на стенах, когда используется спрайт или мэш с текстурой, который накладывается на объект, то есть на стену, например. Сделать это просто и вроде бы, всё работает как надо. Но тут есть пара проблем. Во-первых, если допустим спрайт наложить на край стены, то получится, что часть спрайта просто висит в воздухе, не очень-то красиво выходит. Во-вторых, спрайт или мэш, то бишь плоский объект, не получится наложить на рельеф, или например, на модель персонажа, типа пятна крови и тому подобное. И поэтому, мы будем использовать проектор, чтобы решить эти проблемы, главное, правильно его настроить.


В начале импортируем стандартные ассеты Effects, потому как там есть нужные нам шейдеры. Затем, надо сделать пару новых слоев, для плоской поверхности и для вражеского персонажа допустим. И соответственно назначаем объектам эти слои. Это нужно чтобы конкретные проекторы работали с конкретными слоями, не перекрывая другие:

Следы от пуль / пятна крови на персонаже

Создадим префаб проектора для плоской поверхности, для стен например. Добавляем на сцену новый пустой объект и назовем его ProjectorWall, цепляем на него компонент Projector с настройками как на скриншоте:


Как видно, здесь мы исключаем все слои, кроме слоя Wall в списке Ignore Layers. Параметр Orthographic Size для настройки размера, в режиме Orthographic, это режим лучше всего подходит под наши задачи.

Теперь создаем новый материал под именем Wall и указываем его в соответствующем поле проектора. В материале выбираем шейдер Projector > Multiply:


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


Будет видимый только центр. Настройки текстуры выглядят следующим образом:


Настройки текстуры дырок от пуль для Cookie такие:


Важный момент! След от пули или пятно крови, должно быть на белом фоне, не прозрачном. Формат может быть PNG или JPG, без разницы.

Теперь сделаем дубликат префаба проектора, назовем его ProjectorEnemy настройки почти такие же, но в списке Ignore Layers уже исключаем все кроме слоя Enemy.


А так же укажем новый материал. Дубликат предыдущего, но с другими текстурами, настройки самих текстур такие же, вид FallOff уже будет таким:


Тут уже больше белой области и только края черные. Потому как для рельефа область прорисовки нужна больше, потому что есть глубина.

На оба префаба, вешаем скрипт BulletProjector:

using UnityEngine;
using System.Collections;

public class BulletProjector : MonoBehaviour {
	
	public float distanceTolerance = 0.05f;
	private float origNearClipPlane;
	private float origFarClipPlane;
	private Projector projector;

	void Start() 
	{
		projector = GetComponent<Projector>();
		origNearClipPlane = projector.nearClipPlane;
		origFarClipPlane = projector.farClipPlane;
		Late();
	}

	void Late()
	{
		Ray ray = new Ray(projector.transform.position + projector.transform.forward.normalized * origNearClipPlane, projector.transform.forward);
		RaycastHit hit = new RaycastHit();
		if (Physics.Raycast (ray, out hit, origFarClipPlane - origNearClipPlane, ~projector.ignoreLayers)) 
		{
			float dist = hit.distance + origNearClipPlane;
			projector.nearClipPlane = Mathf.Max(dist - distanceTolerance, 0);
			projector.farClipPlane = dist + distanceTolerance;
		}
	}
}

Скрипт укорачивает рабочую область проектора, допуск мы указываем в переменной distanceTolerance. Для плоскости вполне хватит значения 0.05, а для рельефа 0.1 или больше. Поэкспериментируйте с префабами проекторов и найдите нужное вам значение.

Теперь стрельба.
Добавьте на сцену UI объект типа Image размещаем его по центру экрана указывает спрайт прицела и вешаем на объект скрипт FireSystem, который будет создавать проекторы:

using UnityEngine;
using System.Collections;

public class FireSystem : MonoBehaviour {

	public GameObject projectorWall;
	public GameObject projectorEnemy;
	public int maxProjectors = 50;
	private GameObject[] projectorsArray;
	private int tmpCount;
	private GameObject projector;

	void Start () 
	{
		projectorsArray = new GameObject[maxProjectors];
	}

	void Update () 
	{
		RaycastHit hit;
		Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if (Physics.Raycast(ray, out hit))
		{
			if(Input.GetMouseButtonDown(0))
			{
				Quaternion projectorRotation = Quaternion.FromToRotation(-Vector3.forward, hit.normal);

				switch(hit.transform.gameObject.layer)
				{
				case 8: // номер слоя с плоскими объектами
					projector = projectorWall;
					break;
				case 9: // номер слоя с моделями персонажей или рельефных объектов
					projector = projectorEnemy;
					break;
				}

				if(projector == null) return;

				GameObject obj = Instantiate(projector, hit.point + hit.normal * 0.25f, projectorRotation) as GameObject;

				Destroy(projectorsArray[tmpCount]);
				projectorsArray[tmpCount] = obj;

				obj.transform.parent = hit.transform;

				Quaternion randomRotZ = Quaternion.Euler(obj.transform.eulerAngles.x, obj.transform.eulerAngles.y, Random.Range(0, 360));
				obj.transform.rotation = randomRotZ;

				if(tmpCount == maxProjectors-1) tmpCount = 0; else tmpCount++;
			}
		}
	}
}

Ничего особенного тут нет. Выбор какой создавать объект в зависимости от слоя цели, плюс поворот префаба рандомно по Z. Стоит отметить параметр maxProjectors, то есть сколько всего проектором можно создать, экономия ресурсов системы. Когда максимальное число достигнуто, то новые объекты будут заменять первые, то есть если их всего 50 то после появления 51-го, уничтожен будет объект под номером 1.

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

У вас нет доступа!
Тестировалось на: Unity 5.5.2

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

Офлайн
hell 28 июля 2015
Я сделал Но почему то у меня появляющийся следы в левой стороне от камеры((((

hell,
УУ Разобрано!!!)))

А как сделать чтоб не было видно след когда подходишь к стене или на пол смотришь ((((????
Офлайн
Light 28 июля 2015
Цитата: hell
А как сделать чтоб не было видно след когда подходишь к стене или на пол смотришь ((((????

Почему его не должно быть видно, если проектор прикреплен к объекту. В чём суть вопроса?
Офлайн
Я сделал, но следы неправильно отображаются, можете помочь?
Скриншот:
http://fs65.www.ex.ua/show/265402787/265402787.png?800
Офлайн
Light 16 августа 2016
Євгеній Степанюк, какая текстура используется?
Офлайн
Light,
Та которая в архиве.
Офлайн
Light 17 августа 2016
Євгеній Степанюк, судя по скрину у тебя ошибка с Instantiate, перепроверь все по порядку.
Офлайн
McHack 1 января 2017
Нет шейдера "Projector > Multiply". Попытался найти что-то похожее, ничего не получилось...
Офлайн
Light 1 января 2017
McHack, эти шейдеры находятся в стандартном ассете эффектов.

Офлайн
у меня след от выстрела появляется не там, куда указывает прицел, а в левом нижнем углу. В чем может быть дело?
Офлайн
Light 6 января 2017
Андрей Федотов, заменить:

Ray ray = Camera.main.ScreenPointToRay (transform.position);

На:

Ray ray = Camera.main.ScreenPointToRay (Screen.width/2, Screen.height/2);
Офлайн
Light, ошибка: FireSystem.cs(21,39): error CS1501: No overload for method `ScreenPointToRay' takes `2' arguments
Офлайн
Light 22 января 2017
Андрей Федотов, верно, я чет не доглядел сразу)) Вот так правильно:

Ray ray = Camera.main.ScreenPointToRay(new Vector2(Screen.width/2, Screen.height/2));
Офлайн
Странно, выдаёт вот такую ошибку, когда на ЛКМ нажимаю ArgumentException: The Object you want to instantiate is null.
UnityEngine.Object.CheckNullArgument (System.Object arg, System.String message) (at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:196)
UnityEngine.Object.Instantiate (UnityEngine.Object original, Vector3 position, Quaternion rotation) (at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:143)
FireSystem.Update () (at Assets/Scripts/FireSystem.cs:39)
Помогите пожалуйста.
Офлайн
Light 25 февраля 2017
Александр Нехороший, не определен объект. Код скрипта обновлен.
Офлайн
Light,
Теперь ошибок нет, но проекторы не спавнятся.
Офлайн
Light 25 февраля 2017
Александр Нехороший, нужно создать слои и назначить их соответствующим объектам.
Офлайн
Light,
Можете скинуть готовый UnityPackage?
Офлайн
Light 26 февраля 2017
Александр Нехороший, добавил демо, ссылка в статье.
Офлайн
nanaminer 6 мая 2017
Спасибо большое! Всё работает, но есть одно но: Непонятные тёмные пятна, появляющиеся вместе с проектором! Скрин: https://vk.com/photo280227968_456239039

Помогите пожалуйста! worried
(Unity3d 5.6.0)
Офлайн
Light 6 мая 2017
nanaminer, нечего такого не наблюдалось при тесте (5.6.0).
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика