Простой пример 3D маски (Depth Mask)

В играх с видом от третьего лица, когда камера подвешена сверху под некоторым углом, если персонаж, например, за стеной стоит или зданием, и его невидно, в этом случае можно объект сделать невидимым. Но, такой подход не всегда хорошо работает, потому как убирать, допустим, целые стены замка, не вариант в принципе. Здесь в играх, применяют эффект маски, чтобы вырезать область вокруг персонажа, в этой области здание или стена становятся прозрачными, и мы, словно как в окошко, видим сквозь объекты. Попробуем реализовать простой пример подобной маски и одновременно прозрачности объекта...


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

Один материал обычный:

Простой пример 3D маски (Depth Mask)

Второй материал в режиме прозрачности:


Используем стандартные шейдеры.

Теперь, на нужный объект добавляем скрипт:

using UnityEngine;
[AddComponentMenu("Rendering/Material Control")]
public class MaterialControl : MonoBehaviour
{
    public MeshRenderer meshRenderer;
    public Material opaque, transparent;

    void OnValidate()
    {
        meshRenderer = GetComponent<MeshRenderer>();
    }

    public void SetMask(bool value)
    {
        if (value)
        {
            meshRenderer.material = transparent;
        }
        else
        {
            meshRenderer.material = opaque;
        }
    }
}
Здесь мы указываем обычный и прозрачный материалы.

Следующий шаг, создаем простой шейдер:

Shader "Custom/DepthMask" 
{
	SubShader
	{
		Tags {"Queue" = "Transparent-1" }
		ColorMask 0
		ZWrite On
		Pass {}
	}
}
Этот шейдер будет работать только с другими в режиме прозрачности.

Далее, нужно создать материал для этого шейдера и добавить материал на обычную сферу.

На сферу вешаем скрипт:

using UnityEngine;

public class MaskControl : MonoBehaviour
{
    public Transform player, mask; // трансформ маски и игрока
    public float maskSize = 4;
    public float maskFade = 10;
    public LayerMask playerMask; // слои, которые нужно игнорировать (например, слой игрока)
    private Vector3 maskScale, maskDir;
    private MaterialControl wall;

    void Start()
    {
        maskScale = new Vector3(maskSize, maskSize, maskSize);
        mask.localScale = Vector3.zero;
    }

    void Update()
    {
        RaycastHit raycastHit;

        if (Physics.Linecast(Camera.main.transform.position, player.position, out raycastHit, ~playerMask))
        {
            maskDir = raycastHit.point - player.position;

            if (wall == null)
            {
                wall = raycastHit.collider.GetComponent<MaterialControl>();
                wall.SetMask(true);
            }

            mask.localScale = Vector3.MoveTowards(mask.localScale, maskScale, maskFade * Time.deltaTime);
        }
        else
        {
            mask.localScale = Vector3.MoveTowards(mask.localScale, Vector3.zero, maskFade * Time.deltaTime);

            if (mask.localScale.x == 0)
            {
                if (wall != null)
                {
                    wall.SetMask(false);
                    wall = null;
                }
            }
        }

        mask.position = player.position + maskDir;
    }
}
Скрипт можно цеплять куда угодно и указать в нем маску и игрока.

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

Скачать скрипты:
Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Тестировалось на: Unity 2018.3.3

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

Офлайн
maribara 7 апреля 2019
Как сделать что-бы было без прозрачности? Вписать вместо
Tags {"Queue" = "Transparent-1" }
альфу?
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика