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

这篇具有很好参考价值的文章主要介绍了【程序化天空盒】过程记录01:日月 天空渐变 大气散射。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 日月 SunAndMoon

昼夜的话肯定少不了太阳和月亮,太阳和月亮实现的道理是一样的,只不过是月亮比太阳多了一个需要控制月牙程度(or添加贴图)的细节~

1.1 Sun

太阳的话很简单,直接在shader里实现一个太阳跟随平行光旋转而旋转的样子就行。实现这个效果需要用到Unity内置变量_WorldSpaceLightPos0获取当前平行光的方向,不要被这个参数名字“lightPos”迷惑了,它实际上就是一个归一化的vector(w=0)。接着用Unity内置的distance函数计算当前uv坐标(i.uv.xyz)到上面那个的距离。

如何理解这个“距离”呢?——我们再来复习一遍图形学基础吧:学习齐次坐标时讲到“点与向量的区别”时,例如vector(a, b, c, 0)和point(a, b, c, 1),我们可以把vector看作这个point挪向无穷远处位置。行,那么我们再来看看这个distance计算出来的结果的几何意义是不是就十分简单了——uv坐标越靠近,代表离这个无穷远处的点越近,于是结果越小。

  • 我们需要的是一个实心圆(模拟“日月”),如果只将distance的结果与_SunColor相乘并作为片元着色器的结果输出,主要代码及效果如下:
float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
...
fixed4 col = sun * _SunColor;

程序化天空盒,作品集学习记录,unity,游戏引擎

  • 场景中越靠近远处的“太阳”位置越黑,想要实现一个实心圆就很简单了,补充后代码及效果如下:
float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
float sunDis = 1 - sun / _sunRadius;
...
fixed4 col = sunDis * _SunColor;

程序化天空盒,作品集学习记录,unity,游戏引擎

 为了实现控制最大化,加入了_sunRadius参数以控制“太阳”的大小,选择除法的原因也很简单——太阳越大意味着白色部分越大,意味着disatance()函数计算结果的权重更加分散,所以是除法。

  • 到了这一步你会发现,上图还是缺点什么!

【第一】边界有些模糊,我们想实现的效果是轮廓明显的“日月”,这是因为边界的sunDis数值不够大,导致_sunColor相乘混合的颜色“淡”。如何处理?——简单,直接乘上个合适的倍数就行!

【第二】原有的网格不见了,给人一种黑色“笼罩”整个天空盒的错觉。看到这里你似乎会觉得疑惑:“网格不见了”啥意思?我来举个例子,下面是我将sunDis值分别设置为1,0,-1的效果:

程序化天空盒,作品集学习记录,unity,游戏引擎

程序化天空盒,作品集学习记录,unity,游戏引擎

程序化天空盒,作品集学习记录,unity,游戏引擎

2和3看似都是黑色,其实还是有差别的,他会掩盖网格。而且这个sunDis系数最后是跟类型为Color的_SunColor变量相乘,参考光照计算模型,这里理应将该系数也限制在(0, 1),这里用saturate()就行!

考虑了以上两点后最终的代码:

float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
float sunDis = saturate((1 - sun / _sunRadius) * 50);
...
fixed4 col = sunDis * _SunColor;

最终效果:

程序化天空盒,作品集学习记录,unity,游戏引擎

1.2 Moon 

太阳做完了,到了月亮部分,它俩一个在光的正方向(太阳)一个在反方向(月亮),这个不难理解吧!所以,关于跟随平行光方向的部分,设置跟Sun一样,只是多了一个负号。

这里我计划实现两种月亮的方法,一种是贴上一个真实的月亮图片,另一个是做一个简单的可以控制的月牙形状。

第一种:月牙

另外,由于月亮是有月牙的~就用两个圆相减的形式做出月牙的效果,相减效果采用给uv.x一个偏移值_CrescentOffset的方法实现的。同样,这里也需要注意只要涉及相减的需要给数值规范到(0, 1)才能确保效果的正确。

下面是月亮部分的代码:

//2.Add Moon
float moon = distance(i.uv.xyz, -_WorldSpaceLightPos0);
float moonDis = saturate((1 - moon / _MoonRadius) * 50);
float crescent = distance(float3(i.uv.x + _CrescentOffset, i.uv.yz), -_WorldSpaceLightPos0);
float crescentDis = saturate((1 - crescent / _MoonRadius) * 50);
moonDis = saturate(moonDis - crescentDis);
fixed4 moonN = moonDis * _MoonColor;

最终效果:

程序化天空盒,作品集学习记录,unity,游戏引擎

第二种:月亮贴图

贴图主要问题是解决UV坐标系变换问题,因为如果继续用原始的改变光照方向后月亮贴图会变形的问题,我们希望每个角度贴图形状都是圆圆的(参考日常生活中每个角度的月亮都是圆圆的),那么我们就需要一个建立一个4x4的坐标系变换矩阵去实现。

问题又来了:Unity自带的变换矩阵unity_WorldToLight对于平行光是行不通的,只适用于point/spot/烘焙光,所以这里我们需要自己脚本实现变换矩阵。这里我们不难想到shadowmap里也需要求得光源空间的变换矩阵,可以参考我记录的GAMES202作业1中CalcLightMVP()的实现过程去写出这个变换矩阵,还可以跟着这一篇用Unity实现Shadow Map的博客实现这个变换矩阵,道理都是相通的。

更方便的还可以用Unity自带的transform的worldToLocalMatrix获得当前对象的世界空间到local空间的变换矩阵,给场景中的平行光一个子Camera再获取一下这个变换矩阵就行(后面会补充完整脚本内容和shader部分的内容,这里就先放一个效果)。

效果如下,加上了一点后面会做的渐变天空效果:

程序化天空盒,作品集学习记录,unity,游戏引擎

2 天空主体色 Gradient Sky

1.0版本

完成了日月交替的部分只能说才实现了一小部分,而且天空很单调,为了实现更加酷炫的效果,加点渐变天空颜色。说起渐变,要用上lerp()了!分别给白天天空和晚上天空赋予颜色——基于UV坐标的y 轴值来做天空颜色的渐变,记住还是需要saturate()!最后根据uv坐标(i.uv.y)判断何时昼夜交替。

// 3.gradient sky
fixed3 gradientDay = lerp(_DayBottomColor, _DayTopColor, saturate(i.uv.y));
fixed3 gradientNight = lerp(_NightBottomColor, _NightTopColor, saturate(i.uv.y));
fixed3 gradientSky = lerp(gradientNight, gradientDay, saturate(_WorldSpaceLightPos0.y));

2.0版本

上面的渐变天空简单的lerp做的,很枯燥。参考程序化天空盒实现昼夜变换,我们也来这位大佬的构思思路,做一次分析(毕竟是作品集,所有过程自己实现一遍最好啦!),也天空变化归纳了出来:

程序化天空盒,作品集学习记录,unity,游戏引擎

参考他提出的思路,地平线渐变用worldPos.y控制,但天空的主体颜色用光方的z和y共同控制,关于天空主体色我的理解:

(纠正一下,感觉早晨不是supper blue而是一种偏绿色的蓝色?颜色可以自行调整的)

程序化天空盒,作品集学习记录,unity,游戏引擎

即从早晨开始,早晨(非常蓝)-->中午(正常蓝)-->傍晚(紫色)-->深夜(深蓝色),其中,y控制着白天和晚上,z控制白天三种颜色变换、晚上三种颜色交替

白天:

程序化天空盒,作品集学习记录,unity,游戏引擎

上述思路对应的理解代码为,

// 早午过渡
col = lerp(morningCol, noonCol, smoothstep(0,0.5,z));
// 再把上面的当作午的,进行午傍晚过渡
lerp(col, nightfallCol, smoothstep(0.5,1,z));

同理晚上:

程序化天空盒,作品集学习记录,unity,游戏引擎

// 早晚过渡
col = lerp(morningCol, nightCol, smoothstep(0,0.5,z));
// 再把上面的当作晚的,进行晚和傍晚的过渡
lerp(col, nightfallCol, smoothstep(0.5,1,z));

再优化一下:我想要清晨和傍晚的颜色持续的少一点,白天的天蓝色维持的久一点,这样就需要更改参数,索性直接多给两个参数,来调节一天内清晨和傍晚的持续时间,最终关于天空颜色早晚变化的参数如下:

程序化天空盒,作品集学习记录,unity,游戏引擎

3 地平线渐变

跟参考文章不太一样的是,我把渐变天空分为两个部分:半天空渐变色+范围变化的Bloom,虽然这样比较麻烦(叠加了三层orz),但原神有些画面它就是三种颜色叠加的效果,例如下图傍晚的天空:

程序化天空盒,作品集学习记录,unity,游戏引擎
原神的傍晚天空

索性直接拆成三块做。 

3.1 半天空渐变

半天空渐变色有4种颜色,4个颜色变化的时间刚好跟天空主题渐变色对应,

1 晚上:深蓝色+淡色地平线

早晨:浅蓝色+淡色地平线

中午:天蓝色+浅蓝地平线

傍晚:紫色+淡黄色地平线

程序化天空盒,作品集学习记录,unity,游戏引擎

由于这个是跟主色叠加,是不是应该在天空主体渐变的基础上修改,达到天空主色渐变的感觉:

好,说做就做,以早晨为例,还需要能控制渐变程度等,最后的参数如下:

程序化天空盒,作品集学习记录,unity,游戏引擎

程序化天空盒,作品集学习记录,unity,游戏引擎

整个天空颜色很接近了(斗胆),现在就差地平线附近的Bloom。

3.2 范围变化的Bloom

(做了一下午了,起来活动一下继续,orz,,)

再继续观察:

早->午:红色(小)-->黄色(大)-->白色(小)

傍晚->晚上:黄色(大)-->橙黄色(超大)-->黄色(小)

程序化天空盒,作品集学习记录,unity,游戏引擎

(补充:既然节点4Mie散射开始,那我们把大部分白色的Bloom都交给Mie散射,假设整个发光到节点4就宣告结束。) 

【空缺了一部分思路,这里做得比较着急没有记录,放个对比图吧之后补充】

程序化天空盒,作品集学习记录,unity,游戏引擎

日出日落配上天空颜色变化:

程序化天空盒,作品集学习记录,unity,游戏引擎

程序化天空盒,作品集学习记录,unity,游戏引擎

emmm配色什么的感觉挺脏的,然后bloom那里需要给参数调整的,做的时候随便选的,先继续进行下面的步骤,最后再优化。 

接下来是加上云、和星空银河,放在下一篇文章吧。

我上面实现渐变天空选择的颜色还是照抄参考里的配色。但是!我认为一个优秀的天空盒,配色一定是要有讲究的!配色的实现方法打算参考这篇文章里提到的将配色数据做成数组形式,像动画关键帧那样呈现出来的方法。

3 大气散射

做的时候没有记录过程,作品搞完后会回来补上。

参考

这里是我搜刮遍了各种网站找到的实现动态天空盒的文章,自己在做的过程中也参考了很多,这里罗列出来希望对看到这篇文章的你有所帮助:

风格化的动态天空球 – WalkingFat

Unity日夜循环天空球(Procedural Skybox) - 知乎

Making a Stylized Skybox Shader

Unity 卡通渲染 程序化天空盒 - 知乎

【unity URP】昼夜循环天空球 - 知乎

程序化天空盒实现昼夜变换 - 知乎 (zhihu.com)文章来源地址https://www.toymoban.com/news/detail-799814.html

到了这里,关于【程序化天空盒】过程记录01:日月 天空渐变 大气散射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Unity 使用柏林噪声程序化生成地形

    参考教程链接 项目链接 👇对噪声和柏林噪声不了解的可以看下面这个讲解。 柏林函数简介   简单来说柏林噪声是一种连续的、渐变的噪声,不理解原理也无所谓,unity自带有Mathf.PerlinNoise(X-coordinate,Y-coordinate);我们可以根据这个来制作更有层次性的柏林噪声。你可以把这个

    2024年02月15日
    浏览(41)
  • CityGML程序化建模开源引擎及数据集

    在攻读博士学位期间,我在 3D GIS 研究中遇到了以下缺点: 包含多个细节级别的 CityGML 数据集很少。 不存在程序化生成的 CityGML 格式的数据。 没有免费的程序化建模引擎。 公开可用的 CityGML 模型通常包含大量(拓扑)错误。 推荐:用 NSDT编辑器 快速搭建可编程3D场景 为了解

    2024年02月13日
    浏览(38)
  • 程序化交易接口策略过滤器–九宫格

    不同的程序化交易接口策略适用于不同的市场情况,有些交易策略使用于均值回归,有些则试用于方向明显的时候,有些试用于方向不明显的时候,因此,我们需要根据不同的市场情况,综合考虑方向和波动率,市场成交量来选择合适的交易策略。 本文介绍了一种选择程序化

    2023年04月09日
    浏览(46)
  • 分享股票量化交易程序化模型的设计思路

    一个股票量化交易程序化模型的入市设计往往伴随着设计者的偏好和交易时间框架等。主要分为震荡交易、套利交易以及趋势跟踪等。当然在近些年的发展中,也出现了类似遗传算法、人工智能神经网络等许多种类的系统模型。 但是对于大多数投资者来说,趋势跟踪系统可以

    2024年02月03日
    浏览(59)
  • Three.js程序化3D城市建模【OpenStreetMap】

    对于我在 Howest 的研究项目,我决定构建一个 3D 版本的 Lucas Bebber 的“交互式讲故事的动画地图路径”项目。 我将使用 OSM 中的矢量轮廓来挤出建筑物的形状并将它们添加到 3js 场景中,随后我将对其进行动画处理 推荐:用 NSDT编辑器 快速搭建可编程3D场景 为了使用 Node 和

    2024年02月11日
    浏览(44)
  • 用java去实现程序化广告应该有哪些步骤?

    1. 需求分析和规划 在这一阶段,我们需要详细分析和理解项目需求,并制定相应的规划和计划。这包括以下几个步骤: 项目背景和目标: 理解项目的背景和目标,确定开发的目的和意义。 功能需求分析: 分析用户需求,明确项目需要实现的功能和特性。 技术可行性评估:

    2024年04月10日
    浏览(55)
  • “小程序化”成OA数字化升级突破口

    如果说新冠疫情引发了在线办公需求的激增,那么企业对数字化转型的渴望,则是数字化办公赛道持续火热的根本原因。 2020年新冠疫情爆发,远程办公成为了大部分企业无奈又必然的选择,三年以来,随着疫情的持续蔓延和常态化管控,在线办公逐渐成为刚需,企业对于在

    2024年02月08日
    浏览(40)
  • 程序化交易(二)level2行情数据源接入

    行情在线测试 websocket行情接口 交易在线测试 在线交易接口 官方文档地址 行情交易接口用户文档 注意: 每次分配的服务器地址会发生变化,连接服务前,请务必调用该接口获取最新的服务器地址。 获取服务器: Copy 接口参数: # 参数名 类型 描述 1 market string 市场标志,沪深

    2024年02月05日
    浏览(52)
  • UE5使用Dash插件实现程序化地形场景制作

    目录 0  dash下载后激活 1 初步使用 2  导入bridge的资产路径 3 练习成果 4 参考链接 Dash插件点击蓝色的A,可以使用。 通过输入不同提示命令,来激活不同的功能。 这里需要注意是UAsserts的上一级目录。 实现程序化地形,程序化植被,日光模拟,摄像机视角等功能。 POLYGONFLO

    2024年02月07日
    浏览(40)
  • 股票程序化交易-QMT入门系列(5)-QMT核心接口介绍

    0、前言. 1、QMT前期安装准备 2、QMT中安装python依赖包 3、QMT程序化交易运行机制 4、QMT模型建立、策略运行案例 5、QMT核心接口介绍 6、QMT行情接口介绍 7、QMT交易接口介绍 8、如何实现QMT读取

    2024年01月24日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包