# 1-4 [투영 변환, 예제]

Ricon·2024년 8월 6일

URP Shader Basic

목록 보기
4/17

본 게시물은 Unity Korea 채널의 URP Shader Training 시리즈와 강의에 사용된 도큐먼트를 공부하며 정리한 게시물입니다.

강의 링크
도큐먼트 링크


투영 변환 [Transform Projection]

투영 변환(Transform Projection)은 원근법을 구현하기 위해, 카메라 공간에서 정의된 절두체를 축에 나란한 직육면체 볼륨으로 변경하여 카메라 공간의 모든 물체를 3차원 클립 공간으로 변환하는 것.

// Transform to homogenous clip space
// 뷰 공간에서 동차 클립 공간으로 변환하기 위한 Projection Matrix 반환
float4x4 GetViewHClipMatrix()
{
	//UNITY_MATRIX_P는 Unity에서 미리 정의된 매크로 -> Projection Matrix를 나타냄
	return UNITY_MATRIX_P;
}

// Transform position from view space to homogenous space
// 뷰 공간(View Space)에서 동차 클립 공간(Homogenous Clip)로 위치 변환
float4 TransformWViewToHClip(float3 positionVS)
{
	//입력된 위치를 w성분이 1.0인 4차원 벡터로 변환
    float4 positionVS4D = float4(positionVS, 1.0);
    
    // Projection Matrix을 사용하여 View Space의 위치를 동차 클립 공간의 위치로 변환
	return mul(GetViewHClipMatrix(), positionVS4D);
} 

원근 처리를 위해 3차원 공간을 직육면체 볼륨으로 물체들을 변환시키면서 카메라 공간 밖의 Polygon들을 잘라냄(Cliping)

위 코드를 간단하게 정리하면 아래와 같음

// Transform position from object space to homogenous space
float4 TransformObjectToHClip(float3 positionOS)
{
	//More efficient than computing M*VP matrix product
	return mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)));
}

위 내용을 풀어서 Vertex Stage에서 계산된 내용을 살펴보면 아래와 같음

VertexOutput vert(VertexInput v)
//VertexInput : Vertex Buffer에서 읽어온 정보 v를 계산에 사용함.
{
	VertexOutput o;
    //Vertex Stage에서 계산한 결과는 o.를 붙여 보간기를 통해 Pixel Shader로 전달함.
    o.vertex =  TransformObjectToHClip(v.vertex.xyz);
    //Vertex Buffer에서 읽어온 값을 함수에 넣어 계산한 다음, o.vertex를 통해 Pixel Shader로 전달
    return o;
}

Fragment Function(Pixel Shader Stage)

Pixel로 배열된 Object의 최종 컬러값을 계산하는 단계

half4 frag(VertexOutput i) : SV_Target
// SV_Target -> 이 함수의 반환값은 렌더 타겟에 쓰이는 색상 테이터임을 나타냄. 
{
	return half4(_TintColor);
}

예제 실습

Properties에 Range 항목을 추가하고, 색 밝기/변경으로 슬라이드로 조절하기

// Shader 시작. 셰이더의 폴더와 이름을 여기서 결정합니다.
Shader "URPTraining/02_Example01"
{
	Properties
	{
		// Properties Block : 셰이더에서 사용할 변수를 선언하고 이를 material inspector에 노출시킵니다
		// Color 지정하는 변수를 선언, 변수 타입은 Color이며 기본값은 (1, 1, 1, 1)
		_TintColor("Tint Color", Color) = (1, 1, 1, 1)

		// 색상의 세기를 최소 0에서 최대 1로 조절하는 변수, 기본값 0.5
		_Intensity("Range Sample", Range(0, 1)) = 0.5
	}

	SubShader
	{
		Tags
		{
			//Render type과 Render Queue를 여기서 결정합니다.
			"RenderPipeline" = "UniversalPipeline"
			"RederType" = "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

			//cg shader는 .cginc를 hlsl shader는 .hlsl을 include하게 됩니다.
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

			float _Intensity;
			float4 _TintColor;

			//vertex buffer에서 읽어올 정보를 선언합니다. 
			struct VertexInput
			{
				float4 vertex : POSITION;
			};

			//보간기를 통해 버텍스 셰이더에서 픽셀 셰이더로 전달할 정보를 선언합니다.
			struct VertexOutput
			{
				float4 vertex : SV_POSITION;
			};

			//버텍스 셰이더
			VertexOutput vert(VertexInput v)
			{
				VertexOutput o;
				o.vertex = TransformObjectToHClip(v.vertex.xyz);

				return o;
			}

			//픽셀 셰이더
			half4 frag(VertexOutput i) : SV_TARGET
			{
				float4 color = _TintColor * _Intensity;
				return color;
			}

			ENDHLSL
		}
	}
}

0개의 댓글