UV 기본 개념

  • 2차원 좌표로 이루어진 float2 숫자
  • 0~1 범위로 표현할 수 있음.
  • UV 좌표는 xy와 RG와 동일하게 취급하므로, UV = XY = RG 이기도 함.

 

각 엔진이나 툴마다 UV 배치가 다르다. Unreal 엔진이나 DirectX는 좌측 상단이 float2(0,0) 이지만 Unity 엔진이나 OpenGL은 좌측 하단을 float2(0,0)로 나타낸다.

 

 

 

UV 시각적 확인

Quad 오브젝트를 하나 생성하고 텍스쳐 한 장 받는 것 외엔 아무 기능이 없는 쉐이더를 만들어, 메터리얼과 오브젝트에 적용하였다.

 

 

 

위 사각형에서 가장 좌측 하단 모서리의 Vertex에 들어 있는 UV는 (0.0,0.0) 이며 우측 하단은 (1.0,0.0)이다. 우측/좌측 상단 또한 이와 같은 방식으로 동일하다.

 

 

 

외부 인터페이스가 아닌, 유니티 내부로부터 _MainTex의 UV를 받아옴.
struct Input
{
    float2 uv_MainTex;
};​

 

선언된 UV를 text2D(sampler,UV)에 사용함.
fixed4 c = tex2D (_MainTex, IN.uv_MainTex);​

 

 

 

 

UV를 눈으로 확인할 수 있도록 다양한 방식으로 출력
  • U 출력
void surf (Input IN, inout SurfaceOutputStandard o)
 {
     fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
     o.Albedo =IN.uv_MainTex.x;
     o.Alpha = c.a;
 }

 

 

 

  • V 출력

 

  • U와 V 동시에
    • U는 Red로 표현되고, V는 Green으로 표현
void surf (Input IN, inout SurfaceOutputStandard o)
{
    fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    o.Albedo = float3(IN.uv_MainTex.x, IN.uv_MainTex.y, 0);
    o.Alpha = c.a;
}

 

 

 

UV 연산


fixed4 c = tex2D (_MainTex, IN.uv_MainTex + 0.5);

 

UV에 0.5를 더하면 아래 사진처럼 텍스쳐가 왼쪽 아래로 밀려 내려온 것을 볼 수 있다.

 

 

 

💡텍스쳐의 Wrap Mode를 clamp로 바꾸면 UV를 벗어나는 영역에서도 텍스쳐가 계속 반복되어, UV를 이동시켜도 계속 연결되어 보일 수 있도록 함. Reapeat은 반복됨.

 

 

 

 

UV 응용 (Time 활용)


Time 관련 변수
https://docs.unity3d.com/2021.3/Documentation/Manual/SL-UnityShaderVariables.html

 

Uv에 숫자를 더하면? 이미지가 이동한다. 즉, Time 관련 변수를 활용하여 이미지를 지속해서 이동시켜 흘러가도록 보이게 할 수 있다.

 

더보기

fixed4 c = tex2D (_MainTex, IN.uv_MainTex + _Time.y);

  • X 방향으로 흘러가게 할 때
더보기

fixed4 c = tex2D (_MainTex, float2(IN.uv_MainTex.x + _Time.y, IN.uv_MainTex.y);

 

 

  • Y 방향으로 흘러가게 할 때
더보기

fixed4 c = tex2D(_MainTex, float2(IN.uv_MainT

ex.x, IN.uv_MainTex.y + _Time.y));

 

 

 

UV 활용 이펙트 제작

제작할 불 이펙트를 만들려면 주로 파티클을 사용하거나 시퀀스 이미지들을 겹쳐서 사용하는 두 가지의 방법을 적절히 응용해서 사용하곤 한다. 이번 파트에서는 쉐이더를 사용하여 불 이펙트를 만들 것이다.

 

o.Albedo를 o.Emission으로 변경하여 빛의 영향을 배제

 

 

 

알파 채널 활성화 (임시 작동)
아래와 같이 코드를 변경한다.
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 200

CGPROGRAM
#pragma surface surf Standard alpha:fade​

 

 

 

 

_Time.y에 따라 이동하는 이미지 추가

 

 

 


두 장의 이미지 활용
void surf (Input IN, inout SurfaceOutputStandard o){
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
            fixed4 d = tex2D(_MainTex2, float2(IN.uv_MainTex2.x, IN.uv_MainTex2.y - _Time.y));
            o.Emission = d.rgb * c.rgb;
            o.Alpha = c.a * d.a;
}​

 

 

 

 

 

 

UV 활용 이펙트 제작 (2)

위에서 제작한 불 이펙트를 업그레이드 해보기 위한 과정이다.
우선, 확실한 효과를 보기 위하여 불 이미지를 아래와 같이 체크 이미지로 변경하였으며 두 번째 이미지는 코드 내에서 _MainTex2 ("Albedo (RGB)", 2D) = "black" {}을 추가하여 검정색 이미지를 출력하도록 하였다.

 

 

 

아래와 같이 코드를 변경하여 c의 uv에 d.r을 더해주어도 아무 변화가 일어나지 않는다.
d는 float4(0,0,01)이기 때문이다.

 

 void surf (Input IN, inout SurfaceOutputStandard o)
 {
     fixed4 d = tex2D(_MainTex2, IN.uv_MainTex2);
     fixed4 c = tex2D(_MainTex, IN.uv_MainTex + d.r);
     o.Emission = c.rgb;
     o.Alpha = c.a;
 }
 ENDCG

 

 

d 텍스쳐의 색상에 따라 변경되는 이미지의 이동 범위

 

 

 

 

d 텍스쳐의 이미지에 따라 다르게 출력되는 c 텍스쳐의 이미지

 

 

 

 

  • 위로 흐르도록 코드 변경
void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 d = tex2D(_MainTex2, float2(IN.uv_MainTex2.x, IN.uv_MainTex2.y - _Time.y));
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex + d.r);
            o.Emission = c.rgb;
            o.Alpha = c.a;
        }

 

 

 

  • c 텍스쳐 이미지 불로 변경
텍스쳐 한 장 출력 이외의 코드 정리


쉐이더 코드의 기본형

Shader "Custom/Practice_Part5"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}


위 코드에서 Texture 한 장을 출력하기 위한 코드를 제외하고 필요 없는 코드를 모두 정리해보면 아래와 같다.

Shader "Custom/Practice_Part5"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Standard

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

텍스쳐 입력 및 출력


텍스쳐를 입력받는 인터페이스를 만드는 코드

_MainTex ("Albedo (RGB)", 2D) = "white" {}

"Albedo (RGB)" : 해당 부분은 Albedo 텍스쳐를 넣는 곳이고, 알파는 사용하지 않고 RGB 채널만 사용하겠다는 의미
2D : 해당 인터페이스가 2D 텍스쳐를 받는 부분이라는 의미
"white" {} : 해당 텍스쳐 인터페이스의 초기 default 값은 흰색 텍스쳐라는 의미

 

 

인터페이스를 통해 입력받은 텍스쳐를 변수로 받는 코드

sampler2D _MainTex;


구조체 내부에서 uv를 받아오는 코드

float2 uv_MainTex;
uv : float2이며 텍스쳐는 이 uv 좌표와 text2D를 통해 계산되어야 float4로 출력할 수 있음.
uv는 vertex가 가지고 있기 때문에 이렇듯이 우리가 만든 인터페이스가 아닌 vertex 내부의 것을 엔진에게 명령할 때에는 Input 구조체를 사용해야 함.



텍스쳐를 연산하여 컬러를 화면에 출력하는 코드

fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

 

 

이미지 흑백 전환




흑백 이미지의 두 가지 속성

- R,G,B 모두 동일한 숫자로 이루어짐
- 해당 숫자는 R,G,B 각 요소에 따른 강도의 평균이어야 함

o.Albedo = (c.r+c.g+c.b)/3;

 

 

o.Albedo = c.rgb;에서 o.Albedo = (c.r+c.g+c.b)/ 3;로 코드를 변화하니 위와 같이 이미지가 흑백으로 변경된 것을 볼 수 있다.

 

 

lerp 함수


위 코드와 같이 lerp 함수를 통해 테스쳐 두 장을 섞으면, 아래와 같이 출력된다.

  • lerp: Linear Interpolation 선형 보간
  • lerp 함수:
  • s값이 0에 가까울 수록 X와 가깝게 출력되며 1에 가까울 수록 반대
  • lerp ( X , Y , s)

 

오브젝트에 메터리얼(Material)과 쉐이더 적용

 

  1. 오브젝트 생성: (예시) GameObject > 3D Object > Sphere
  2. 쉐이더 생성:
  3. 메터리얼 생성:
  4. 적용:
    • 쉐이더->메터리얼 drag&drop / 메터리얼->화면 상의 오브젝트 drag&drop
    • 메터리얼의 Inspector에서 쉐이더 변경 / 오브젝트의 Inspector > Mesh Renderer > Meterials > Element 0 에 메터리얼 적용

 

쉐이더 코드


  • 쉐이더 코드를 더블 클릭하면 MonoDevelop 또는 VisualStudio 프로그램 실행
  • 기본 코드
    • Shader "Custom/NewSurfaceShader"에서 "Custom/NewSurfaceShader"는 메터리얼에서 선택할 수 있는 쉐이더의 이름이며 '/' 트리구조 생성

 

쉐이더 ProPerties

 Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
  • 쉐이더의 인터페이스인 Properties 영역
    • 이 부분에서 작성한 코드는 메터리얼의 인스펙터 인터페이스로 볼 수 있음.
    • 인터페이스를 만드는 방법
//Float을 받는 인터페이스
_Name ("display name", Range (min, max)) = number
_Name ("display name", Float) = number
_Name ("display name", int) = number

//Float4를 받는 인터페이스
_Name ("display name", Color) = (number, number, number, number)
_Name ("display name", Vector) = (number, number, number, number)

//기타 SampLer를 받는 인터페이스
_Name ("display name", 2D) = "name" { options }
_Name ("display name", Rect) = "name" { options }
_Name ("display name", Cube) = "name' { options }
_Name ("display name", 3D) = "name" { options }

 

1. Range
최솟값과 최댓값을 입력해주면 슬라이더가 나오는 명령

_Name ("display name", Range (min,max)) = number

 

2. Float
한 자리의 소수점을 입력받는 인터페이스

_Name ("display name", Float) = number

 

3. Color
R,G,B,A 4자리 숫자인 float4를 입력받는 인터페이스
_Name ("display name", Color) = (number,number,number,number)​

 

4. Vector
Color와 동일하게 float4를 숫자로 입력받지만, 색상이 아닌 값으로 입력받음
_Name ("display name", Vector) = (number,number,number,number)​

 

5. text2D
float 계열로 분류되지 않는 sampler들 (2D텍스쳐를 받는 인터페이스)
_Name ("display name", 2D) = "name" {options}​

 

 

 

색상 출력 및 연산


  • 유니티 자체 스크립트가 아닌 CG 언어를 이용하여 쉐이더를 짜는 CGPRGRAM ~ ENDCG 영역
 CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        #pragma enable_d3d11_debug_symbols

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG

1. 설정 부분
전처리 또는 스니핏(snippet)이라 부름. 쉐이더의 조명 계산 설정이나 세부적인 분기를 정해주는 부분

// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0

2. Input 구조체
엔진으로부터 받아와야 할 데이터

struct Input{
            float2 uv_MainTex;
};

3. 함수 영역
색상이나 이미지가 출력되는 부분

void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
  • o.Albed: 빛의 영향을 받는 색이 출력
  • o.Emmision: 빛의 영향을 받지 않는 색이 출력위와 같이 변수를 사용하여 출력 색상 변경 또한 가능하다.
void surf (Input IN, inout SurfaceOutputStandard o) { 
	float4 test = float4(1,0,0,0); 
    fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; 
    //o.Albedo = test.ggg; 
    //o.Albedo = test.b; 
    o.Albedo = test; 
    o.Alpha = c.a; }

 

 

외부의 입력값 출력


  • 색상 입력 받고 출력
    ex) properties에 _TestColor("TestColor", Color) = (1,1,1,1) 을 추가하여 인스펙터에 나타내고, float4 _TestColor; 로 변수를 추가한 뒤, surf 함수 내에서 o.Albedo = _TestColor.rgb;을 추가

즉, 인터페이스에서 원하는 타입의 변수를 생성한 후, SubShader 코드에 선언하고, surf함수에서 변수를 사용하면 출력 가능

 

유니티 쉐이더 작성

ShaderLab으로만 작성

  • ShaderLab 문법만 이용해서 작성하는 방법
  • 장점: 매우 가볍고 하드웨어 호환성이 좋음
    단점: 기능이 부족하며 자체 문법으로 이루어져 있어, 다른 쉐이더 문법과 거의 호환되지 않음. 고급 기법 구현 불가

Surface Shader로 작성

  • ShaderLab 스크립트와 함께 일부분은 CG 쉐이더 코드를 사용
  • 장점: 조명과 버텍스 쉐이더의 복잡한 부분은 스크립트가 자동 처리하며 픽셀 쉐이더 부분만 간편하게 작성할 수도 있어서 편리함.
    단점: 최적화에 무리가 있으며 일정 수준 이상의 고급 기법은 구현 불가

Vertex & Fragment Shader로 작성

  • ShaderLab 스크립트와 CG 쉐이더 코드를 모두 사용하며 보다 본격적인 쉐이더 작성 방법
  • 제대로 된 CG 쉐이더 방식으로 버텍스의 좌표 변환부터 제대로 처리해야 작동
  • 장점: 최적화와 고급 기법 표현에 유리

렌더링 파이프라인( Rendering Pipeline:렌더링 순서)


  • 오브젝트 데이터 받아오기
    • 그래픽 카드는 버텍스(Vertex)으로 이루어진 물체의 데이터 값을 받아옴.
    • -> 그래픽 카드 내부의 값으로만 존재하는 데이터
    • 버텍스는 Index number, Position, Normal, Color, UV 등의 정보를 가짐.
    • 그래픽 카드는 버텍스의 정보들을 통하여 삼각형 면을 생성하여 오브젝트의 기본적인 형태를 갖춘 후, 이를 버텍스 쉐이더로 넘길 준비를 함.

 

  • 정점(Vertex) 쉐이더
    • 데이터들을 활용한 본격적인 쉐이딩 작업의 첫 번째 과정
    • 좌표 변환
      • 버텍스는 물체가 가지고 잇는 '자기중심적인' 위치 값을 의미하는 로컬(Local) 좌표계 상태
      • -> 오브젝트별로 가지고 있는 본인의 피봇이 0,0,0 위치값, 즉 중심값인 상태
      • _'원드 변환 행렬(월드 좌표계)'_을 곱해주어 월드 좌표계로 변환
      • -> 절대 좌표인 월드 좌표계의 위치로부터 각 물체의 상대적 위치 값 표현
      • _'카메라 행렬'_을 곱하여 원드 좌표계상의 오브젝트 버텍스 위치 값들을 카메라 중심점으로부터의 상대적 거리로 변환
        🔑 카메라 행렬 = 뷰(View) = 오쏘그래픽 프로젝션(Orthographic Projection)
      • 다시 _'프로젝션(Projection) 행렬'_로 곱하여 원근감 표현
    여기까지 작업을 그대로 모니터에 출력하면? 텍스쳐, 음영, 라이트 무엇도 없는 그냥 폴리곤 덩어리가 생성된다. 말 그대로 모니터로 볼 수도 없는 단지 3D 공간에서 존재하는 오브젝트일 뿐이다.

 

  • 래스터라이저(Rasterizer)
    • Rasterizer : 이 오브젝트가 모니터에서 표현될 때 어느 픽셀로 표현될 것인지를 나타내는 장치
    • 래스터화 : 3D 오브젝트를 모니터에 보이도록 '픽셀'로 변환하는 과정

 

  • 픽셀 쉐이더(Pixel Shader)

'한 픽셀의 색을 결정하는 코드'

모니터까지 넘어온 3D 그래픽 데이터는 본격적으로 화면에 픽셀로 찍히게 되는데, 아직 텍스쳐와 라이팅은 없는 상태임. 여기에서 픽셀 쉐이더가 가동되며 조명과 텍스쳐, 그림자와 각종 특수효과 등을 연산함.

 

 

 

색과 빛의 기본 원리


  • 가산혼합: RGB(Red, Green, Blue)로 이루어진 색을 더하면 더할수록 밝아지며, 모두 더하며녀 흰색이 되는 색의 체계
  • 일반적인 컬러 모니터는 RGB로 구성된 3개의 서브 픽셀로 이루어짐.
💡'3D 컴퓨터 그래픽에서 최종적으로 화면에 출력하는 픽셀의 색을 정해주는 함수'
💡'그래픽 데이터의 음영과 색상을 계산하여 다양한 재질을 표현하는 방법'
유니티 엔진에서는 '쉐이더(Shader)', 언리얼 엔진에서는 '메터리얼(Material)'

+ Recent posts