Unity 室外光照

Unity 光照文档:  https://docs.unity3d.com/cn/2022.3/Manual/LightingOverview.html光照

目的:提升游戏体验和视觉效果

Unity 使用详细的光线工作模型来获得更逼真的结果,并使用简化模型来获得更具风格化的结果。

1. 光照概念

        1.1 光照分类

Directional 方向光 : 日光、月光,无限远的光源,不会随距离而衰竭

Spot 探照光: 锥形的方向光,从添加点向一个方向照射,适合模拟:路灯、台灯、手电、舞台灯、车灯等等锥形光源;

Point 点光: 全方向的一个点光源,适合模拟:萤火虫、蜡烛、夜光宝石等

Area 面光: 面光源,不能是实时的,可以模拟一个静态发光面,适合模拟:荧光灯、LED 平面灯 等等

路灯光源的三个关键属性会影响光线:
  • 它的 形状将决定光波发射的 方向。
  • 它的 大小将决定光影响的 区域。
  • 它的 强度(或 强度)将决定这些光波可以传播多远以及它的亮度。
考虑这三个属性:发出光的灯泡很小(尺寸)且呈圆形(形状),但其强度足以照亮那个小区域(强度)。

天空盒 Skybox: 是每个面上都有不同纹理的立方体。

使用天空盒来渲染天空时,Unity 本质上是在将场景放置在天空盒立方体中。Unity 首先渲染天空盒,因此天空总是在背面渲染。使用天空盒执行以下操作:

  • 在场景周围渲染一个天空盒。
  • 配置光照设置来根据天空盒创建逼真的环境光照。
  • 使用天空盒组件覆盖由单个摄像机使用的天空盒。

梯度(渐变、Gradient):种用于创建平滑过渡颜色的工具。在Unity中,使用梯度来定义环境光、材质、粒子效果、UI元素等的颜色变化。在环境光中实现光线渐变视觉效果,仿真霞光、地面色的渐变光照效果。

2. 光照设置

        2.1 Light Explorer (光照资源管理窗口)

在Unity界面 Window -> Rendering -> Light Explorer

光照资源管理窗口 Lights 选项卡

光源设置:Directional Light 室外必备光源,还可以添加多个,提高整体光照效果,夜晚应该降低光照强度

光照类型: 例如 spot, area

Shape : 形状影响光发射的方向

Mode 光照模式: 

  •         烘培光照 Baked: Unity 提前执行光照计算并将结果保存为光照数据,然后在运行时应用
  •         实时光照 Realtime:Unity 在运行时计算光照。需要更高的配置,消耗更多算力
  •         混合光照 Mixed:实时和烘焙的混合

color : 光的颜色很重要,合理使用好光色,可以更好地凸显游戏氛围

Range 光照范围:光在场景中的传播距离。但要受到光源形状的限制,比如 spot light 聚光灯,将值增加到超过该上限,就把不会导致任何进一步的范围增加

Intensity 光照强度: 一般夜晚的光源,在比较符合现实的游戏氛围中,电灯其强度应该设置为 200-600 之间; 蜡烛、火把等前度应该介于 50 -100 之间

Indirect Multiplier 间接光乘数:此光源提供的间接光的强度(在被传感器接收之前多次反弹的光)。

  •         低于1时,间接光在每次从物体反弹时都会变暗。这是真实光照的行为方式,但您可能希望覆盖该行为以实现特定的光照效果。
  •         高于1 ,间接光会随着每次反弹而变亮。这并不自然,但如果您试图照亮场景中的黑暗封闭空间,它会非常有用。
  •         一般默认为1

2.2 Lighting (光源场景设置)窗口

在Unity界面 Window -> Rendering -> Lighting

Scene 场景选项卡

显示有关分配给活动场景光照设置资源的信息。如果没有为活动场景分配光照设置资源,它会显示有关默认 LightingSettings 对象的信息

  • Lighting Settings Asset controls:    新建或选择不同的光照配置文件,将光照设置资源分配给活动(当前)场景
  • Mixed Lighting 混合光照:
    • Baked Indirect 烘焙间接光: 将实时直接光照与烘焙间接光照相结合。它提供实时阴影。此光照模式提供逼真的光照和合理的阴影保真度,适用于中档硬件。
    • Shadowmask 阴影遮罩: 将实时直接照明与烘焙间接照明相结合。它可以为远处提供烘焙阴影游戏对象,并自动将它们与实时阴影混合。它是最现实的,也是最耗费资源的光照模式。您可以使用质量设置来配置其性能和视觉保真度。此照明模式适用于高端或中档硬件。
    • Subtractive 减法: 提供烘焙的直接和间接照明。它只为一个定向光渲染直接实时阴影。此光照模式不提供特别逼真的光照效果,适用于风格化艺术或低端硬件。
  • Lightmapping Settings:
    • Lightmap Resolution 光照贴图解决方案:       指定每单位用于光照贴图的纹素(texel)数。增加此值可提高光照贴图质量,但也会增加烘焙时间。请注意,将该值加倍会使纹素的数量增加四倍,因为它决定了光照贴图的高度和宽度。
    • Lightmap Padding 光照贴图填充:      确定烘焙光照贴图中不同形状之间的间隔(以纹素为单位)。默认值为 2。
    • Max Lightmap Size 最大光照贴图大小:      指定完整光照贴图纹理的大小(以像素为单位),其中包含每个包含的游戏对象的单独区域。默认值为 1024。
    • Lightmap compression 光照贴图压缩:      编辑器用于光照贴图的压缩级别。四个选项:
      • none,低中高质量。      
      • 无:不压缩光照贴图。      
      • 低质量:这可能比正常质量使用更少的内存和存储空间,但也会引入视觉伪影。      
      • 正常质量:这是内存使用和视觉质量之间的良好折衷。      
      • 高质量:比普通质量需要更多的内存和存储空间,但提供更好的视觉效果。
  • Workflow Settings:工作流设置

Environment 环境选项卡

包含相关当前场景的环境光照效果的设置。内容取决于项目使用的渲染管线。

  • Environment(环境):包含与光照相关的设置和控件,这些设置和控件适用于当前场景中的环境光照,例如天空盒、漫射光照和反射
    • Skybox Material    天空盒是一种材质,它出现在场景中的所有其他对象后方,用于模拟天空或其他遥远的背景。使用此属性可选择要用于场景的天空盒。默认值是内置的默认天空盒 (Default Skybox)。
    • Environment Lighting    此部分包含可影响当前场景中的环境光的设置。
    • Environment Reflections    此部分包含反射探针烘焙的全局设置,以及影响全局反射的设置。
  • Other Settings 部分包含雾、光环光晕剪影的设置
    • Fog    在场景中启用或禁用雾效。请注意,此模式无法用于延迟渲染路径。
    • Halo Texture    设置要用于在光源周围绘制光环的纹理。
    • Halo Strength    定义光源周围光环的可见性,值在 0 到 1 之间。
    • Flare Fade Speed    定义最初出现镜头光晕之后从视图中淡出的时间(以秒为单位)。默认情况下,该值设置为 3。
    • Flare Strength    定义光源下镜头光晕的可见性,值在 0 到 1 之间。

Baked Lightmaps 烘焙光照贴图选项卡

此选项卡显示光照贴图为当前场景生成的所有光照贴图的列表,以及光照数据资源。如果项目中未启用烘焙全局光照 (Baked Global Illumination),则此选项卡将为空。

3. 天空盒

天空盒是每个面上都有不同纹理的立方体。使用天空盒来渲染天空时,Unity 本质上是在将场景放置在天空盒立方体中。Unity 首先渲染天空盒,因此天空总是在背面渲染。
使用天空盒执行以下操作:

  • 在场景周围渲染一个天空盒。
  • 配置光照设置来根据天空盒创建逼真的环境光照, 例如场景中的环境光 Ambient lighting 是由天空背景产生。
  • 使用天空盒组件覆盖由单个摄像机使用的天空盒。

3.1 天空盒着色器 SkyBox Shader

 天空盒着色器应用到SkyBox,可以订制skybox,下面4.2,4.3将讲述一个订制的实例

SkyBox Shaders 共有四种,可以分为两大类:

  1. 使用纹理 Textured:
    • 6 Sided 六面:
      从六个单独的纹理生成天空盒。每个纹理代表沿特定世界轴的天空视图。为了说明这一点,想想场景就像在一个立方体里面。每个纹理代表立方体的一个内部面,所有六个组合起来创建一个无缝的环境。 

    • Cubemap 立方体贴图:
      从单个Cubemap Asset生成天空盒。
    • Panoramic 全景:
      将单个 Texture 球形包裹在场景 

    2. 不使用纹理:

              4. Procedural 程序生成,不需要任何输入纹理,而是纯粹从材质中设置的属性生成天空盒。

4. 光照练习

下载项目文件

解压缩文件,在Unity Hub中点击“打开”按键,在Unity中打开项目后在Project窗口中选择 CreativeCore_Lighting -> Scenes,在其右侧窗口中双击 Tutorial Scene_Lighting_Outdoor 文件,如下图所示:

4.1 配置定向光

在 Unity 中,每当创建场景时,它都会附带已添加到层次结构中的定向光;这盏灯的作用就像真实世界的太阳或月亮。

  • 新建一个定向光并放置在场景中的任何位置,并且不会影响投射的光线,需要显式更改光线的方向才能在场景中更改它。
  • 在Hierarchy(层次结构)窗口中点击 Lighting, 在展开的目录中点击 Directonal Light, 在Scene(场景)窗口中看到该游戏物体

  • 尝试将定向光移动到场景中的不同位置:更近或更远。这些变化引起的光照没有差异 - 与真实太阳不同,定向光的位置不会改变光的方向。
  • 使用旋转工具 更改定向光的方向。注意到场景中已有的天空会对其位置变化做出响应。 
  • 在上图右侧Inspector 窗口并在 Light 组件中找到Color属性(上图中红色箭头所指)。
  • 选择颜色框以打开颜色选择器窗口并选择不同的色调。注意圆形剧场的结构——这是最容易看到颜色变化影响的地方。这可以帮助营造场景气氛。

这种效果可能相对微妙,并且不一定适合场景当前配置的方式。如果场景设置在深夜而不是清晨,神秘的紫色或不祥的红色可能会产生更大的影响。现在可以随意尝试不同的颜色,但在本教程结束时您将有机会更多地调整定向光。

4.2 配置Skybox

1. 新建1个skybox material

在右侧 Project 窗口中 打开窗口 Assets > CreativeCore-Lighting > Materials,然后鼠标放在Materials上点击鼠标右键弹出菜单,选择 Create -> Material, 新建一个材质 Material

2. 更新材质名字为 CustomSky, 在右侧Inspector 窗口点击 Shader,弹出下拉菜单,选择SkyBox,在接下来的窗口中选择 Procedural 用程序生成skybox 材质

3. 将上述新建的skybox着色器应用在当前场景的sky。

点击Unity主界面 Window > Rendering > LIghting,打开 (2.2的)Lighting设置窗口,可以将该窗口移到右侧 并嵌入到 Inspector窗口右侧

4. 点击Lighting窗口中 Skybox Material 右侧的按键,在弹出的窗口中输入CustomSky,选择该新建的skybox material,更新原有的 Default-Skybox material

5. 在scene窗口中显示skybox (如果skybox已经存在,即天空是蓝色的,不是灰色的,可以省略该步骤)

6.再次在Project窗口中点击 Assets > CreativeCore-Lighting > Materials 在打开的窗口中选择刚才新建的CustomSky 材质,在右侧的Inspect窗口中,更改各个参数数值,看场景中Sky的变化,例如更改太阳大小尺寸,然后在Scene窗口中旋转场景看天空中太阳尺寸的变化。再尝试更改其他的参数,看场景中环境变化。

4.3 设计日夜交替

设计1个日夜交替的场景,完成下述任务:

  • 通过构建1个TimeController空游戏物件;
  • 绑定编写的脚本script文件,控制上述CutomSky天空盒的材质参数,实现天空白天与黑夜的交替显示;
  • 同时构建1个TextMeshPro 的UI控件,实时显示当前的时间。

1. 点击Unity主界面 GameObject > UI > Text - TextMeshPro,在场景中添加1个文字控件 。首次使用TextMeshPro 会弹出窗口 TMP Import 导入该控件资源。

2. 在 Project 窗口中增加了如下信息,更改 Text(TMP) 为 TimeText

3. 鼠标放在上述 Canvas上,点击右键,在弹出菜单中点击“Create Empty”在该目录下构建1个空游戏物件。

4. 更改该GameObject 名称为 TimeController, 在点击 "Add Compontent", 在该 TimeController文件下添加1个脚本文件, 也取名为TimeController。

5. 在Inspector窗口中,新增了TimeController (Script),点击右侧的 三点按键,在弹出菜单中选择 Edit Script

6. 该script将在Visual Studio 2022中打开,供代码编辑

7. 更新代码如下

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

public class TimeController : MonoBehaviour
{
    //设置1帧时间转换为1秒的乘数
    [SerializeField]
    private float timeMultiplier;

    //设置一天开始的时间
    [SerializeField]
    private float startHour;

    //设置显示时间的text物件
    [SerializeField]
    private TMPro.TextMeshProUGUI timeText;

    //当前时刻时间
    private DateTime currentTime;

    //场景中的定向光游戏物件
    [SerializeField]
    private Light sunLight;

    //日出时间 浮点变量
    [SerializeField]
    private float sunriseHour;
    //日落时间 浮点变量
    [SerializeField]
    private float sunsetHour;

    //日出时间值 timespan变量
    private TimeSpan sunriseTime;
    //日落时间 timespan变量
    private TimeSpan sunsetTime;

    // Start is called before the first frame update
    void Start()
    {
        //初始化当前时间
        currentTime = DateTime.Now.Date + TimeSpan.FromHours(startHour);
        //初始化日出时间
        sunriseTime = TimeSpan.FromHours(sunriseHour);
        //初始化日落时间
        sunsetTime = TimeSpan.FromHours(sunsetHour);

        Debug.Log("currentTime 0: "+ currentTime.ToString("HH:mm"));
    }

    // Update is called once per frame
    void Update()
    {
        UpdateTimeOfDay();
        RotateSunLight();
    }

    private void UpdateTimeOfDay()
    {
        //当前时间的累计,程序运行时间deltaTime (1帧时间大概0.004秒) 乘以 timeMultiplier (设置250) = 1 秒
        currentTime = currentTime.AddSeconds(Time.deltaTime * timeMultiplier);
        if (timeText != null)
        {
            timeText.text = currentTime.ToString("HH:mm");
        }
        Debug.Log("currentTime: " + currentTime.ToString("HH:mm"));
        Debug.Log("deltaTime: " + Time.deltaTime.ToString());
    }
    //旋转定向光
    private void RotateSunLight()
    {
        float sunLightRotation =0.0f;
        //如果当前时间是白天
        if (currentTime.TimeOfDay > sunriseTime && currentTime.TimeOfDay < sunsetTime)
        {
            //日升到日落的时间差
            TimeSpan sunriseToSunsetDuration = CalculateTimeDifference(sunriseTime, sunsetTime);
            //日升到当前时间的时间差
            TimeSpan timSinceSunrise = CalculateTimeDifference(sunriseTime, currentTime.TimeOfDay);
            //当前时间差和总白天时间的比率
            double percentage = timSinceSunrise.TotalMinutes / sunriseToSunsetDuration.TotalMinutes;
            //计算定向光的角度值
            sunLightRotation = Mathf.Lerp(0, 180, (float)percentage);

        }
        else
        {
            //日落到日升的时间差
            TimeSpan sunsetToSunriseDuration = CalculateTimeDifference(sunsetTime, sunriseTime);
            //日落到当前时间的时间差
            TimeSpan timeSinceSunset = CalculateTimeDifference(sunsetTime, currentTime.TimeOfDay);
            //当前时间差和总黑夜时间的比率
            double percentage = timeSinceSunset.TotalMinutes / sunsetToSunriseDuration.TotalMinutes;
            //计算定向光的角度值
            sunLightRotation = Mathf.Lerp(180, 360, (float)percentage);
            
        }

        Debug.Log("rotation: " + sunLightRotation.ToString());
        //设置定向光的角度值
        sunLight.transform.rotation = Quaternion.AngleAxis(sunLightRotation, Vector3.right);
    }

    //计算fromTime 和 toTime 之间的时间差
    private TimeSpan CalculateTimeDifference(TimeSpan fromTime, TimeSpan toTime)
    {
        TimeSpan diff = toTime - fromTime;

        //如果时间差是负值,加上24小时,新的1天
        if (diff.TotalSeconds < 0)
        {
            diff += TimeSpan.FromHours(24);
        }
        return diff;
    }
}
 

代码解释视频: 日夜更替 日夜交替-2 日夜更替-1

4.4 添加路灯

1. 场景中添加路灯,点击 Project 窗口中 Assets > Prefabs, 可以看到项目自带的路灯,鼠标点击其中1个路灯,例如StreetLamp,拖拽到左侧的 Hierarchy窗口中,这时场景中会显示该路灯,调整路灯在场景中的位置,也可以在拖拽其他的灯到场景中

2. 依次共添加 4 个路灯,可以如图所示:

3. 更改点光源光照生成方式,由 Mixed 改为 Baked。 点击一个路灯,例如下图中 StreeLamp(2),在下拉目录中选择Spot Light,在右边 Inspector 窗口中看到 Light > Genenal > Mode 中为Mixed,点击该下拉控件,选择Baked

可以尝试在Scene窗口中移动上述选择的路灯 StreeLamp(2),可以看到灯光照射区域随着路灯的移动而移动,表明该灯照区域是系统(实时)生成的,改为Baked的话,则灯照区域会保留 在原地,不随着灯的位置而改变。

虽然上述操作已经改 Mixed 为 Baked,但场景中 灯照区域还是 mixed,这是因为还没有对场景中灯光进行重新 生成。

4. 打开lighting窗口,点击unity界面上Window菜单,选择Rendering > lighting

5.在Lighting窗口中选择Scene选项卡,在页面最下端点击 "Generate Lighting" 按键,将场景中点光源光照区域进行烘焙,系统需要一段时间烘焙灯光区域。

5. 当生成结束后,可以再尝试在Scene窗口中移动上述选择的路灯 StreeLamp(2),可以看到灯光照射区域依然保留 在原地,不随着灯的位置而改变。

4.5  路灯开关 

1. 添加 StreetLampLight tag。 选择上述 StreetLamp(2)目录中的 SpotLgith, 在右侧Inspector窗口中 Tag行点击 Untagged下拉窗口,选择 Add Tag

在弹出的界面中,Tags下方的 “+” 按键

在弹出窗口中输入 “StreetLampLight”,在点击下方 Save 按键

再回到原来Unity 界面,将Spot Light 的Tag改为StreetLampLight

2. 再次在visual stuidio 打开上述TimeController 脚本。 点击TimeController,在右侧Inspector窗口中,点击Timecontroller脚本右侧的三点空间,在弹出窗口中选择 Edit Script

3. 在程序中加入如下黑体代码,

public class TimeController : MonoBehaviour
{
    [SerializeField]
    private bool streetLampLightEnabled;

    [SerializeField]
    private float timeMultiplier;

。。。。

  private void RotateSunLight()
  {
      float sunLightRotation;
      if (currentTime.TimeOfDay > sunriseTime && currentTime.TimeOfDay < sunsetTime)
      {
          TimeSpan sunriseToSunsetDuration = CalculateTimeDifference(sunriseTime, sunsetTime);
          TimeSpan timSinceSunrise = CalculateTimeDifference(sunriseTime, currentTime.TimeOfDay);

          double percentage = timSinceSunrise.TotalMinutes / sunriseToSunsetDuration.TotalMinutes;

          sunLightRotation = Mathf.Lerp(0, 180, (float)percentage);

          if (streetLampLightEnabled)
          {
              GameObject[] streetLamps = GameObject.FindGameObjectsWithTag("StreetLampLight");
              foreach (GameObject streetLamp in streetLamps)
              {
                  Light streetLampLight = streetLamp.GetComponent<Light>();
                  if (streetLampLight != null)
                  {
                      streetLampLight.enabled = false;
                  }
              }
          }

      }
      else
      {
          TimeSpan sunsetToSunriseDuration = CalculateTimeDifference(sunsetTime, sunriseTime);
          TimeSpan timeSinceSunset = CalculateTimeDifference(sunsetTime, currentTime.TimeOfDay);

          double percentage = timeSinceSunset.TotalMinutes / sunsetToSunriseDuration.TotalMinutes;

          sunLightRotation = Mathf.Lerp(180, 360, (float)percentage);
          if (streetLampLightEnabled)
          {
              GameObject[] streetLamps = GameObject.FindGameObjectsWithTag("StreetLampLight");
              foreach (GameObject streetLamp in streetLamps)
              {
                  Light streetLampLight = streetLamp.GetComponent<Light>();
                  if (streetLampLight != null)
                  {
                      streetLampLight.enabled = true;
                  }
              }
          }

      }

      sunLight.transform.rotation = Quaternion.AngleAxis(sunLightRotation, Vector3.right);
  }

。。。。

4. 返回Unity界面,等编译完成后,点击TimeController脚本下方 Street lamp Light Enable 边的框,打钩

5.点击界面正上方的 play  (三角形) 按键,查看上述街灯 StreetLamp(2)是否在白天(6点后)关闭,晚上(18点后)打开

注意:这个灯没有改变 (为什么?)

6. 将另外三个StreetLight 目录下的SpotLight的 tag 改为 “StreetLampLight”,例如下图所示:

7.再次点击界面正上方的 play  (三角形) 按键,查看上述新的三个街灯 (除了StreetLamp(2))是否在白天(6点后)关闭,晚上(18点后)打开使得日夜交替的时候,路灯在白天关闭,黑夜点亮!

注意:这三灯开关会随着时间改变 (为什么?)

代码解释视频: 日夜更替日夜更替-3

4.6 配置路灯

在场景中完成如下的路灯配置:

  • 添加红色墙灯

1. 点击 Project窗口在 Assets > Creativecore_Lighting > Prefabs  的窗口中选择 LongLight, 拖拽到右边Scene串口,放在一个墙壁上,注意初始的灯光是青蓝色的,在Hierarchy窗口中会自动增添该墙灯名字 LongLight

2. 点击上述 LongLight目录下的 LongLight,在右侧Inspector中,Materials下Element0中为BlueEmission, 点击右侧的圈点控件,在弹出窗口中,输入Red,在窗口中双击选择 RedEmission,这样改蓝光为红光,

    

3. 在Hierarchy窗口中,点击原先LongLight目录下的 Area Light,在右侧Inspector中,点击Emission下的Color行右端的蓝色框,在弹出颜色窗口中选择红色光

 

4. 打开lighting窗口,点击unity界面上Window菜单,选择Rendering > lighting

5.在Lighting窗口中选择Scene选项卡,在页面最下端点击 "Generate Lighting" 按键,将场景中新加入的红色墙灯生成红色灯照区域(注意,没有生成的红色强灯,在游戏场景中是不会显示红灯的,还是蓝灯,虽然在Scene场景中看到红灯),系统需要一段时间生成灯光

生成红色光照后的场景如下图所示:

作业1

添加1个绿色墙灯,如图所示:

Unity 教学课程:光照练习

 B站教学课程: 【unity2022入门教程】200-技术美术入门系列-20-光照设置_哔哩哔哩_bilibili

  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值