Vertex shader를 활용한 mesh animation 구현
Shader "URPTraining/Vertex_Test_shader"
{
Properties
{
_Texture2D("Texture2D", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderPipeline"="UniversalPipeline"
"RenderType"="Opaque"
"Queue"="Geometry"
}
Pass
{
Name "Universal Forward"
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma prefer_hlslcc gles
#pragma exclude_renderers d3d11_9x
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct VertexOutput
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _Texture2D_ST;
Texture2D _Texture2D;
SamplerState sampler_Texture2D;
VertexOutput vert(VertexInput v)
{
VertexOutput o;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
/*
인덱스 버퍼에서 가져온 버텍스 포지션을
TransformObjectToHClip 함수를 이용해 로컬공간에서 *클립공간으로 변환하는 뜻이다.
##
*클립공간은 3D공간을 2D로 투영하기 전 중단 단계이며
카메라의 *뷰 프리스텀에 맞게 조정된 공간이다.
클립공간은 레스터라이제이션 과정에 앞서 위치하고 있는데 다음과 같은 역할을 해준다
1. 3D 객체의 좌표를 카메라 관점의 좌표로 조정해준다. (이 때 뷰변환과 투영변환을 통해 이루어진다)
2. 이 과정에서 뷰 프리스텀내에 있는 객체만 렌더링하기 위해서 클리핑이 수행된다.
*뷰 프리스텀이란 카메라가 볼 수 있는 공간을 나타내는 피라미드 형태의 구조이며
Fov(Field of View)에 따라 넓어지는 모양을 가르킨다. 즉 렌더링해야 할 3D공간을 정의한다.
*/
//o.vertex.y += v.vertex.x;
//ㄴ 이녀석은 그냥 무지성으로 Y에 X를 더할랭 ㅋㅋ 하는거라 로컬 기준으로 대각선의 모습을 보일 것이다
half3 positionWS = TransformObjectToWorld(v.vertex.xyz);
//인덱스 버퍼에서 버텍스 포지션을 가져와 월드공간으로 변환하겠다는 소리.
// 좌표를 3개 쓰니까 당연히 float 혹은 half를 이용.
o.vertex.y += positionWS.x;
// 인덱스 버퍼에 있는 로컬공간 Y에 월드로 변환한 X를 더하며 대입하겠다는 소리다.
// 유니티에서는 Y는 위, X는 옆이니까 위에 옆값을 더한다는 소리니 렌더링된 오브젝트는 대각선의 모습을 보일 것이다.
o.uv = v.uv.xy * _Texture2D_ST.xy + _Texture2D_ST.zw;
return o;
}
half4 frag(VertexOutput i) : SV_Target
{
float4 TEX01 = _Texture2D.Sample(sampler_Texture2D, i.uv);
float4 color = TEX01;
return color;
}
ENDHLSL
}
}
}
여기서 더 심도있게 넘어가보자. 사인을 써보자!
아까 o.vertex.y += positionWS.x; 이 부분을 sin으로 감싸줘보자
o.vertex.y += sin(positionWS.x);
/*
해석해보자면 인덱스 버퍼에 있는 로컬공간 Y에 X축으로 움직이는 sin을 더해서 대입한다는 얘기다.
얘는 옆으로 파도치는 모습이고 월드를 대입했기 때문에 월드 포지션을 움직이면 따라서 같이 움직일 것이다.
*/
오 근데 자동으로 움직이고 싶은데.. 그러먼 어떡하지?
당연히 _Time을 사용하면 된다!
일단은 월드로 움직이긴 싫으니까 월드에서 다시 로컬로 사용하겠다고 바꾼 뒤에 적용해보자.
o.vertex.y += sin(v.vertex.x + v.vertex.y + v.vertex.z + _Time.y);
// 인덱스 버퍼에서 가져온 Y(위) 포지션에 사인에 타임으로 움직이는 로컬 XYZ을 고대로 넣어버린다는 뜻
참고로 y는 x보다 빠르게 움직인다는 뜻이다 (1/20 , 1/8 , 1/4 ,1) 이였나 가물가물한데 전에 타임에 적어둔게 있을것임
하여튼 큰 의미는 아님 속도를 더 빠르게하려면 프로퍼티스로 빼서 float으로 지정하고 임의대로 곱하고 움직이게끔 하면 되는 문제.
자 sin같이 파형을 수식으로 구할 수도 있지만 우리가 전에 사용했던 방법, 그러니까 FlowMap 같은 것으로도 제어할 수 있다.
물론 이 경우엔 Tex2Dlod 함수를 사용해야해서 샘플러를 따로 정의해주어야만 한다.
Tex2Dlod 함수는 컴퓨터 그래픽스에서 텍스처(이미지)를 다룰 때 사용하는 특별한 방법인데
이 함수의 목적은 텍스처의 다양한 '해상도' 버전 중에서 원하는 하나를 선택해서 사용하는 것이다.
LOD: 'Level of Detail'의 약자로, 간단히 말해 '해상도 수준'을 의미합니다.
하나의 텍스처에는 여러 해상도의 버전이 있을 수 있습니다.
가까이 있는 객체에는 고해상도 텍스처를, 멀리 있는 객체에는 저해상도 텍스처를 사용하는 식입니다.
'유니티 > Shader Study' 카테고리의 다른 글
유니티에서 HLSL으로 Voronoi custom 을 만들어 유용하게 쓰는 방법 (0) | 2024.01.21 |
---|---|
URP Shader Study #12 - 카메라 벡터를 활용한 rim light의 적용 (0) | 2023.12.13 |
URP Shader Study #10 - Flow map (0) | 2023.12.04 |
URP Shader Study #9 - UV 정보를 픽셀 셰이더에 출력, Texture Splatting (0) | 2023.12.03 |
URP Shader Study #8 - Alpha To Coverage (1) | 2023.12.02 |