유닛으로 카메라와 피사체 사이의 차폐물을 숨기는 스크립트를 만들어 봤어요.

13691 단어 Unity
만약 3D 게임을 했다면 카메라와 피사체 사이의 벽에서 앞을 볼 수 없었을 것이다.
이러면 어떻게 움직이는지도 몰라요.

카메라와 피사체 사이에서 Update를 사용하여 Ray를 건너뛸 때마다 객체 레이어 객체의 렌더기가 유효하지 않게 처리됩니다.

아래 스크립트 구성 요소를 사용하면 위gif처럼 벽을 잠시 숨기고 벽의 깊은 곳을 표시할 수 있습니다.
더 좋은 방법이 있지만 나 같은 3D 초보자도 쉽게 쓸 수 있는 방법으로 Qita에 미리 적어두고 싶다.

동작 확인 환경

  • windows7 64bit (Home Premium)
  • Unity 2018.1.0f2 Personal (64bit)
  • 소스 코드


    이 소스 코드github의 gist도 공개됐다.
    SCCameraCoverTransparent.cs
    /// License
    /// 
    /// NYSL Version 0.9982
    /// 
    /// A. 本ソフトウェアは Everyone'sWare です。このソフトを手にした一人一人が、
    ///    ご自分の作ったものを扱うのと同じように、自由に利用することが出来ます。
    /// 
    ///   A-1. フリーウェアです。作者からは使用料等を要求しません。
    ///   A-2. 有料無料や媒体の如何を問わず、自由に転載・再配布できます。
    ///   A-3. いかなる種類の 改変・他プログラムでの利用 を行っても構いません。
    ///   A-4. 変更したものや部分的に使用したものは、あなたのものになります。
    ///        公開する場合は、あなたの名前の下で行って下さい。
    /// 
    /// B. このソフトを利用することによって生じた損害等について、作者は
    ///    責任を負わないものとします。各自の責任においてご利用下さい。
    /// 
    /// C. 著作者人格権は SakuraCrowd に帰属します。著作権は放棄します。
    /// 
    /// D. 以上の3項は、ソース・実行バイナリの双方に適用されます。
    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Linq;  // Except
    
    /// <summary>
    /// カメラと対象との間の遮蔽物(Cover)を透明化します。
    /// カメラに付加してください。
    /// 透明にする遮蔽物は Renderer コンポーネントを付加している必要があります。
    /// </summary>
    public class SCCameraCoverTransparent : MonoBehaviour {
    
    
        /// <summary>
        /// 被写体を指定してください。
        /// </summary>
        [SerializeField]
        private Transform subject_;
    
        /// <summary>
        /// 遮蔽物のレイヤー名のリスト。
        /// </summary>
        [SerializeField]
        private List<string> coverLayerNameList_;
    
        /// <summary>
        /// 遮蔽物とするレイヤーマスク。
        /// </summary>
        private int layerMask_;
    
        /// <summary>
        /// 今回の Update で検出された遮蔽物の Renderer コンポーネント。
        /// </summary>
        public List<Renderer> rendererHitsList_ = new List<Renderer>();
    
        /// <summary>
        /// 前回の Update で検出された遮蔽物の Renderer コンポーネント。
        /// 今回の Update で該当しない場合は、遮蔽物ではなくなったので Renderer コンポーネントを有効にする。
        /// </summary>
        public Renderer[] rendererHitsPrevs_;
    
    
        // Use this for initialization
        void Start () {
            // 遮蔽物のレイヤーマスクを、レイヤー名のリストから合成する。
            layerMask_ = 0;
            foreach(string _layerName in coverLayerNameList_)
            {
                layerMask_ |= 1 << LayerMask.NameToLayer(_layerName);
            }
    
        }
    
    
        // Update is called once per frame
        void Update () {
            // カメラと被写体を結ぶ ray を作成
            Vector3 _difference = (subject_.transform.position - this.transform.position);
            Vector3 _direction = _difference.normalized;
            Ray _ray = new Ray(this.transform.position, _direction);
    
            // 前回の結果を退避してから、Raycast して今回の遮蔽物のリストを取得する
            RaycastHit[] _hits = Physics.RaycastAll(_ray, _difference.magnitude, layerMask_);
    
    
            rendererHitsPrevs_ = rendererHitsList_.ToArray();
            rendererHitsList_.Clear();
            // 遮蔽物は一時的にすべて描画機能を無効にする。
            foreach (RaycastHit _hit in _hits)
            {
                // 遮蔽物が被写体の場合は例外とする
                if (_hit.collider.gameObject == subject_)
                {
                    continue;
                }
    
                // 遮蔽物の Renderer コンポーネントを無効にする
                Renderer _renderer = _hit.collider.gameObject.GetComponent<Renderer>();
                if (_renderer != null)
                {
                    rendererHitsList_.Add(_renderer);
                    _renderer.enabled = false;
                }
            }
    
            // 前回まで対象で、今回対象でなくなったものは、表示を元に戻す。
            foreach (Renderer _renderer in rendererHitsPrevs_.Except<Renderer>(rendererHitsList_))
            {
                // 遮蔽物でなくなった Renderer コンポーネントを有効にする
                if (_renderer != null)
                {
                    _renderer.enabled = true;
                }
            }
    
        }
    }
    
    주요 처리는 업데이트입니다. 매번 다음과 같은 일을 반복합니다.
  • 레이는 자신과 피사체 사이를 비행하여 그 사이의 대상을 얻는다(Collider 필요).
  • 가져온 객체에서 지정된 레이어의 객체를 멤버의 마스크 목록에 마스크로 추가합니다.
  • 차폐물 목록을 업데이트하기 전에 복사하여 이전 차폐물 목록을 제작한다.(List의 대입이면 참조 교부이기 때문에 정렬 교부)
  • 렌더러 어셈블리가 가림막 객체에서 제거되면 비활성화됩니다.
  • 이전 마스킹 목록에서 현재 마스킹 목록에 없는 객체, 더 이상 마스크가 아닌 객체에서 렌더링 어셈블리를 다시 활성화합니다.
  • 얼렁뚱땅 말하면, 방해가 될 때 잠시 숨기고, 장애가 아니라면 다시 표시하는 느낌일 뿐이다.

    사용법


    Camera에 위의 스크립트 구성 요소를 추가합니다.

    다음 항목을 설정합니다.
  • Subject_ : 피사체 (조작된 문자 등) 의 Transform을 설정하십시오.
  • CoverLayerNameList_ : 목록에 게임 대상이 속하는 숨겨진 층의 이름을 추가하십시오.
  • 게임 대상과 피사체 사이의 차폐물이 잠시 숨겨집니다. 예를 들어 이 구성 요소를 추가한 카메라입니다.

    주의점


    땅이 다 사라졌어!


    예를 들어 플레인을 전체적인 지면으로 하고 지형이 융기되면 움푹 패인 구덩이에 들어갈 때 지면이 모두 숨겨진다.

    대책으로 CoverLayer NameList에 등록된 도면층 이름과 일치하지 않는 도면층입니다.

    보이기 싫은 벽이 나와!


    밖으로 떨어지지 않기 위해 보이지 않는 벽을 만드는 건 좋은 일이라고 생각해요.아마
    이 스크립트 구성 요소는 보이지 않으려는 벽이라도 차폐물이 아니기 때문에 표시할 수 있을 정도로 복원됩니다.

    대책으로 아까와 마찬가지로 CoverLayersNameList입니다.변경합니다.

    겸사겸사 말씀드리겠습니다.


    이 스크립트는 유닛룸 씨가 진행한 이벤트 "ProBuilder 게임 잼"에 참가했을 때 만든 것이다.
    이때 참가한 작품인'마을 속의 p.b.j.a.m'는 아래 링크부터 놀 수 있습니다.
    화살표 키와 스페이스 바만 조작되며 게임 시간은 2~5분입니다.
    가능하면 놀아주세요.
    무료 게임 투고 사이트 유닛룸

    해바라기 기능 사용 가능...


    2018/07/25 추기.유니티 카메라는 해바라기 교육 기능이 있어서 이걸로 할 수 있을 것 같아요.
    부탄가 교육 - Unity 브로셔

    사이트 축소판 그림

  • Unity 플레이어 객체가 다른 객체에 숨겨져 있는 경우에도 볼 수 있습니다. - LLC DigiFie
  • 이벤트 "ProBuilder 게임 잼" | 무료 게임 투고 사이트 unityroom
  • 무료 게임 투고 사이트 유닛룸
  • 부탄가 교육 - Unity 브로셔
  • 좋은 웹페이지 즐겨찾기