Unity에서 Shader를 직접 작성할 때, 기본 조명과 그림자 데이터를 받아오는 방법을 정리한다.

Shader Graph에서 활용할 Custom Function을 만들고, HLSL을 사용하여 유니티의 조명 및 그림자 정보를 가져오는 방법을 다룬다.

기본 조명 가져오기

GetMainLight()를 통해 씬의 메인 라이트 정보를 가져올 수 있다.

다음과 같이 HLSL 함수를 작성하면, 메인 라이트의 방향(Direction)과 색상(Color)을 받아올 수 있다.

void GetMainLight_float(out float3 Direction, out float3 Color)
{
    #ifdef SHADERGRAPH_PREVIEW
        Direction = float3(1, 1, 1); // Shader Graph 미리보기 환경에서는 기본 방향을 설정
        Color = float3(1, 1, 1);
    #else
        Light mainLight = GetMainLight();
        Direction = mainLight.direction; // 씬 내 실제 조명 방향 사용
        Color = mainLight.color;
    #endif
}
  • Shader Graph 미리보기 모드(SHADERGRAPH_PREVIEW)
    • 미리보기에서는 씬 조명이 없으므로, Direction = float3(1,1,1)과 같이 임의의 값을 할당한다.
  • 실제 조명 적용 (#else)
    • GetMainLight()를 통해 유니티 씬의 메인 라이트 정보를 가져온다.
    • mainLight.direction → 조명의 방향
    • mainLight.color → 조명의 색상

이를 Shader Graph의 Custom Function에서 활용하면, 유니티 기본 조명을 받아와 사용할 수 있다.

image-20250320222538545

유니티 기본 그림자 받아오기

유니티의 그림자 데이터를 가져오려면 그림자 좌표(Shadow Coordinate)를 계산한 후, 이를 샘플링해야 한다.

아래 Custom_Shadow_float 함수는 그림자 감쇄(Shadow Attenuation)를 계산하는 역할을 한다.

void Custom_Shadow_float(float3 worldPos, out float ShadowAtten, out float3 Direction, out float3 Color)
{
#ifdef SHADERGRAPH_PREVIEW
    Direction = float3(1,1,1);
    Color = float3(1,1,1);
    ShadowAtten = 1.0f;
#else
    Direction = float3(1,1,1);
    Color = float3(1,1,1);

    // Shadow Coord 만들기
    #if defined(_MAIN_LIGHT_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
        half4 clipPos = TransformWorldToHClip(worldPos);
        half4 shadowCoord = ComputeScreenPos(clipPos);
    #else
        half4 shadowCoord = TransformWorldToShadowCoord(worldPos);
    #endif

    // 그림자 사용 여부 확인
    #if !defined(_MAIN_LIGHT_SHADOWS) || defined(_RECEIVE_SHADOWS_OFF)
        ShadowAtten = 1.0f;
    #endif

    // Shadow Atten 샘플링
    #if SHADOWS_SCREEN
        ShadowAtten = SampleScreenSpaceShadowmap(shadowCoord);
    #else
        ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
        half shadowStrength = GetMainLightShadowStrength();
        ShadowAtten = SampleShadowmap(shadowCoord, 
                      TEXTURE2D_ARGS(_MainLightShadowmapTexture, 
                                     sampler_MainLightShadowmapTexture), 
                      shadowSamplingData, shadowStrength, false);
    #endif
#endif
}
  1. Shader Graph 미리보기 모드

    • ShadowAtten = 1.0f; // 그림자가 없는 상태
    • Direction, Color도 기본값으로 설정.
  2. Shadow Coordinate(그림자 좌표) 계산

    • _MAIN_LIGHT_SCREEN
      

      이 활성화된 경우:

      • TransformWorldToHClip(worldPos)월드 좌표 → 클립 공간 변환
      • ComputeScreenPos(clipPos)스크린 좌표 변환
    • 그렇지 않은 경우:

      • TransformWorldToShadowCoord(worldPos)월드 좌표를 그림자 좌표로 변환
  3. 그림자가 적용되지 않는 경우(옵션 비활성화)

    • _MAIN_LIGHT_SHADOWS가 없거나 _RECEIVE_SHADOWS_OFF가 설정된 경우, 그림자 효과 없이 ShadowAtten = 1.0f;로 설정.
  4. 그림자 샘플링

    • SHADOWS_SCREEN
      

      이 활성화된 경우:

      • SampleScreenSpaceShadowmap(shadowCoord)스크린 공간에서 그림자 샘플링
    • 그렇지 않은 경우:

      • SampleShadowmap()을 통해 그림자 맵을 샘플링하여 그림자 강도를 계산

이 함수를 활용하면 Shader Graph에서 유니티의 기본 그림자 데이터를 받아올 수 있다.

image-20250320222508390

트러블 슈팅

Custom Function 오류 해결 트러블슈팅

Shader Graph에서 CustomLight_Shadow_float를 사용하는 Custom Function 노드에서 다음과 같은 오류가 발생했다.

  • 'CustomLight_Shadow_float': no matching 2 parameter function

  • 'CustomLight_Shadow_float': cannot convert output parameter from 'float3' to 'float'

image-20250320222721043

원인: Shader Graph에서 Custom Function 노드의 Output 개수 부족

문제 발생 원인은 Shader Graph에서 Custom Function 노드의 출력(Outputs) 설정이 HLSL 함수의 반환 값과 일치하지 않아서였다.

void CustomLight_Shadow_float(float3 worldPos, out float ShadowAtten, out float3 Direction, out float3 Color)
  • 이 함수는

    총 3개의 출력 값

    을 반환해야 한다:

    • ShadowAtten (float)
    • Direction (float3)
    • Color (float3)
  • 그러나 Shader Graph에서 Custom Function 노드의 출력이 일부 누락된 경우, Shader Graph가 올바르게 호출할 수 없어 오류가 발생했다.

결과적으로 Shader Graph가 잘못된 인자 개수로 Custom Function을 호출하려고 시도했으며, 그로인해 함수 매칭 오류가 발생했다.

no matching 2 parameter function → 인자 개수가 맞지 않음

하지만 ShadowAtten의 자료형을 변환 할 수 없는 오류가 뜨는게 이상하긴 하다.

댓글남기기