

Mesh Trail.cs를 만들어 Mesh를 갖고있는 캐릭터에 붙여준다,
using System.Collections;
using UnityEngine;
public class MeshTrailTut : MonoBehaviour
{
public float activeTime = 2f;
private bool isTrailActive;
//메쉬 지연
public float meshRefreshRate = 0.1f;
//캐릭터가 얼마나 많은 스킨과 메쉬 렌더링을 갖고있는가
private SkinnedMeshRenderer[] skinnedMeshRenderers;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && !isTrailActive)
{
isTrailActive = true;
StartCoroutine(ActivateTrail(activeTime));
}
}
private IEnumerator ActivateTrail(float timeActive)
{
//대부분의 잔상효과는 이곳에서 발생
while (timeActive > 0)
{
timeActive -= meshRefreshRate;
if (skinnedMeshRenderers == null)
{
skinnedMeshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>(); //Getcomponet 's'
}
//각 스킨과 메쉬 반복
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
GameObject gObj = new GameObject();
gObj.AddComponent<MeshRenderer>();
gObj.AddComponent<MeshFilter>();
}
yield return new WaitForSeconds(meshRefreshRate);
}
//0 이되면 더이상 트레일이 활성화되지않음
isTrailActive = false;
}
}

if(GetKeyDown (KeyCode.Space)) 를 누르면 게임오브젝트가 생성되고, 그 안에는MeshRenderer와 MeshFilter가 존재하게된다. 다시 스크립트로 돌아와


메쉬렌더러와 메쉬필터를 할당해주고 BakeMesh해준다. 어디에있는지 기록한다는 듯.

이제 SpaceBar를 누르면 머터리얼이 없는 객체를 생성합니다.이제 이 오브젝트가 플레이어를 따라오게 해야합니다.
다음과같이 스크립트를 작성합니다.
public class MeshTrailTut : MonoBehaviour
{
...기존 코드
public Transform positionToSpawn
private IEnumrator ActivateTrail(float time Active)
{
...
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
GameObject gObj = new GameObject();
//따라오게하기
gObj.transform.SetPositionAndRotation(positionToSpawn.position, positionToSpawn.rotation);
...기존코드
}
}
gObj.transform.SetPositionAndRotation(positionToSpawn.position, positionToSpawn.rotation);를 추가해준다.

그리고 인스펙터창에서 Transform으로 열린 빈 곳에 플레이어를 드래그하여 넣는다.
이제 우리가 해야할 일은 핑크색 머터리얼(비어있는)에 머터리얼을 할당하는 것입니다. 머터리얼을 할당하기위해 셰이더가 필요하므로 셰이더 변수 참조를위한 코드를 작성합니다.


인스펙터창에서 구분하기 쉽게 헤더를 작성했습니다.
MeshRenderer의 Material은 헤더에서 작성한 Material과 같다 선언해주고,
무한으로 생성되므로 몇초뒤에 파괴시키기위해 Destroy를 적었습니다.
이후 Material에 머터리얼을 드래그하여 넣어주면됩니다.

셰이더 적용

ShaderGraph에서 Unit Shader Graph 생성

여기서 이제 프레넬 효과를 줄것입니다.
프네넬 효과 : https://m.blog.naver.com/fscreen/50169708619
이제 연결하는것은 아래에 유튜브를 참고하자.
https://www.youtube.com/watch?v=7vvycc2iX6E
8:30초 ~ 9분 40초
쉐이더를 다 만들었다면 저장하고 만든 쉐이더에 머터리얼을 생성해준다,.

머터리얼을 생성했다면 원하는 Color로 변경해주고 FresnalPower와 Alpha값을 조절해준다.
그리고 셰이더 Mat에 다시 연결.



이제 여기까지 재질 업그레이드가 완료되었습니다. 이제 Mesh가 Fade Out 될수있도록 설정합시다!
스크립트를 통해 셰이더 속성을 건드리겠습니다.
using System;
using System.Collections;
using UnityEngine;
public class MeshTrailTut : MonoBehaviour
{
public float activeTime = 2f;
private bool isTrailActive;
[Header("메쉬")]
public float meshRefreshRate = 0.1f;
public float meshDestroyDelay = 3f;
public Transform positionToSpawn;
[Header("셰이더")]
public Material mat;
public string shaderVarRef;
public float shaderVarRate = 0.1f;
public float shaderVarRefreshRate = 0.05f;
//캐릭터가 얼마나 많은 스킨과 메쉬 렌더링을 갖고있는가
private SkinnedMeshRenderer[] skinnedMeshRenderers;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && !isTrailActive)
{
isTrailActive = true;
StartCoroutine(ActivateTrail(activeTime));
}
}
private IEnumerator ActivateTrail(float timeActive)
{
//대부분의 잔상효과는 이곳에서 발생
while (timeActive > 0)
{
timeActive -= meshRefreshRate;
if (skinnedMeshRenderers == null)
{
skinnedMeshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>(); //Getcomponet 's'
}
//각 스킨과 메쉬 반복
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
GameObject gObj = new GameObject();
gObj.transform.SetPositionAndRotation(positionToSpawn.position, positionToSpawn.rotation);
MeshRenderer mr = gObj.AddComponent<MeshRenderer>();
MeshFilter mf = gObj.AddComponent<MeshFilter>();
//각 정점이 어디에있는지 기록한다.
Mesh mesh = new Mesh();
skinnedMeshRenderers[i].BakeMesh(mesh);
mf.mesh = mesh;
mr.material = mat; //메쉬런더러는 머터리얼과 같다 선언
StartCoroutine(AnimateMaterialFloat(mr.material, 0, shaderVarRate, shaderVarRefreshRate));
Destroy(gObj, meshDestroyDelay);
}
yield return new WaitForSeconds(meshRefreshRate);
}
//0 이되면 더이상 트레일이 활성화되지않음
isTrailActive = false;
}
//페이드아웃을 위해 머터리얼의 목표, 속도, 새로고침 빈도 매개변수 설정
private IEnumerator AnimateMaterialFloat(Material mat, float goal, float rate, float refreshRate)
{
//애니메이션 부동 소수점에 액세스
float valueToAnimate = mat.GetFloat(shaderVarRef);
while (valueToAnimate > goal)
{
valueToAnimate -= rate;
mat.SetFloat(shaderVarRef, valueToAnimate); //애니메이션 값 전달
yield return new WaitForSeconds(refreshRate);
}
}
}

알파값의 레퍼런스 이름을 ShaderVarRef에 넣으면 완료. 잔상효과가 구현되었습니다.
이후 성능저하를 하고있는 부분을 수정하겠습니다.
if (skinnedMeshRenderers == null)
{
skinnedMeshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
}
를 삭제하고
private void Awake()
{
skinnedMeshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
}
Awake에다 1회만 선언해줍니다.
그리고 for문에 있던
mr.material = mat;를
mr.material = new Material(mat);
새로운 재질 인스턴스를 사용해 복제 매쉬 생성하는 방식으로 바꿨습니다.
이제 끝인줄 알았는데

그림자는 늦게 사라지더라구요. 잔상효과에 그림자는 필요없으니까 지워버리겠습니다.
MeshRenderer에서 제공하는 기능을 이용하겠습니다.
//...
mr.material = new Material(mat);
mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; //그림자 제거
StartCoroutine(AnimateMaterialFloat(mr.material, 0, shaderVarRate, shaderVarRefreshRate));
//...
MaterialRenderer의 shadowCastringMode를 Off합니다.

완벽한 잔상효과 완료.
'Unity Engine > Unity 3D.' 카테고리의 다른 글
| [유니티 3D] 메기도 구현 (무한히 튕기는 광선) (1) | 2023.10.21 |
|---|---|
| 일정한 간격으로 오브젝트 생성 (0) | 2023.10.20 |
| 콤보어택 정리 전 (0) | 2023.10.19 |
| [유니티 3D]몬스터가 플레이어를 추적하고 공격하게 만들어보자 (1) | 2023.10.09 |
| [유니티 3D] 팩토리 패턴으로 몬스터와 보스 소환 해보기 (1) | 2023.10.08 |