美文网首页Unity商店资源推广
TOD的云层渲染和Flare遮挡

TOD的云层渲染和Flare遮挡

作者: 恶毒的狗 | 来源:发表于2020-04-17 10:37 被阅读0次

关于TOD

前项目在模仿塞尔达的昼夜变换效果时用过 Time Of Day 这个Unity插件。

本文记录一下 TOD 的云层渲染方式,以及如何让 TOD 的云层遮挡太阳光的 Flare

TOD渲染顺序

image

以上图的白天为例,TOD的主要渲染顺序如下:

  1. 绘制太阳 (Background+30)
  2. 绘制大气层 (Background+50)
  3. 绘制云层 (Geometry+530)

其中,太阳和大气层都是实体渲染,按照实体渲染从近往远的优化策略,这里 RenderQueue 放在 Background 似乎不太合理,我们游戏中会把他们的渲染顺序调整到 Geometry 的后面。

关于太阳和大气层的渲染,特别是大气层的渲染,内容还不少,日后慢慢写,本文主要是关于云层渲染的。

TOD的云层渲染

大气层的模型是一个球面,而云层的模型是一个半球面,因为云层不会出现在地平线之下:

image

云层渲染的基本原理比较简单,就是根据一张密度图计算云层的形状,贴在这个半球面上,然后和大气层做Alpha混合。

作者在这个插件的主页说这个云层是 Semi-volumetric 的,从代码上看,这里的半体积其实就是在 yz 两个方向计算云的密度,这样计算很快,虽然不是真正的 体积云,但是效果不错,移动设备也能跑得动。

云层的密度图

云层的形状主要根据作者提供的一张密度图来计算,密度图的4个通道分别是不同频率的噪声图,如下:

image

在介绍密度计算之前,我们首先需要处理好半球面上的点到密度图的UV映射问题。

云层的UV计算

根据 TOD 的实现机制,摄像机刚好位于球面的中心,我们可以用模型空间下 归一化viewDir 来映射密度图的纹理坐标。

这里 viewDir 计算方式如下:

o.viewDir  = normalize(v.vertex.xyz);

考虑下面这种最简单的映射方式:用 viewDir 的水平面 XZ坐标 直接映射纹理的 UV

image

可以看到,云层越接近水平线,拉伸的就越厉害,因为均匀变化的水平坐标XZ对应的球面跨度变化是不均匀的。

要得到正确的结果,我们可以参考 这篇文章 来做球面点到纹理二维坐标的转换,不过作者用了一个计算量更小的方式:

inline float3 CloudPosition(float3 viewDir, float3 offset)
{
    float mult = 1.0 / lerp(0.1, 1.0, viewDir.y);
    return (float3(viewDir.x * mult + offset.x, 0, viewDir.z * mult + offset.z)) / TOD_CloudSize;
}

这里就是把 viewDir.y 考虑进去,这个值越小越接近水平线,XZ 平面上的跨度就越大,效果如下:

image

云层的密度计算

正确计算UV后,我们就可以在像素着色器计算密度了。

这里先不考虑N层噪声的叠加,我们看一下一层噪声的代码:

inline half3 CloudLayerDensity(sampler2D densityTex, float4 uv, float3 viewDir)
{
    half3 density = 0;
    half4 n = tex2D(densityTex, uv.xy);

    // Density when marching in up direction
    density.y += n.r;

    // Density when marching in view direction
    density.z += n.r;

    // Coverage
    density.yz = (density.yz - TOD_CloudCoverage) * half2(TOD_CloudAttenuation, TOD_CloudDensity);

    // Opacity
    density.x = saturate(density.z);

    return density;
}

这里 yz 两个方向的密度都取密度图的R通道,TOD_CloudCoverage 用于裁剪云朵的范围,TOD_CloudDensity 可以控制云朵边缘的透明程度,TOD_CloudAttenuation 可以控制云朵的颜色衰减。

云层的颜色计算

得到密度后,云层的颜色计算代码如下:

inline half4 CloudLayerColor(sampler2D densityTex, float4 uv, float4 color, float3 viewDir, float3 lightDir, float3 lightCol)
{
    half3 density = CloudLayerDensity(densityTex, uv, viewDir);

    half4 res = 0;
    res.a = density.x;
    res.rgb = 1.0 - density.y;

    res *= color;

    return res;
}

代码很简单,不啰嗦。

云层的渲染分级

上面的代码只是云层最基础的计算,TOD 针对云层的渲染质量分了三级:

  • TOD_CloudQualityType.Low
    • 一层噪声
  • TOD_CloudQualityType.Medium
    • 四层噪声叠加
  • TOD_CloudQualityType.High
    • 四层噪声叠加
    • 米氏散射叠加

这里就不贴代码了,有兴趣的话可以去支持一下作者。

Flare遮挡

下面回到项目中实际遇到的问题,如下图所示,太阳其实已经被云层遮挡了,但是 Flare 还是显示了出来:

image

要解决这个问题其实也简单,首先我们需要定义自己的 LensFlare 的渲染,如下图:

image

然后,在像素着色器部分,我们需要计算出太阳所在位置的云密度,进而计算出 影衰减 并应用到 Flare 上,主要代码如下:

half4 frag (v2f i) : SV_Target
{
    half4 texColor = tex2D(_FlareTexture, i.uv);

    float3 skyPos = normalize(mul((float3x3)TOD_World2Sky, TOD_SunWorldPos));
    float4 cloudUV = CloudUV(skyPos);
    float cloudShadowAtten = TOD_CloudOpacity * CloudShadow(TOD_CloudTexture, cloudUV);
    cloudShadowAtten = 1 - cloudShadowAtten;

    texColor.rgb = texColor.rgb * cloudShadowAtten;
    return texColor * i.color;
}

最后放一张动图:

image

个人主页

本文的个人主页链接:https://baddogzz.github.io/2020/04/16/Tod-Cloud/

好了,拜拜!

相关文章

  • TOD的云层渲染和Flare遮挡

    关于TOD 前项目在模仿塞尔达的昼夜变换效果时用过 Time Of Day 这个Unity插件。 本文记录一下 T...

  • 心念:云层遮挡不住天空

    或游泳于湖滨 将眼睛望着城市与山岩 但见张着帆的船儿升起 但当一个生活问题太小 明丽的天空里 也许因为我们两个生命...

  • 渲染优化-遮挡剔除

    相机视野范围外的游戏物体不显示直接用Unity的遮挡剔除组件Occlusion Culling即可 步骤:1.场景...

  • 遮挡显示效果

    GitHub项目地址 遮挡显示的原理:使用两个Pass,一个Pass渲染被遮挡的部分,另一个Pass正常渲染。(1...

  • flare_flutter动画动效

    导入Flare_Flutter包 打开pubspec.yaml, 并导入Flare_Flutter包. 在term...

  • 火眼的FLARE VM发行版

    来源:https://github.com/fireeye/flare-vm 你也可以使用FLARE VM发行版自...

  • Unity Occlusion Culling Sumup

    意义 遮挡剔除,当一个物体被其他物体遮挡住而不在摄像机的可视范围内时不对其进行渲染。 不同于视锥剔除(只是不渲染摄...

  • TOD为锚点,龙湖挑战“能力者”的游戏

    [摘要] 从对TOD模式的摸索到落地,龙湖倾注了大量的时间和精力。截至目前,龙湖已经开业的TOD商业项目18个,...

  • 2020-11-06

    tod,

  • 【六十四,高级OpenGL-01深度测试】

    深度测试 深度测试(Depth Buffer)防止被遮挡住的面渲染遮挡面的前面,它由窗口自动创建,深度值存储为16...

网友评论

    本文标题:TOD的云层渲染和Flare遮挡

    本文链接:https://www.haomeiwen.com/subject/boqevhtx.html