일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Specular
- URP
- Three(Two) Tone Shading
- 게임 수학
- AppSW
- 개인 바이트
- 3d
- URP로 변경
- ColorGradingLutPass
- Rim Light
- working set
- Windows Build
- 프로그래밍 기초
- C언어
- OculusMotionVectorPass
- Cell Shader
- 벡터
- Toon Shader
- ASW(Application SpaceWarp)
- Cell Look
- Cartoon Rendering
- VR
- Virtual Byte
- 가상 바이트
- 메모리 누수
- 작업 집합
- Private Bytes
- Today
- Total
WinCNT
UniTask를 이용한 스크립트로 포스트 프로세싱이 아닌 Fade In, Fade Out를 구현해보기 본문
UniTask를 이용한 스크립트로 포스트 프로세싱이 아닌 Fade In, Fade Out를 구현해보기
WinCNT_SSS 2023. 12. 15. 11:45서론
이번에는 UniTask를 이용한 스크립트로 Fade In, Fade Out를 구현해보려고 한다
물론 딱히 UniTask가 아니라 Coroutine도 사용할 수 있지만 모처럼 UniTask를 인스톨했으니 겸사겸사 사용해봤다
Fade In, Fade Out의 구현에 대해
Fade In, Fade Out은 포스트 프로세싱을 이용한 구현이 일반적일 것이다
하지만 그 방법만 있는 것이 아니다!!
다른 방법이 있는데 바로 카메라의 거의 바로 앞에 Quad를 두고, 그 Qaud만 Fade In, Fade Out시키는 방법(…)이다
원리는 매우 간단하다
이 방법은 구현이 간단하고 좀 더 직관적으로 Fade In, Fade Out를 사용할 수 있다는 메리트가 있다
하지만 화면의 비율이나 카메라의 FOV 등에 따라서는 커버가 안 되는 부분이 생길 수 있다는 디메리트가 있다
성능적인 관점에서는 글쎄?
처음에는 Quad를 이용한 것이 더 좋을 것 같았지만 잘 생각해보니 그다지 차이가 안 날 거 같기도 하고…
이 부분은 기기에 따라 차이나 나기도 할 테니 따로 검증하진 않으려고 한다
우선은 셰이더의 샘플 코드부터
다음은 이번에 사용한 셰이더의 샘플 코드이다
App/ScreenFade
Shader "App/ScreenFade"
{
Properties
{
_Color("Color", Color) = (0,0,0,0)
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha
ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _Color;
CBUFFER_END
struct appdata_img
{
float4 vertex : POSITION;
half2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f_img
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
v2f_img vert_img( appdata_img v )
{
v2f_img o = (v2f_img)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.pos = TransformObjectToHClip(v.vertex.xyz);
o.uv = v.texcoord;
return o;
}
half4 frag (v2f_img i) : SV_Target
{
return _Color;
}
ENDHLSL
}
}
}
단순히 프로퍼티의 색을 출력하는 반투명 셰이더이다
이번에는 프로퍼티의 설정을 스크립트에서 할 예정이라 이 정도면 충분하다
버텍스 셰이더는 UnityCG.cginc의 vert_img를 가져왔다
Fade In, Fade Out를 실행하는 스크립트
ScreenFadeView.cs
using System.Collections;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace App.Common.Views
{
public class ScreenFadeView : MonoBehaviour
{
[SerializeField] private float _fadeTime = 1.0f;
[SerializeField] private Color _fadeColor = new Color(0.01f, 0.01f, 0.01f, 1.0f);
[SerializeField] private int _renderQueue = 3500;
private MeshRenderer _fadeRenderer;
private MeshFilter _fadeMesh;
private Material _fadeMaterial = null;
private bool _isFading = false;
private float _currentAlpha;
void Start()
{
// Fade용 머티리얼 작성(셰이더는 별도 기재)
_fadeMaterial = new Material(Shader.Find("App/ScreenFade"));
_fadeMesh = gameObject.AddComponent<MeshFilter>();
_fadeRenderer = gameObject.AddComponent<MeshRenderer>();
_fadeRenderer.material = _fadeMaterial;
// 카메라를 덮는 Fade용 Mesh를 작성
var mesh = new Mesh();
_fadeMesh.mesh = mesh;
Vector3[] vertices = new Vector3[4];
float width = 2f;
float height = 2f;
float depth = 1f;
// 버텍스
vertices[0] = new Vector3(-width, -height, depth);
vertices[1] = new Vector3(width, -height, depth);
vertices[2] = new Vector3(-width, height, depth);
vertices[3] = new Vector3(width, height, depth);
mesh.vertices = vertices;
// 인덱스
int[] indices = new int[6];
indices[0] = 0; indices[1] = 2; indices[2] = 1;
indices[3] = 2; indices[4] = 3; indices[5] = 1;
mesh.triangles = indices;
// 노멀
Vector3[] normals = new Vector3[4];
normals[0] = -Vector3.forward;
normals[1] = -Vector3.forward;
normals[2] = -Vector3.forward;
normals[3] = -Vector3.forward;
mesh.normals = normals;
// UV
Vector2[] uv = new Vector2[4];
uv[0] = new Vector2(0, 0);
uv[1] = new Vector2(1, 0);
uv[2] = new Vector2(0, 1);
uv[3] = new Vector2(1, 1);
mesh.uv = uv;
// Fade 알파
_currentAlpha = 0.0f;
}
private async UniTask FadeInAsync()
{
await Fade(1f, 0f);
}
public void FadeIn()
{
FadeInAsync().Forget();
}
private async UniTask FadeOutAsync()
{
await Fade(0f, 1f);
}
public void FadeOut()
{
FadeOutAsync().Forget();
}
/// <summary>
/// 머티리얼의 알파를 조정해서 Fade시키는 함수
/// 1.0 ~ 0.0으로 설정하면 Fade out
/// 0.0 ~ 1.0으로 설정하면 Fade in
/// </summary>
private async UniTask Fade(float startAlpha, float endAlpha)
{
var elapsedTime = 0.0f;
while (elapsedTime < _fadeTime)
{
elapsedTime += Time.deltaTime;
_currentAlpha = Mathf.Lerp(startAlpha, endAlpha, Mathf.Clamp01(elapsedTime / _fadeTime));
SetMaterial();
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
}
_currentAlpha = endAlpha;
SetMaterial();
}
/// <summary>
/// 머티리얼의 알파 값을 조정해서 Fade를 실시
/// </summary>
private void SetMaterial()
{
Color color = _fadeColor;
color.a = _currentAlpha;
_isFading = color.a > 0;
if (_fadeMaterial != null)
{
_fadeMaterial.color = color;
_fadeMaterial.renderQueue = _renderQueue;
_fadeRenderer.material = _fadeMaterial;
_fadeRenderer.enabled = _isFading;
}
}
}
}
이번의 주연인 스크립트
요는 쿼드를 만들고, UniTask를 이용해 쿼드의 알파 값을 컨드롤하는 스크립트다
결과
카메라나 카메라의 자식 오브젝트에 위의 스크립트를 붙여주면 준비 OK!
그리고 적당한 실행용 스크립트로 필요할 때 ScreenFadeView의 메소드를 호출하면 된다
아래는 간단한 샘플 코드
ScreenFadeController.cs
using App.Common.Views;
using UnityEngine;
public class ScreenFadeController : MonoBehaviour
{
public ScreenFadeView screenFadeView;
// Start is called before the first frame update
void Start()
{
screenFadeView.FadeIn();
}
}
이건 샘플 코드의 실행 예제이다
마무리
URP 14 이전에는 포스트 프로세싱 구현이 귀찮복잡했기 때문에 이 방법으로 구현했던 것 같다
현재 프로젝트는 URP 14이고 이 버전부터는 포스트 프로세싱 구현이 간단해졌다고 하니 슬슬 써도 좋을지도 모르겠다
'Unity > URP or Shader 관련' 카테고리의 다른 글
Unity의 Depth Texture에는 실제로 어떤 오브젝트가 기록되는 걸까?(feat. SSAO) (0) | 2024.01.22 |
---|---|
MatCap 셰이더를 만들어보자 (0) | 2024.01.15 |
URP에서 Cutout(Alpha Test) 구현해보기(feat. Alpha to Coverage) (0) | 2023.12.06 |
커스텀 셰이더의 머티리얼을 Bakery(라이트 맵 생성 에섯)으로 Bake하기(feat. Meta Pass) (0) | 2023.10.12 |
URP에서 SpriteRenderer는 SRP Batcher가 작동하지 않았던 이유 조사 (0) | 2023.09.28 |