공부 기록/유니티 Unity

[Unity/TIL] 3D 환경 조성하기 (스카이박스 & 낮과 밤 구현하기)

톰마토 2025. 3. 4. 20:56
반응형
목차
- 스카이박스로 하늘 만들기
- 조명으로 낮과 밤 만들기 

실행 예시

스카이박스

전체 씬을 둘러싸서 하늘의 역할을 함. 6 Sided Skybox를 만들면 총 여섯 면으로 둘러싸고 있어서 6개 각각 텍스처 매핑할 수 있음. 

6 Sided 선택 시

스카이박스로 하늘 만들기

새 'Material' Create > Shader를 Skybox로 적용.

Skybox Material

Window > Rendering > Lighting 창 열어서 Environment 탭에서 Skybox 머티리얼 지정해줄 수 있음.

Skybox 적용하는 방법

스카이박스의 Sky와 Ground 색을 지정해줬다. 

만든 Skybox 설정

조명으로 낮과 밤 만들기

Directional Light의 Roatation을 조절해보면 90도일 때 해가 꼭데기(정오)에 있음. 0도일 때 해가 동쪽에 있고, 180도일 때 서쪽에 있으며 270도일 때 가장 깜깜하다. 

이게 가능한 이유는 단순히 Directional Light가 있으면 그게 해가 되는 것이 아니라, 아까 Skybox를 지정해줬던 같은 Lighting 창 > Environment 탭의 Sun Source에 Directional Light를 넣었기 때문에 태양 효과를 볼 수 있는 것이다. 

설정하는 것 뿐만 아니라 아래 옵션 중 Lighting Intensity Multiple, Reflections Intensity Multiple을 조절해줄 것이다. 

Sun Source

조절해줄 때는 Sprite 애니메이션에서 일정 값 사이를 자연스럽게 보간해주던 것처럼, Key값을 설정해주면 그 사이사이를 보간해주는 방식으로 조절하게 된다.

 

AnimationCurve는 유니티에서 애니메이션의 키프레임을 사용하여 값을 보간하는 데 사용되는 클래스이다. 이 클래스를 사용해서 값을 부드럽게 변화시키는 커브를 정의하고, 이를 기반으로 애니메이션을 만들 수 있다.

 

1. Sun, Moon 만들어주기

씬의 Directional Light를 Sun으로, 복제본을 Moon으로 만듦. 

2. DayNightCycle 스크립트 작성 및 설정

스크립트에서 해와 달의 사이클을 돌려준다. Evaluate는 Curve에서 특정 시간에 해당하는 값을 보간하여 반환한다.

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class DayNightCycle : MonoBehaviour
{
    [Range(0f, 1f)]
    public float time;
    public float fullDayLength;
    public float startTime = 0.4f; // 시간을 0~1로 잡을 것이기 때문에 타임이 0.5일 때 정오. 각도가 90도 
    private float timeRate;
    public Vector3 noon; // Vector 90 0 0

    [Header("Sun")]
    public Light Sun;
    public Gradient sunColor;
    public AnimationCurve sunIntensity;

    [Header("Moon")]
    public Light Moon;
    public Gradient moonColor;
    public AnimationCurve moonIntensity;

    [Header("Other Lighting")]
    public AnimationCurve lightingIntensityMultiplier;
    public AnimationCurve reflectionIntensityMultiplier;

    private void Start()
    {
        timeRate = 1f / fullDayLength;
        time = startTime;
    }

    private void Update()
    {
        time = (time + timeRate * Time.deltaTime) % 1f; // time을 0~1로 지키기 위함
        
        UpdateLighting(Sun, sunColor, sunIntensity);
        UpdateLighting(Moon, moonColor, moonIntensity);

        // 씬 전체의 환경광 밝기 조절 (0으로 하면 씬 전체가 어두워짐)
        RenderSettings.ambientIntensity = lightingIntensityMultiplier.Evaluate(time);
        // 씬 전체의 반사광 강도 조절
        RenderSettings.reflectionIntensity = reflectionIntensityMultiplier.Evaluate(time);
    }

    void UpdateLighting(Light lightSource, Gradient gradient, AnimationCurve intensityCurve)
    {
        float intensity = intensityCurve.Evaluate(time); // time 시간에 해당하는 값을 보간하여 반환

        // 360도의 0.5면 180도가 나옴. 우리의 0.5는 90도여야 함. 그래서 0.25를 빼주는 것. 
        lightSource.transform.eulerAngles = (time - (lightSource == Sun ? 0.25f : 0.75f)) * noon * 4f;
        lightSource.color = gradient.Evaluate(time);
        lightSource.intensity = intensity;

        GameObject go = lightSource.gameObject;
        if(lightSource.intensity == 0 && go.activeInHierarchy) // 밝기가 완전히 없어지고 하이어라키창에 켜져있으면 꺼주기
        {
            go.SetActive(false);
        }
        else if(lightSource.intensity > 0 && !go.activeInHierarchy)
        {
            go.SetActive(true);
        }
    }
}

 

otherLighting으로 설정하는 것들은 다른 조명들의 세기를 조절하는 것이 아니라, 씬의 환경광과 반사광을 조절해서 어두워진 것처럼 만든다. 

// 씬 전체의 환경광 밝기 조절 (0으로 하면 씬 전체가 어두워짐)
RenderSettings.ambientIntensity = lightingIntensityMultiplier.Evaluate(time);
// 씬 전체의 반사광 강도 조절
RenderSettings.reflectionIntensity = reflectionIntensityMultiplier.Evaluate(time);

만약 Update 함수에서 위 두 줄을 빼고 실행하면 아래와 같이 해가 졌을 때도 환경이 모두 잘보이게 된다. 

좌 : 광조절X, 우 : 조절 O

 

3. 에디터에서 Intensity Curve 키값들 설정해주기 

DayNightCycle 스크립트를 오브젝트에 붙여주고 Sun과 Moon 넣어줌. 그리고 각 조명의 intensity Curve와 Gradient할 Color값을 설정해준다.

  • 그래프에서 우클릭하고 Add Key > 키를 우클릭해서 Edit Key > (time, value)쌍으로 애니메이션의 키가 될 수치 집어 넣음.

Intensity Curve 그래프 만들어주기
Color Gradient 값들 넣어주기

 

반응형