【Unity大气渲染】Unity Shader中实现大气散射(半成品)

这篇具有很好参考价值的文章主要介绍了【Unity大气渲染】Unity Shader中实现大气散射(半成品)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

这是之前在做天空盒的时候同步写的分析博客,结果后面写到一半就忘了继续了,这里先贴出当时写的半成品,有小伙伴问我怎么做的,这里只能尽力把之前的半成品先放出来了(写得很乱,勿怪orz),,后面有机会会完善好的!希望能帮到大家~

前置知识学习

【Unity大气渲染】关于单次大气散射的理论知识

关于卡通渲染的大气散射

因为我想实现的是跟Unity 卡通渲染 程序化天空盒 昼夜变化,而作者实现过程的文章Unity 卡通渲染 程序化天空盒里说了只是想实现一个日出日落的效果,大概做了如下两点简化:

  • 只计算了Mie散射
  • 光学距离部分只计算了,省去了计算

既然不是基于物理的,那【Unity大气散射】GAMES104:3A中如何实现大气散射里整理的LUT优化方式等等内容就派不上用场了,但也无妨!多了一次学习~

那么接下来计算会尽量参考着这两点去做~ 很大部分的过程参考【实战】从零实现一套完整单次大气散射_四 - 知乎

分析原神的日出

截图来自【原神】好美,原神一天中天空的变化_哔哩哔哩_bilibili

早晨,是地平线的颜色Bloom超突出,伴随着缓缓升起的Mie散射的日出效果: 

unity 大气散射,作品集学习记录,unity,游戏引擎

随着太阳升起,地平线Bloom褪去,留下明显的Mie散射: 

unity 大气散射,作品集学习记录,unity,游戏引擎

日出结束,进入白天时间,太阳始终伴随着一个炫光(猜测是直接叠加了一个炫光图案),加上有随太阳高度角变化的镜头光晕效果: 

unity 大气散射,作品集学习记录,unity,游戏引擎

关于地平线Bloom和太阳炫光、镜头光晕部分这里不提,先实现如此的Mie散射。

1 整体思路

我们需要模拟出人站在地面上看向天空的过程,其实就是人眼发出射线与天空相交的过程,这个过程还须判断是否被物体挡住,挡住了返回黑色;没挡住就调用一个单次散射函数,返回散射的值。

1.2 构建坐标系

  • 首先要有一个明确的坐标系:这里将地球顶部作为世界原点建立坐标系,换句话来说,就按照Unity的世界坐标就行!
  • 人眼此时就是A了,那么在Unity中相机的位置就是A的世界坐标,从A点出发发出射线与天空相交于点B,这时射线AB就是整个模拟过程中的“视线”

下图是解释图,我觉得画的不错hhh

unity 大气散射,作品集学习记录,unity,游戏引擎

1.2 函数1:射线与球体求交

数学原理没什么好说的,随便找了个解释原理的文章:

射线与球体/三角面片求交、重心坐标、插值_csu_xiji的博客-CSDN博客_射线求交

函数返回值

返回的是±t,rayOrigin+t*rayDir就能得到两个交点啦。

//-------------------------------------
// RaySphereIntersection
//-------------------------------------
float2 RaySphereIntersection(float3 rayOrigin, float3 rayDir, float3 sphereCenter, float sphereRadius)
{
    rayOrigin -= sphereCenter;
    float a = dot(rayDir, rayDir);
    float b = 2.0 * dot(rayOrigin, rayDir);
    float c = dot(rayOrigin, rayOrigin) - (sphereRadius * sphereRadius);
    float d = b * b - 4 * a * c;
    if (d < 0)
    {
        return -1;
    }
    else
    {
        d = sqrt(d);
        return float2(-b - d, -b + d) / (2 * a);
    }
}

1.3 计算的部分

就是主要的单次散射函数,主要有两个关键:

  • 计算

2 计算T(PA)

参考开头的简化方法,我们不计算,那么整体就是按照下式计算了!其中,海平面的散射系数是已知的,相位函数和光学距离(累加相对大气密度)都需要计算。

unity 大气散射,作品集学习记录,unity,游戏引擎

2.1 函数2:计算大气密度

//---------------------------------------------------------------------------
// GetAtmosphereDensity
//---------------------------------------------------------------------------
void GetAtmosphereDensity(float3 position, float3 planetCenter, float3 lightDir, out float dpa, out float dpc)
{
    // ρ(h)= exp(-h/H)
    float height = length(position - planetCenter) - _PlanetRadius;
    dpa = exp(-height / _DensityScaleHeight);

    // we don't computer the D(PC)
    dpc = 0;
}

其中,_DensityScaleHeight为大气厚度。

2.2 函数3:相位函数

//---------------------------------------------------------------------------
// ApplyPhaseFunction
//---------------------------------------------------------------------------
void ApplyPhaseFunction(inout float scatterMie, float cosAngle)
{
    // only Mie
    float g = _MieG;
    float g2 = g * g;
    float phase = (1.0 / (4.0 * PI)) * ((3.0 * (1.0 - g2)) / (2.0 * (2.0 + g2))) * ((1 + cosAngle * cosAngle) / (pow((1 + g2 - 2 * g * cosAngle), 3.0 / 2.0)));
    scatterMie *= phase;
}

2.3 函数3:计算总散射

//---------------------------------------------------------------------------
// IntegrateInscattering
//---------------------------------------------------------------------------
float4 IntegrateInscattering(float3 rayStart, float3 rayDir, float rayLength, float3 planetCenter, float3 lightDir, float sampleCount)
{
    float3 stepVector = rayDir * (rayLength / sampleCount);
    float stepSize = length(stepVector);

    float2 prevDPA = 0;
    float prevTransmittance = 0;

    float densityPA = 0;
    float densityCP = 0;
    float localDPA = 0;

    float scatterMie = 0;

    GetAtmosphereDensity(rayStart, planetCenter, lightDir, localDPA, densityCP);

    densityPA += localDPA * stepSize;
    prevDPA = localDPA;

    // local Inscattering, densityCP=0
    float Transmittance = exp(-(densityCP + densityPA) * _ExtinctionM) * localDPA;
    prevTransmittance = Transmittance;

    [loop]
    for (float i = 1.0; i < sampleCount; i += 1.0)
    {
        float3 p = rayStart + stepVector * i;
        GetAtmosphereDensity(p, planetCenter, lightDir, localDPA, densityCP);
        densityPA += (prevDPA + localDPA) * (stepSize / 2.0);        
        
        Transmittance = exp(-(densityCP + densityPA) * _ExtinctionM) * localDPA;

        scatterMie += (prevTransmittance + Transmittance) * stepSize / 2;

        prevTransmittance = Transmittance;
        prevDPA = densityPA;
    }
    // phase function
    ApplyPhaseFunction(scatterMie, dot(rayDir, -lightDir.xyz));

    float3 lightInscatter = _ScatteringM * scatterMie;

    return float4(lightInscatter, 1);
}

其中,为了方便用户调试,cpp里对于Mie散射的S项和T项分别提供可控参数MieScatterCoef和MieExtinctionCoef:

Vector4 MieSct = new Vector4(2.0f, 2.0f, 2.0f, 0.0f) * 0.00001f;

_ExtinctionM = MieSct * MieExtinctionCoef;
_ScatteringM = MieSct * MieScatterCoef;

也就是_ExtinctionM是计算所取的S项海平面处的散射系数,_ScatteringM是计算所取的M项海平面处的散射系数,都是由cpp直接传入,MieSct取值参考:

unity 大气散射,作品集学习记录,unity,游戏引擎文章来源地址https://www.toymoban.com/news/detail-719794.html

1.1

到了这里,关于【Unity大气渲染】Unity Shader中实现大气散射(半成品)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【程序化天空盒】过程记录01:日月 天空渐变 大气散射

    昼夜的话肯定少不了太阳和月亮,太阳和月亮实现的道理是一样的,只不过是月亮比太阳多了一个需要控制月牙程度(or添加贴图)的细节~ 太阳的话很简单,直接在shader里实现一个太阳跟随平行光旋转而旋转的样子就行。实现这个效果需要用到Unity内置变量 _WorldSpaceLightPos0

    2024年01月18日
    浏览(43)
  • Unity中Shader裁剪空间推导(在Shader中实现)

    我们在上一篇文章中,进行了正交相机视图空间下转化到裁剪空间下的矩阵推导。 Unity中Shader裁剪空间推导(正交相机到裁剪空间的转化矩阵) 我们在这篇文章中,在Unity的Shader中实现一下。 OpenGL下: [ 2 w 0 0 0 0 2 h 0 0 0 0 2 n − f n + f n − f 0 0 0 1 ] begin{bmatrix} frac{2}{w} 0 0 0

    2024年02月03日
    浏览(40)
  • Unity中Shader观察空间推导(在Shader中实现)

    在上篇文章中,我们是实现了Shader中的观察空间推导。 Unity中Shader观察空间推导 我们在这篇文章中,根据上篇文章的推导,在Shader中实现观察空间矩阵的推导。 P view = [W view ] * P world P view = [V world ] -1 * P world P view = [V world ] T * P world 在属性面板定义测试使用到的 摄像机坐标

    2024年01月24日
    浏览(39)
  • 【Unity Shader】Unity前向渲染

    ForwardBase Pass(优先渲染),渲染一个逐像素平行光和所有的顶点/球面调和光,阴影只和平行光有关系,那阴影应该是这个Pass中实现的 ForwardAdd Pass(需要和Base配合使用,否则不生效),渲染剩余全部逐像素灯光 Unity会根据场景中各个光源的设置以及这些光源对物体的影响程

    2024年02月08日
    浏览(59)
  • 在 Substance Painter中实现Unity Standard Shader

    由于有需要在Substance Painter中显示什么样的效果,在Unity就要显示什么样的效果的需求,最近研究了几天,总算在Substance Painter中实现Unity standard的材质的渲染效果。具体效果如下: 在Unity中: Substance Painter中: 相识度能够达到百分之八九十吧。主要是Unity的项目使用的是Gamm

    2024年02月08日
    浏览(40)
  • Unity中Shader编译目标渲染器

    Unity中Shader编译到目标渲染器 #pragma only_renderers 仅编译指定平台的Shader d3d11 - Direct3D 11/12 glcore - OpenGL 3.x/4.x gles - OpenGL ES 2.0 gles3 - OpenGL ES 3.x metal - iOS/Mac Metal vulkan - Vulkan d3d11_9x - Direct3D 11 9.x功能级别,通常在WSA平台上使用 xboxone - Xbox One ps4 - PlayStation 4 psp2 - PlayStation Vita n3ds -

    2024年02月05日
    浏览(53)
  • Unity shader 入门之渲染管线一、总览

     如下示意图 应用阶段(ApplicationStage):准备场景信息(视景体,摄像机参数)、粗粒度剔除、定义每个模型的渲染命令(材质,shader)——由开发者定义,不做讨论。 几何阶段(GemetryStage):顶点着色器、曲面细分着色器、几何着色器、裁剪、屏幕映射; 光栅化阶段(Rasterizer

    2024年02月11日
    浏览(49)
  • 【unity shader】水体渲染基础-水下透视效果

    接下来是水体渲染基础的最后一篇,通过水面看到水下的物体,并呈现深度效果。 我们直接搭一个小场景。 增加水面,赋予uv变形的水面材质,并增加透明度的设置。 水体会吸收光线,所以真实的水体并不是完全透明的。此外,水体对不同频率的光吸收率不同,蓝光被吸收

    2024年03月14日
    浏览(56)
  • Unity大面积草地渲染——1、Shader控制一棵草的渲染

    目录 1、Shader控制一棵草的渲染 2、草地的动态交互 3、使用GPUInstancing渲染大面积的草 4、对大面积草地进行区域剔除和显示等级设置 大家好,我是阿赵。 这里开始讲大面积草地渲染的第一个部分,一棵草的渲染。按照惯例,完整shader在最后。前面是原理的介绍。 这里我自己

    2024年02月12日
    浏览(47)
  • unity build-in 渲染管线升级urp渲染 shader篇

            由于工作原因需要对项目进行升级,从build-in渲染管线升级到urp渲染管线,我自己对应的unity版本是2018.版本升级到2021.3.2版本,由于最近几年unity版本升级比较快,个体版本差异有所不同,如遇与版本不一致问题敬请谅解。以下是根据官网等系列网站整理的内容

    2023年04月16日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包