์กธ์ ์ํ์ ๋ง๋ฌด๋ฆฌํ๋ ์์ฆ์ด๋ผ ๋ฐ๋น ์, ๊ฐ๋ฐ์๋ง ๋ชฐ๋ํ๋ค ๋ณด๋ ๊ธ์ ์ธ ์๊ฐ์ด ์์๋ค์. ๋ง๊ฐ์ด ๋ค๊ฐ์ค๋, ํจ์จ์ ์ด๊ณ ์ข์ ์์ค ์ฝ๋๋ฅผ ์ง๋ ๊ฒ๊ณผ ์๊ฐ ์์ ๋ง๋ฌด๋ฆฌ ํ๋ ๊ฒ ์ฌ์ด์์ ํํ์ ํด์ผ ํ์ต๋๋ค.
๊ทธ๋ฌ๋ค ๋ณด๋, ์ด๊ฒ ์ข์ ๋ฐฉ๋ฒ์ธ๊ฐ๋ฅผ ๊ณ ๋ฏผํ ๊ฒจ๋ฅผ์ด ๋ง์ด ์์ด ํ๋ ์ฝ๋ฉ๋ ์ด๋ ์ ๋ ๋ค์ด๊ฐ ๊ฒ ๊ฐ์ต๋๋ค. ์๊ฐ์ด ๋๋ฉด ์ฐจ์ฐจ ๋ค์ ๊ณ ๋ฏผํด๋ณด๋ฉฐ ๋ฆฌํฉํ ๋ง์ ํด๋ณด๊ณ ์ถ๋ค์.
๊ธ์ ์ ์ด ์ง ์ค๋ ๋์๋ค ๋ณด๋, ์ด๋์๋ถํฐ ๊ธ์ ์จ์ผํ ์ง ๋ชจ๋ฅด๊ฒ ๋๊ตฐ์,,, ๊ทธ๋์ ์ผ๋จ ์ต๊ทผ์ ํ ๊ฒ ์ค ๊ธ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ธ ์ ์๋ ๋ถ๋ถ๋ถํฐ ์จ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
1. ์ฟผํฐ๋ทฐ(isometric view) ์์ ์ ๋ฌธ์ ์
์ด ๊ฒ์์ 3D ๋ก๊ทธ๋ผ์ดํฌ ํต ์ค ์ฌ๋์ ๊ฒ์์ผ๋ก, ์ฟผํฐ๋ทฐ ์์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์์์ ์ด์ง ๋๊ฐ์ ๋ฐฉํฅ์ธ ๋ถ๋ถ์์ ๋ด๋ ค๋ค ๋ณด๋ ์์ ์ ์๋ฏธํ์ง์.
์ฌ์ค, isometric view๋ ๋ง์ด ์ ํํ ๊ฐ๋ ์ด๊ธด ํฉ๋๋ค. isometric view๋ Orthographic ํฌ์๊ณผ ๊ด๋ จ๋ ๋ด์ฉ์ด๋ผ 3D์์๋ ๊ฑฐ์ ์ฐ์ด์ง ์์ง๋ง, ๋์์ด๋๊ฐ ์๋ ์ ํฌ ํ ํํธ์ isometric 2D Sprite๋ฅผ ๊ตฌํ๊ธฐ๊ฐ ์ฝ์ง ์์๊ธฐ์ 3D๋ก ๋ถ๊ฐํผํ๊ฒ ๊ฒฐ์ ๋ ์ผ์ด์ค๊ธด ํฉ๋๋ค.
์์ ๊ฐ์ ํน์ง์ ๊ฐ์ง ์ฟผํฐ๋ทฐ๋ ๊ฒ์ ๋ด์ ํ๊ฒฝ ์ค๋ธ์ ํธ(๊ฑด๋ฌผ, ๋๋ฌด ๋ฑ)๊ฐ ์บ๋ฆญํฐ๋ฅผ ๊ฐ๋ฆด ์ ์๋ค๋ ๋ฌธ์ ์ ์ด ์กด์ฌํฉ๋๋ค.
์ด๋ฌํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก, ์ค๋ธ์ ํธ๊ฐ ์บ๋ฆญํฐ๋ฅผ ๊ฐ๋ฆฌ๋ ๋์์๋ง ํด๋น ์ค๋ธ์ ํธ๋ฅผ ํฌ๋ช ํ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ณดํต ํด๋น ์ค๋ธ์ ํธ์ Material Rendering Mode๋ฅผ Transparent๋ก ์ฒ๋ฆฌํ์ฌ Albedo์ ์ํ๊ฐ์ ์กฐ์ ํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ ์ ์์ต๋๋ค. (์ฐฝ๋ฌธ๊ณผ ๊ฐ์ ํฌ๋ช ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค ๋ ์ ์ฉํ ๋ฐฉ๋ฒ์ด์ฃ .)
ํ์ง๋ง ์ ๊ฒ์์์ ์ด ๋ฐฉ๋ฒ์ ์ ์ฉํ๋ ๊ฒ์๋ ๋ฌด๋ฆฌ๊ฐ ์์์ต๋๋ค.
2. LOD๊ฐ ์กด์ฌํ๋ Material์ ํฌ๋ช ํ ๋ฌธ์
LOD(Level Of Detail)๋ ์นด๋ฉ๋ผ์์ ๊ฑฐ๋ฆฌ์ ๋ฐ๋ผ ํ์ง์ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ๋ ๊ฑธ ๋งํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฐฐํ๊ทธ๋ผ์ด๋์ ๊ฐ์ ๊ฒ์์์ ๋์ 1km์ ๋จ์ด์ ธ ์๋ ์ง์ ์๋ง์ ํด๋ฆฌ๊ณค(Polygon)๋ค์ ์ฌ์ฉํ์ฌ ๊ณ ํ๋ก ํด๋์ ํ์๋ ์์ ๊ฒ๋๋ค. ๋ฉ๋ฆฌ ์์ด์ ์ ์ ๋ณด์ผํ ๋๊น์. ์ ๋ณด์ด๋ ์ง์ ๊น์ง ๋ฉ์ด์ก๋ค๋ฉด ์์ Cullingํ๋ฉด ๋๊ฒ ์ง์.
๊ทธ๋์ ํด๋น ์ค๋ธ์ ํธ์ ๋ํด ๊ฑฐ๋ฆฌ์ ๋ฐ๋ผ ์ฌ์ฉํ ํ์ง๋ค์ ๊ทธ๋ฃน์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ LOD Group์ ๋๋ค.
์์ผ ๊ฑฐ๋ฆฌ์ ๋ฐ๋ผ ๊ธฐ๋ฅ ์ค๋ธ์ ํธ์ ํ์ง์ด ๋ค์ ๋ณํ๋ ๊ฑธ ๋ณผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ์ต์ ํ๋ฅผ ํด์ฃผ๋ ๊ฒ์ด์ฃ . ๋ค๋ง, ์ฌ๋ฌ ๊ฐ์ ๋ฉ์(Mesh)๋ค์ ๊ทธ๋ฃน์ผ๋ก ๊ด๋ฆฌํ๊ธฐ์ ์์์ ์ ์ฉํ ํฌ๋ช ํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํฌ๋ช ํ๊ฐ ๋๊ณค ํ์ต๋๋ค.
์ ๋งํ์ต๋๋ค. ๋ชจ๋ฅด๊ฒ ์ด์ ๊ตฌ๊ธ๋ง๋ ์ด์ฌํ ํด๋ณด๊ณ ํ๋๋ 2์๊ฐ์ด ํ์ฉ ์ง๋ฌ๋๊ตฐ์. ๊ทธ๋ฌ๋ค๊ฐ ๋ฐํ์ ์ค์ Material์ Rendering Mode๋ฅผ ๋ณ๊ฒฝํ๋ ์์ด๋์ด๋ฅผ ๋ฐ๊ฒฌํ ์ ์์์ต๋๋ค.
(์์งํ, Material์ ๋ด๋ถ ํ๋กํผํฐ๊น์ง ๋ค ์ดํด๋ณธ ๊ฒ์ด ์๋์๊ธฐ์ ์ฝ๋์ ์ ํํ ๋์ ์๋ฆฌ๋ ์ค๋ช ํ์ง ๋ชปํฉ๋๋ค..)
โ๏ธ๋ฌธ์ ํด๊ฒฐ ์์ํ๊ธฐ
1. "TransparentObject" ์คํฌ๋ฆฝํธ ์์ฑํ๊ธฐ
์ฐ์ ์๊ณ ๋ฆฌ์ฆ ์์ด๋์ด๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์บ๋ฆญํฐ์ ์นด๋ฉ๋ผ ์ฌ์ด์ ์บ๋ฆญํฐ๋ฅผ ๊ฐ๋ฆฌ๋ ์ค๋ธ์ ํธ๋ฅผ ๊ฒ์ฌํ๋ค.
- ํด๋น ์ค๋ธ์ ํธ์ Material Rendering Mode๋ฅผ "Fade"๋ก ๋ณ๊ฒฝ, Source๋ฅผ "Albedo alpha", Albedo alpha ๊ฐ์ ์ฒ์ฒํ ๋ด๋ฆฐ๋ค. ์ํ ๊ฐ์ ๋ค ๋ด๋ ธ๋ค๋ฉด, ํ์ด๋จธ๋ฅผ ๋์ํ๋ค.
- ์ค๋ธ์ ํธ๊ฐ ํฌ๋ช ํ๊ฐ ์งํ์ด ๋ค ๋์๋๋ฐ๋ ์บ๋ฆญํฐ๋ฅผ ๊ฐ๋ฆฌ๊ณ ์๋ค๋ฉด, ํ์ด๋จธ๋ฅผ ๊ณ์ ์ด๊ธฐํํ๋ค.
- ์๋๋ผ๋ฉด, ์ง์ ํ ์๊ฐ์ด ๋ค ๊ฒฝ๊ณผ๋์์ ๊ฒฝ์ฐ, ๋ค์ Resetํ๋ค.
์ ๊ฐ ๊ตฌ๋งคํ ์์ ๋ค์ ์์ ์ค๋ธ์ ํธ๋ค์๊ฒ MeshRenderer๊ฐ ๋ค ๋ถ์ด ์์ด์, GetComponentsInChildern()์ ์ด์ฉํ์ต๋๋ค. ์์ค์ฝ๋๋ ์๋์ ๋๋ณด๊ธฐ๋ฅผ ๋๋ฅด๋ฉด ์์ต๋๋ค.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TransparentObject : MonoBehaviour
{
public bool IsTransparent { get; private set; } = false;
private MeshRenderer[] renderers;
private WaitForSeconds delay = new WaitForSeconds(0.001f);
private WaitForSeconds resetDelay = new WaitForSeconds(0.005f);
private const float THRESHOLD_ALPHA = 0.25f;
private const float THRESHOLD_MAX_TIMER = 0.5f;
private bool isReseting = false;
private float timer = 0f;
private Coroutine timeCheckCoroutine;
private Coroutine resetCoroutine;
private Coroutine becomeTransparentCoroutine;
void Awake()
{
renderers = GetComponentsInChildren<MeshRenderer>();
}
public void BecomeTransparent()
{
if (IsTransparent)
{
timer = 0f;
return;
}
if (resetCoroutine != null && isReseting)
{
isReseting = false;
IsTransparent = false;
StopCoroutine(resetCoroutine);
}
SetMaterialTransparent();
IsTransparent = true;
becomeTransparentCoroutine = StartCoroutine(BecomeTransparentCoroutine());
}
#region #Run-time ์ค์ RenderingMode ๋ฐ๊พธ๋ ๋ฉ์๋๋ค
/// Runtime ์ค์ RenderingMode๋ฅผ ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋, ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํจ. <summary>
// 0 = Opaque, 1 = Cutout, 2 = Fade, 3 = Transparent
private void SetMaterialRenderingMode(Material material, float mode, int renderQueue)
{
material.SetFloat("_Mode", mode);
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = renderQueue;
}
private void SetMaterialTransparent()
{
for(int i = 0; i< renderers.Length; i++)
{
foreach(Material material in renderers[i].materials)
{
SetMaterialRenderingMode(material, 3f, 3000);
}
}
}
private void SetMaterialOpaque()
{
for (int i = 0; i < renderers.Length; i++)
{
foreach (Material material in renderers[i].materials)
{
SetMaterialRenderingMode(material, 0f, -1);
}
}
}
#endregion
public void ResetOriginalTransparent()
{
SetMaterialOpaque();
resetCoroutine = StartCoroutine(ResetOriginalTransparentCoroutine());
}
private IEnumerator BecomeTransparentCoroutine()
{
while (true)
{
bool isComplete = true;
for(int i =0; i< renderers.Length; i++)
{
if (renderers[i].material.color.a > THRESHOLD_ALPHA)
isComplete = false;
Color color = renderers[i].material.color;
color.a -= Time.deltaTime;
renderers[i].material.color = color;
}
if (isComplete)
{
CheckTimer();
break;
}
yield return delay;
}
}
private IEnumerator ResetOriginalTransparentCoroutine()
{
IsTransparent = false;
while (true)
{
bool isComplete = true;
for (int i = 0; i < renderers.Length; i++)
{
if (renderers[i].material.color.a < 1f)
isComplete = false;
Color color = renderers[i].material.color;
color.a += Time.deltaTime;
renderers[i].material.color = color;
}
if (isComplete)
{
isReseting = false;
break;
}
yield return resetDelay;
}
}
public void CheckTimer()
{
if (timeCheckCoroutine != null)
StopCoroutine(timeCheckCoroutine);
timeCheckCoroutine = StartCoroutine(CheckTimerCouroutine());
}
private IEnumerator CheckTimerCouroutine()
{
timer = 0f;
while (true)
{
timer += Time.deltaTime;
if(timer > THRESHOLD_MAX_TIMER)
{
isReseting = true;
ResetOriginalTransparent();
break;
}
yield return null;
}
}
}
์ด๋ ๊ฒ ์์ค์ฝ๋๋ฅผ ์์ฑํ๊ณ , ํฌ๋ช ํ ์ฒ๋ฆฌ๊ฐ ๋๊ธธ ์ํ๋ ์ค๋ธ์ ํธ์ ๋ถ์ด๊ณ , Layer๋ฅผ EnvironmentObject๋ก ๋ณ๊ฒฝํ์ฌ ์ค๋๋ค.
2. ์นด๋ฉ๋ผ์์ ํ๋ ์ด์ด ์บ๋ฆญํฐ๋ฅผ ๊ฐ๋ฆฌ๋ ์ค๋ธ์ ํธ ํ์งํ๊ธฐ
์ค๋ธ์ ํธ๊ฐ ๋ช ๊ฐ ๊ฒน์ณ์ ๊ฐ๋ฆด ์๋ ์์ผ๋ฏ๋ก, RaycastAll()์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ํ์งํ๋๋ก ํฉ๋๋ค.
// Camera script
void LateUpdate()
{
// Player๋ ์ฑ๊ธํค์ด๊ธฐ์ ์ ์ญ์ ์ผ๋ก ์ ๊ทผํ ์ ์์ต๋๋ค.
Vector3 direction = (Player.Instance.transform.position - transform.position).normalized;
RaycastHit[] hits = Physics.RaycastAll(transform.position, direction, Mathf.Infinity,
1 << LayerMask.NameToLayer("EnvironmentObject"));
for (int i = 0; i < hits.Length; i++)
{
TransparentObject[] obj = hits[i].transform.GetComponentsInChildren<TransparentObject>();
for (int j = 0; j < obj.Length; j++)
{
obj[j]?.BecomeTransparent();
}
}
}
์ฌ๊ธฐ์๋ GetComponentsInChildren()์ ์ด์ฉํ์ฌ TransparentObject ์คํฌ๋ฆฝํธ๋ฅผ ๊ฐ์ ธ์ค๋ ์ด์ ๋ ๋น ์ค๋ธ์ ํธ์ ์์์ผ๋ก ๋ฌถ์ด์ ์ค๋ธ์ ํธ๋ค์ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์์์ ๋ณด์ฌ๋๋ฆฐ ๊ธฐ๋ฅ ์ค๋ธ์ ํธ๋ ddi_pillar_01์ด๋ฉฐ, ์ด๊ฒ์ Obejcts๋ผ๋ ๋น ์ค๋ธ์ ํธ์ ์์์์ ๊ด๋ฆฌ๋๊ณ ์์์ ๋ณผ ์ ์์ต๋๋ค. ์๋ฌดํผ, ์ด๋ ๊ฒ ํ๊ณ ๋๋ฉด ํฌ๋ช ํ๊ฐ ์ ์ฒ๋ฆฌ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๊ฒฐ๊ณผ
์ด์ ๋ฒฝ์ด๋ ์ค๋ธ์ ํธ๊ฐ ์บ๋ฆญํฐ๋ฅผ ๊ฐ๋ ค์ ๋ชฌ์คํฐ์ ์ธ์ฐ๋๋ฐ ๋ถํธํจ์ด ์์ด์ก์ต๋๋ค.