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

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


В начале импортируем стандартные ассеты 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(transform.position);
		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;
				}

				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.

Скачать текстуры по теме:

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

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

Офлайн
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));
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика