그래픽스 튜토리얼
셰이더(Shaders): 버텍스 및 프래그먼트 프로그램(vertex and fragment programs)

셰이더(Shaders): ShaderLab 및 고정 함수 셰이더(ShaderLab and fixed function shaders)

이 튜토리얼에서는 게임의 그래픽 구현 및 그래픽스 퍼포먼스를 최적화할 수 있는 자체 셰이더를 만드는 첫 번째 단계를 설명합니다.

Unity에는 ShaderLab 이라고 하는 강력한 셰이딩 및 머티리얼 언어가 포함되어 있습니다. ShaderLab은 스타일이 CgFX 및 Direct3D Effects(.FX) 언어와 유사하며 머티리얼을 표시하는 데 필요한 모든 것을 정의합니다.

셰이더는 Unity의 머티리얼 인스펙터에 노출되는 프로퍼티와 여러 그래픽스 하드웨어를 대상으로 한 모든 그래픽스 하드웨어 렌더링 상태, 사용하는 버텍스/프래그먼트 프로그램이 포함된 다중 셰이더 구현(SubShaders)을 기술합니다. 셰이더 프로그램은 고급 Cg/HLSL 프로그래밍 언어로 작성됩니다.

튜토리얼에서는 “고정 함수” 표기법을 사용하여 매우 간단한 셰이더를 작성하는 방법을 설명합니다. 다음 장에서는 버텍스 및 프래그먼트 셰이더 프로그램을 소개합니다. 여기서는 독자가 OpenGL 또는 Direct3D 렌더링 상태를 기본적으로 이해하고 있고 HLSL, Cg, GLSL 또는 Metal 셰이더 프로그래밍 언어에 대한 지식이 있다고 가정합니다.

시작

새로운 셰이더를 생성하려면 메인 메뉴에서 Assets > Create > Shader > Unlit Shader 를 선택하거나, 기존 셰이더를 복사하여 작업합니다. 새로운 셰이더는 프로젝트 뷰에서 더블 클릭하여 편집할 수 있습니다.

Unity는 “고정 함수” 표기법으로 매우 간단한 셰이더를 작성할 수 있으며, 이 표기법을 통해 간단하게 시작합니다. 내부적으로 고정 함수 셰이더는 셰이더 임포트 시 일반 버텍스 및 프래그먼트 프로그램으로 전환됩니다.

매우 기본적인 셰이더로 시작합니다.

Shader "Tutorial/Basic" {
    Properties {
        _Color ("Main Color", Color) = (1,0.5,0.5,1)
    }
    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
            }
            Lighting On
        }
    }
}

이 간단한 셰이더는 가능한 가장 기본적인 셰이더 중 하나입니다. Main Color 라고 하는 컬러 프로퍼티를 정의하고 기본 분홍색(red=100% green=50% blue=50% alpha=100%)을 할당합니다. Pass 를 적용하고, 패스에서 디퓨즈 머티리얼 컴포넌트를 _\Color__ 프로퍼티에 설정하고 버텍스당 조명을 활성화하여 오브젝트를 렌더링합니다.

이 셰이더를 테스트하려면 새 머티리얼을 생성한 다음, (Tutorial->Basic)드롭다운 메뉴에서 셰이더를 선택하고 머티리얼을 일부 오브젝트에 할당합니다. 머티리얼 인스펙터에서 컬러를 미세 조정하고 변화를 확인합니다. 이제 더 복잡한 단계로 이동합니다.

기본 버텍스 조명

기존의 복합 셰이더를 열면 한번에 파악하기가 다소 어려울 수 있습니다. 먼저 Unity에 탑재된 빌트인 VertexLit 셰이더를 분석합니다. 셰이더는 표준 버텍스당 조명을 실행하는 데 고정 함수 파이프라인을 사용합니다.

Shader "VertexLit" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,0.5)
        _SpecColor ("Spec Color", Color) = (1,1,1,1)
        _Emission ("Emmisive Color", Color) = (0,0,0,0)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }

    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
                Ambient [_Color]
                Shininess [_Shininess]
                Specular [_SpecColor]
                Emission [_Emission]
            }
            Lighting On
            SeparateSpecular On
            SetTexture [_MainTex] {
                constantColor [_Color]
                Combine texture * primary DOUBLE, texture * constant
            }
        }
    }
}

모든 셰이더는 셰이더 키워드로 시작하고 셰이더의 이름을 나타내는 문자열이 뒤따릅니다. 이 이름은 Inspector 에 표시되는 이름입니다. 셰이더의 모든 코드는 그 뒤의 중괄호 { }(블록이라고 함) 안에 포함해야 합니다.

  • 이름은 간결하고 서술적이어야 합니다. .shader 파일 이름과 일치하지 않아도 됩니다.
  • 셰이더를 Unity의 하위 메뉴에 포함하려면 슬래시를 사용해야 합니다. 예를 들어 MyShaders/TestMyShaders 라고 하는 하위 메뉴에 Test 로 표시되거나 MyShaders->Test 로 표시됩니다.

셰이더는 Properties 블록과 SubShader 블록으로 구성됩니다. 각 SubShader 블록은 아래 섹션에 설명되어 있습니다.

프로퍼티

셰이더 블록을 처음 시작할 때 아티스트가 머티리얼 인스펙터에서 편집할 수 있는 모든 프로퍼티를 정의할 수 있습니다. 예제 프로퍼티는 VertexLit 는 다음과 같이 표시됩니다.

프로퍼티는 프로퍼티 블록에서 별도의 행에 나열됩니다. 각 프로퍼티는 내부 이름(Color, MainTex)으로 시작합니다. 괄호 안에서 인스펙터에 표시되는 이름과 프로퍼티 유형이 뒤따릅니다. 그 뒤에는 프로퍼티의 기본값이 나열됩니다.

가능한 타입의 리스트는 프로퍼티 레퍼런스에 있습니다. 기본값은 프로퍼티 유형에 따라 달라집니다. 컬러 예제에서 기본값은 네 가지 컴포넌트 벡터여야 합니다.

이제 프로퍼티를 정의했으며, 실제 셰이더 작성을 시작할 준비가 되었습니다.

셰이더 본문

계속하기 전에 셰이더 파일의 기본 구조를 정의합니다.

그래픽 하드웨어마다 성능이 모두 다릅니다. 예를 들어, 일부 그래픽 카드는 프래그먼트 프로그램을 지원하지만 다른 프로그램은 지원하지 않으며, 일부는 패스당 네 개의 텍스처를 사용할 수 있지만 일부는 오직 두 개 또는 하나만 사용할 수 있습니다. 어떤 하드웨어를 보유하고 있든지 최상의 사용을 위해 셰이더에 여러 개의 SubShaders 를 포함할 수 있습니다. Unity는 세이더를 렌더링할 때 모든 서브셰이더를 확인한 후 하드웨어가 지원하는 첫 번째 셰이더를 사용합니다.

Shader "Structure Example" {
    Properties { /* ...shader properties... }
    SubShader {
        // ...subshader that requires fancy DX11 / GLES3.1 hardware...
    }
    SubShader {
        // ...subshader that requires DX9 SM3 / GLES3 hardware...
    }
    SubShader {
        // ...subshader that might look ugly but runs on anything :)
    }
}

이 시스템으로 Unity는 기존의 모든 하드웨어를 지원하고 각 하드웨어에서 품질을 극대화합니다. 하지만 셰이더는 다소 길어집니다.

각 서브셰이더 블록 안에 모든 패스가 공유하는 렌더링 상태를 설정하고 자체적으로 렌더링 패스를 정의합니다. 사용 가능한 커맨드의 전체 리스트는 서브셰이더 레퍼런스에서 확인할 수 있습니다.

패스(Passes)

각 서브셰이더는 패스의 컬렉션입니다. 각 패스에 대해 오브젝트 지오메트리가 렌더링되며 최소 하나 이상의 패스가 존재해야 합니다. 버텍스 릿 셰이더에는 패스가 하나만 포함됩니다.

// ...snip...
Pass {
    Material {
        Diffuse [_Color]
        Ambient [_Color]
        Shininess [_Shininess]
        Specular [_SpecColor]
        Emission [_Emission]
    }
    Lighting On
    SeparateSpecular On
    SetTexture [_MainTex] {
        constantColor [_Color]
        Combine texture * primary DOUBLE, texture * constant
    }
}
// ...snip...

패스에 정의된 모든 커맨드는 특정한 방법으로 지오메트리를 렌더링할 그래픽스 하드웨어를 설정합니다.

위의 예제에는 프로퍼티 값을 고정 함수 조명 머티리얼 설정으로 바인드하는 머티리얼 블록이 있습니다. Lighting On 커맨드는 표준 버텍스 조명을 켜고 SeparateSpecular On 은 스페큘러 하이라이트용 개별 컬러 사용을 활성화합니다.

지금까지 모든 커맨드는 고정 함수 OpenGL/Direct3D 하드웨어 모델에 매우 직접적으로 매핑합니다. 이에 대한 자세한 내용은 OpenGL red book을 참조하십시오.

다음 커맨드 SetTexture 는 매우 중요합니다. 이 커맨드는 사용하고자 하는 텍스처 및 텍스처를 렌더링에서 믹스하고 결합하고 적용하는 방법을 정의합니다. SetTexture 커맨드 뒤에는 사용하고자 하는 텍스처의 프로퍼티 이름(여기서는 _\MainTex)이 나옵니다. 이 뒤에는 텍스처가 적용되는 방법을 정의하는 combiner block__ 이 나옵니다. 컴바이너 블록의 커맨드는 화면에 렌더링되는 각 픽셀에 대해 실행됩니다.

이 블록에서는 상수 컬러 값, 머티리얼 컬러, _\Color__ 를 설정합니다. 이 상수 컬러는 아래에서 사용합니다.

다음 커맨드에서 텍스처와 컬러 값을 어떻게 믹스할지 지정합니다. 텍스처를 다른 텍스처 또는 컬러와 어떻게 블렌드할지 지정하는 Combine 커맨드로 실행합니다. 일반적으로 다음과 같이 표시됩니다: Combine ColorPart, AlphaPart

여기서 ColorPartAlphaPart 는 각각 컬러(RGB)와 알파(A) 컴포넌트의 블렌딩을 정의합니다. AlphaPart 가 생략되면 ColorPart 와 같은 블렌딩을 사용합니다.

버텍스 릿 예제 중: Combine texture * primary DOUBLE, texture * constant

여기서 texture 는 현재 텍스처(여기서 \MainTex)에서 가져오는 컬러로 primary_ 버텍스 컬러로 곱셈(*)됩니다. 주 컬러는 버텍스 조명 컬러로 위의 머티리얼 값에서 연산됩니다. 마지막으로 결과는 조명 강도를 증가시키기 위해 2가 곱해집니다(DOUBLE). 알파 값(콤마 뒤)은 (위에서 constantColor__ 로 설정된) textureconstant 값을 곱한 값입니다. 일반적으로 사용되는 다른 컴바이너 모드는 previous 라고 합니다(이 셰이더에서 사용되지 않습니다). 모든 이전__ SetTexture__ 단계의 결과이며 일부 텍스처 및 컬러를 결합하는 데 사용될 수 있습니다.

요약

버텍스 릿 셰이더는 표준 버텍스 조명을 설정하고 텍스처 컴바이너를 설정해 렌더링된 조명 강도가 두 배가 됩니다.

셰이더에 한 패스가 끝난 뒤 다른 패스가 렌더링되도록 더 많은 패스를 부여할 수 있습니다. 하지만 이제 원하는 효과를 적용했기 때문에 필요하지 않습니다. 모든 고급 기능을 사용하지 않기 때문에 단 하나의 서브셰이더만 필요합니다. 이 특정 셰이더는 Unity가 지원하는 모든 그래픽 카드에서 작동합니다.

버텍스 릿 셰이더는 생각할 수 있는 가장 기본 셰이더 중 하나입니다. 하드웨어 특정 작업을 사용하지 않고 ShaderLab 및 Cg/HLSL가 제공해야 하는 더 특별하고 멋진 커맨드를 사용하지 않습니다.

다음 장에서 Cg/HLSL 언어를 사용하는 커스텀 버텍스 및 프래그먼트 프로그램을 어떻게 작성하는지에 대한 설명을 계속합니다.

그래픽스 튜토리얼
셰이더(Shaders): 버텍스 및 프래그먼트 프로그램(vertex and fragment programs)