WinCNT

유니티의 에디터에서 장면 전환 후에 바로 플레이 모드를 시작하면 Lighting이 어두워지는 이슈 본문

Unity/Unity 개발 중 발생한 이슈 정리

유니티의 에디터에서 장면 전환 후에 바로 플레이 모드를 시작하면 Lighting이 어두워지는 이슈

WinCNT_SSS 2023. 9. 22. 16:30

발생한 이슈

툴바에 메뉴를 추가해서 장면 전환과 재생(과 그 외 기타 등등)을 하는 기능을 만들던 중에 발생한 이슈이다

 

장면 전환과 재생을 따로 실행하는 건 간단하고 문제도 없었다

그런데 장면 전환과 재생을 스크립에서 동시에 실행할 경우, Lighting(조명) 처리가 제대로 작동하지 않았다

사실 이 부분은 조금 애매한 데, Scene Load 등으로 장면 전환을 해도 바로 바뀌는 것은 아니므로, 해당 이슈는 플레이 모드 중에 장면을 전환해도 일어날 것으로 예상된다

(비슷한 이슈들이 대부분 그런 경우였음)


이슈 상세

다음과 같이 Directional Light가 없는 씬이 있다(기본 Lit 머티리얼)

그 씬을 열고 플레이하는 메뉴도 있다

[MenuItem("Test/Open Scene")]
public static void OnMenuClicked()
{
    EditorSceneManager.OpenScene(_ScenePath);
    EditorApplication.isPlaying = true;
}

마지막으로 다른 씬을 연 상태에서 위의 메뉴를 실행하면 다음과 같이 출력된다

(플레이 모드를 끝내면 뭔가 재계산되는 듯 하면서 제대로 나온다)


발생 원인

직접적인 원인 1: 전역 조명(GI)

일단 Lighting이 어두워지는 직접적인 원인은 전역 조명(GI)에 있다

Lit 셰이더에는 SAMPLE_GI라는 매크로로 베이크된 GI나 미리 계산된 GI를 가져오는데, 여기서 제대로 된 값을 획득하지 못 하고 있었다(아마도 0, 0, 0을 획득하는 것으로 보인다)

 

실제로 LitForwardPass.hlsl의 inputData.bakedGI = SAMPLE_GI(…)의 부분을 적당히 수정하니 해당 이슈가 사라지는 것을 확인할 수 있었다

또한 커스텀 셰이더에도 SAMPLE_GI를 사용하고 있는 부분이 있어서 같은 현상이 일어나고 있었는데, 이 부분을 주석 처리하니 마찬가지로 이슈가 발생하지 않았다

원인은 전역 조명만이 아니었다

 

직접적인 원인 2: unity_SpecCube0_HDR

Auto Generate로 전역 조명을 제대로 나오게 한 경우에도 라이팅에 문제가 남아있었다

좌) 스크립트로 씬을 열고 바로 재생한 경우(이슈) / 우) 프로젝트 창에서 씬을 열기만 한 경우(정상)

처음에는 프레넬에 문제가 생긴 줄 알았으나 조사해보니 아니었다

Lit 셰이더에서 씬을 열고 재생한 경우와 씬을 열기만 한 경우의 return 값이 달라지는 곳을 하나하나 검증해본 결과, unity_SpecCube0_HDR란 변수에서 차이가 발생한다는 것을 알게 되었다

 

참고로 unity_SpecCube0_HDRGlobalIllumination.hlslGlossyEnvironmentReflection라는 메소드 근처에서 사용하고 있는 걸 발견해서 검증했다

// GlobalIllumination.hlsl

half3 GlossyEnvironmentReflection(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion)
{
    // ....
}

 

다음은 unity_SpecCube0_HDR를 그대로 return해본 결과이다

좌) 스크립트로 씬을 열고 바로 재생한 경우(이슈) / 우) 프로젝트 창에서 씬을 열기만 한 경우(정상)

씬을 열고 재생한 경우에는 unity_SpecCube0_HDR의 R채널 값이 1이며, 씬을 열기만 한 경우에는 1이상(아마도 2)으로 추정된다

Global Volume에서 Bloom을 설정 안 했으면 눈치 못 챘을 뻔

 

unity_SpecCube0_HDR는 주로 Reflection Probe와 관련 있는 변수로, 커스텀으로 Reflection Probe의 영향을 받는 셰이더를 작성할 때 사용하거나 한다

unity_SpecCube0는 Reflection Probe의 영향 범위 밖에 있는 경우, Lighting Window의 Environment Reflection에서 설정한 큐브 맵이 들어온다고 한다

【Unity】【シェーダ】Reflection Probeの影響を受けるシェーダを書く - LIGHT11

 

【Unity】【シェーダ】Reflection Probeの影響を受けるシェーダを書く - LIGHT11

Reflection Probeを適用するシェーダの書き方です。 ここではReflection Probeの仕組みは割愛し、シェーダ内での取り扱いについてのみ書きます。 Reflection Probeについては別の記事で書きます(17.07.10

light11.hatenadiary.com

Reflection Probe의 영향 범위 밖에 있는 경우의 큐브 맵은 ReflectionProbe.defaultTexture라는 곳에 설정되는 것으로 보인다

브레이크 포인트를 지정해보니, 씬을 열기만 한 경우(정상인 경우)는 ReflectionProbe.defaultTexture에 UnityCube가 제대로 설정됐지만, 씬을 열고 재생한 경우(이슈가 발생하는 경우)에는 ReflectionProbe.defaultTexture에 UnityBlackCube라는 것이 설정되는 것을 확인할 수 있었다

 

원인 1의 근본적인 원인: SkyBox와 Lighting의 Precomputed

애초에 왜 전역 조명(GI)의 값이 이상한가에 대해서 조사하다가 아래의 레퍼런스를 찾았다

Loading scene additively causes change in lighting

 

Loading scene additively causes change in lighting

I load a scene additively and have my main camera in the first "core" scene and the game world plus single parallel light in the second scene (I've...

forum.unity.com

특히 중요한 문장은 다음이다

Further to this, I'm guessing you may be using Unity's default procedural skybox despite your Camera being set to clear to black. This skybox takes a Directional Light as a "sun" to determine how the sky should be rendered. If the skybox and the Directional light are in separate Scenes it may be the case that the sun is not active in the Scene when the skybox is rendered and lighting precomputed. This might be worth investigating.

위의 글에 따르면 유니티의 디폴트 스카이박스는 절차적 스카이박스(procedural skybox)인데, 이 스카이박스는 Directional Light를 “Sun”으로써 하늘을 어떻게 렌더링하는지 정한다고 한다

(찾아보니 실제로 RenderSettings.sun라는 프로퍼티도 있었다)

 

여기서부터는 위의 글에 추측이 좀 섞이는데, 씬이 전환될 때는 스카이박스가 렌더링되고 Lighting이 미리 계산되는데, 이 때 Directional Light(혹은 Sun)이 비활성화 상태이면 전역 조명(GI)이 제대로 계산되지 않아서 이번 이슈가 발생하지 않았을까 싶다

 

원인 2의 근본적인 원인: SkyManager의 디자인

Skybox나 Reflection Probe는 SkyManager에 의해 컨트롤된다고 한다

Unity - Manual: SkyManager

 

Unity - Manual: SkyManager

SkyManager Understanding the SkyManager Unity includes a dedicated manager—the SkyManager—to ensure that environment lighting affects your sceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level.

docs.unity3d.com

 

아무튼 조사를 해보니 Unlit 장면 전환 시에 Reflection Probe가 이상해지는 것은 SkyManager의 디자인 결함이라는 이슈 트랙커를 찾았다…

Unity IssueTracker - Skybox lighting doesn't update when switching Scenes using SceneManager

 

Unity IssueTracker - Skybox lighting doesn't update when switching Scenes using SceneManager

Reproduction steps: 1. Open the attached project 2. Open "Lit Scene" Scene in the Assets folder of the Project window 3. Enter Play ...

issuetracker.unity3d.com

대부분은 의도된 것입니다

 


해결법

전역 조명(GI) 관련 이슈는 여러 방법으로 해결이 가능했다

하지만 Reflection Probe 관련 이슈는 완전한 해결책을 찾지 못 했다

아무튼 발견한 해결책들을 정리해두고자 한다

 

GI 이슈 해결책 1) Lighting Settings Asset의 Auto Generate

가장 간단한 방법으로는 Lighting Settings Asset를 새로 만들어서 설정하고, Auto Generate를 체크해준다

이 방법으로 전역 조명 관련 이슈는 해결이 가능하다

(아쉽게도 Reflection Probe에는 아무런 영향을 미치지 않음)

 

GI 이슈 해결책 2) 스크립트에서 Lighting Settings를 설정

위의 방법은 다음과 같이 스크립트로도 가능하다

아래는 간단한 예시이다

LightingSettings lightingSettings = new LightingSettings();
lightingSettings.autoGenerate = true;
Lightmapping.lightingSettings = lightingSettings;

LightingSettings에는 그 외에도 다양한 설정이 가능하지만, LightingSettings는 따로 저장되지 않으니 필요하다면 Lighting Settings Asset로 저장하는 처리를 추가해야 한다

플레이 모드를 꺼도 LightingSettings가 그대로 설정되어 있거나, 여러 씬을 로딩할 때는 어디에 설정할지 컨트롤해야 한다거나 하는 등 여러가지로 신경써야 할 부분이 있으므로 사용할 때는 주의가 필요하다

 

GI 이슈 해결책 3) DynamicGI.UpdateEnvironment();

DynamicGI.UpdateEnvironment는 환경 큐브맵을 업데이트(를 예약)하는 메소드가 있었다

DynamicGI.UpdateEnvironment();
yield return new WaitForEndOfFrame(); // 예약된 커맨드가 실행되기 위해 한 프레임 기다림

플랫폼이 AsyncGPUReadback를 지원할 필요가 있는 것 같지만, 이번 프로젝트에선 신경 쓸 필요가 없었다

하지만 ambient probe(RenderSettings.ambientProbe)는 업데이트를 하지 않는 것 같고, 예약된 커맨드가 언제 실행되는지를 알 수 없으니 사용에 주의가 필요한 것 같다

Toggle Precomputed Realtime GI data using scripts

 

Toggle Precomputed Realtime GI data using scripts

I have tried getting an answer to this question a couple of times already in Unity Answers but I think it is too technical for that forum, so I thought...

forum.unity.com

 

Reflection 이슈에 관해

이쪽은 명확한 해결책을 찾을 수 없었다

반쪽짜리 해결책으로는 미리 Lighting 창에서 Generate Lighting을 해두거나, Lightmapping.Bake()를 통해서 라이트 맵을 굽는 방법이 있긴 했다

하지만 이 방법은 Unlit 상태의 Reflection Probe는 제대로 나오지만, 런타임 중에 Directional Light가 변경되서 Skybox가 업데이트 되도 그 상태를 반사하지 못 했다

다음은 그 예시인데, Directional Light가 변경되어 Skybox도 밝아졌지만, Sphere는 맨 처음에 베이킹된 어두운 Skybox를 그대로 반사하고 있는 것을 알 수 있다

Metallic, smoothness가 1인 구체

조금 더 조사해보니 런타임 중에 Directional Light가 변경되서 Default-Skybox, 즉 절차적 스카이박스(procedural skybox)도 변경되어도, 그 반사를 업데이트하지 못 하는 이슈는 다른 이슈 트랙커에 등록되어 있었다

Unity IssueTracker - DynamicGI.UpdateEnvironment fails to update default skybox reflection in Editor in play mode

 

Unity IssueTracker - DynamicGI.UpdateEnvironment fails to update default skybox reflection in Editor in play mode

How to reproduce: 1. Open the user's attached project 2. Open scene Test 3. Go to Window -> Rendering -> Lighting Settings 4. ...

issuetracker.unity3d.com

답변에 따르면 Default의 스카이박스가 아니라, 스카이박스를 직접 베이크하고, 그걸RenderSettings.customReflectionTexture를 통해 할당하는 등의 방법을 소개하고 있다

만약 절차적 스카이박스랑 똑같은 머티리얼을 만들고, 그걸 customReflectionTexture에 할당하는 방법이면 Reflection 이슈도 해결할 수 있을까 싶었지만 실험해보진 않아서 모르겠다

다행히 현 프로젝트는 아직까지는 Reflection를 적용할 예정은 없기에 그냥 무시하기로 했다

딱봐도 무거워 보이기도 하고…설정할 것도 많고…


마무리

간만에 오랫동안 삽질한 이슈였다

처음에는 무엇이 문제로 어떤 일이 일어나고 있는지 파악하는 것 자체가 힘들었다

그 상태에서는 뭐라 검색해야 좋은지도 애매해서 다양한 키워드로 검색했는데 이것도 꽤나 힘든 작업이었다 😭

아무튼 정확한 원인과 일부에 불과하지만 나름 해결책을 찾아서 다행이었다


참고 자료

Unity - Manual: The Lighting window

 

Unity - Manual: The Lighting window

The Lighting window The Lighting window (menu: Window > Rendering > Lighting) is the main control point for Unity’s lighting features. You can use the Lighting window to adjust settings related to the lighting in your Scene, and to optimise your precompu

docs.unity3d.com

Rendering changing with scenes

 

Rendering changing with scenes

Hello everyone, I'm pretty new to Unity and I am running into a bizarre issue I don't know how to fix. Basically, when I load scenes from one...

forum.unity.com

Loading scene additively causes change in lighting

 

Loading scene additively causes change in lighting

I load a scene additively and have my main camera in the first "core" scene and the game world plus single parallel light in the second scene (I've...

forum.unity.com

【Unity】【シェーダ】Reflection Probeの影響を受けるシェーダを書く - LIGHT11

 

【Unity】【シェーダ】Reflection Probeの影響を受けるシェーダを書く - LIGHT11

Reflection Probeを適用するシェーダの書き方です。 ここではReflection Probeの仕組みは割愛し、シェーダ内での取り扱いについてのみ書きます。 Reflection Probeについては別の記事で書きます(17.07.10

light11.hatenadiary.com

Minimal Example of Updating Sky Reflection and Ambient SH

 

Minimal Example of Updating Sky Reflection and Ambient SH

Is there a minimal example, anywhere, that shows how to update a procedural skybox such that objects in the scene are updating their sky environment...

forum.unity.com

Unity - Manual: SkyManager

 

Unity - Manual: SkyManager

SkyManager Understanding the SkyManager Unity includes a dedicated manager—the SkyManager—to ensure that environment lighting affects your sceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level.

docs.unity3d.com

Toggle Precomputed Realtime GI data using scripts

 

Toggle Precomputed Realtime GI data using scripts

I have tried getting an answer to this question a couple of times already in Unity Answers but I think it is too technical for that forum, so I thought...

forum.unity.com

 

이슈 트랙커

Unity IssueTracker - Skybox lighting doesn't update when switching Scenes using SceneManager

 

Unity IssueTracker - Skybox lighting doesn't update when switching Scenes using SceneManager

Reproduction steps: 1. Open the attached project 2. Open "Lit Scene" Scene in the Assets folder of the Project window 3. Enter Play ...

issuetracker.unity3d.com

Unity IssueTracker - ReflectionProbe.defaultTexture changes to UnityBlackCube when changing scenes in Play Mode

 

Unity IssueTracker - ReflectionProbe.defaultTexture changes to UnityBlackCube when changing scenes in Play Mode

Reproduction steps: 1. Open the user’s attached project 2. Open “Assets/Scenes/StartScene.unity” scene 3. Enter Play Mode 4. In Game...

issuetracker.unity3d.com

Unity IssueTracker - DynamicGI.UpdateEnvironment fails to update default skybox reflection in Editor in play mode

 

Unity IssueTracker - DynamicGI.UpdateEnvironment fails to update default skybox reflection in Editor in play mode

How to reproduce: 1. Open the user's attached project 2. Open scene Test 3. Go to Window -> Rendering -> Lighting Settings 4. ...

issuetracker.unity3d.com