计算uv坐标上天空球上的坐标与_WorldSpaceLightPos0间的距离

计算uv坐标上天空球上的坐标与_WorldSpaceLightPos0间的距离

本节实现Unity日夜循环天空球♥(´∀`)人

unity 天空盒动态变化_unity数值平滑变化_unity 绘制包围盒

概述

Unity中有两种天空盒,一种是纹理类(6面、立方体贴图、全景),另一种是程序类。本文实现了程序化天空盒(其实就是100%纯手写的天空盒=-=)

本文中的天空盒主要参考了小黄人的分享(日常告白→

做吧,根据你的需要做魔法改变,和时间系统相关联,repo在这里("·ω·)"→

天空盒设置

确保相机中的Clear Flags设置为天空盒模式,然后将天空盒组件挂在任意物体下,并添加使用天空盒着色器的材质。

太阳和月亮图画

Unity 内置变量 _WorldSpaceLightPos0 存储定向光的方向。这样就可以通过改变定向光的旋转来旋转天空球unity 天空盒动态变化,形成昼夜效果。

首先,光所指向的正负方向就是我们画太阳和月亮的地方!

计算uv坐标上天空球体上的坐标与_WorldSpaceLightPos0的距离,根据距离画出这个值。得到的是一个从中心到边缘亮度递减的圆形效果(距离方向坐标越近,数值越小)2d游戏素材,可以使用 saturate 再次对球面区域的颜色进行处理,将球体乘以一个大数, 并将数字返回 1 以获得清晰的边界。

// sun
float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
float sunDisc = 1 - (sun / _SunRadius);
sunDisc = saturate(sunDisc * 50);

unity数值平滑变化_unity 天空盒动态变化_unity 绘制包围盒

月亮的画法也是一样,两个球就可以达到月食/日食的效果——

// moon
float moon = distance(i.uv.xyz, -_WorldSpaceLightPos0); //日月方向相反
float moonDisc = 1 - (moon / _MoonRadius);
moonDisc = saturate(moonDisc * 50);
float crescentMoon = distance(float3(i.uv.x + _MoonOffset, i.uv.yz), -_WorldSpaceLightPos0);
float crescentMoonDisc = 1 - (crescentMoon / _MoonRadius);
crescentMoonDisc = saturate(crescentMoonDisc * 50);
moonDisc = saturate(moonDisc - crescentMoonDisc);

unity 绘制包围盒_unity 天空盒动态变化_unity数值平滑变化

渐变天空

天气有两种,白天和黑夜。

unity 绘制包围盒_unity 天空盒动态变化_unity数值平滑变化

使用lerp函数形成颜色渐变,根据uv坐标确定昼夜不交替时的天空颜色,根据saturate函数和世界坐标的y值确定昼夜交替。

// gradient day sky
float3 gradientDay = lerp(_DayBottomColor, _DayTopColor, saturate(i.uv.y));
float3 gradientNight = lerp(_NightBottomColor, _NightTopColor, saturate(i.uv.y));
float3 skyGradients = lerp(gradientNight, gradientDay,saturate(_WorldSpaceLightPos0.y));

unity数值平滑变化_unity 绘制包围盒_unity 天空盒动态变化

星空/云图

星空和云彩是用噪声贴图+截止制作的。

在“天空”纹理中,不能直接使用 uv 坐标。在uv坐标下,emmm感觉附着在一个巨大的球体上。在这里游戏图片素材,繁星点点的天空和云彩只会出现在“天空”中,屏幕上的表演只会出现在屏幕上。上半部分。所以这里是使用世界坐标来实现的,在xz平面上显示纹理,使用y轴坐标来控制上半部分的显示范围。

用于天空贴图的坐标如下处理。用clamp控制世界坐标y值在0到最大值之间(我不知道y轴最大值怎么取,但是大于10000的时候没有区别,所以我用这个数...接下来就是熟悉的cutoff操作,使用step设置一个cutoff阈值,突出亮部,关键代码如下:

float2 skyuv = i.worldPos.xz / clamp(i.worldPos.y, 0, 500);
float3 stars = tex2D(_Stars, skyuv + float2(_StarsSpeed, _StarsSpeed) * _Time.x);
stars = step(_StarsCutoff, stars);

同样的方法,添加云彩(和星星一样,只是改变纹理),效果如下:

unity数值平滑变化_unity 天空盒动态变化_unity 绘制包围盒

unity数值平滑变化_unity 绘制包围盒_unity 天空盒动态变化

云优化添加噪声图

当前的云只是单层纹理,看起来很有层次感,可以看到明显的纹理图案。接下来,通过添加噪声图来丰富云的形状。

这里添加了两种纹理,一种用于在原始纹理上叠加丰富的云图案,另一种用于创建更明显的失真效果。

float distort = tex2D(_DistortTex, (skyuv + (_Time.x * _DistortionSpeed)) * _DistortScale);
float noise = tex2D(_CloudNoise, ((skyuv + distort ) - (_Time.x * _CloudSpeed)) * _CloudNoiseScale);
float finalNoise = saturate(noise) * 3 * saturate(i.worldPos.y);
cloud = saturate(step(_CloudCutoff, cloud * finalNoise));

unity数值平滑变化_unity 绘制包围盒_unity 天空盒动态变化

蓬松的!

云的边缘现在太清晰了,所以让我们让云看起来更蓬松,添加一个参数,在一个截止范围内平滑值,使云在边缘有点模糊。

cloud = saturate(smoothstep(_CloudCutoff * cloud, _CloudCutoff * cloud + _Fuzziness, finalNoise));

这似乎更接近现实。

unity数值平滑变化_unity 绘制包围盒_unity 天空盒动态变化

unity数值平滑变化_unity 天空盒动态变化_unity 绘制包围盒

云层

复制并粘贴上一层云并添加另一层以提供不同的截止范围。效果非常好。可以制作浓密或稀疏的云层,多层也方便以后添加不同的颜色。

cloud = saturate(smoothstep(_CloudCutoff * cloud, _CloudCutoff * cloud + _Fuzziness, finalNoise));
float cloudSec = saturate(smoothstep(_CloudCutoff * cloud, _CloudCutoff * cloud + _FuzzinessSec, finalNoise));

颜色加

给上层和下层的云层赋予不同的颜色。这里按照白天和黑夜添加两组颜色,然后根据白天和黑夜交替更换云色。

unity 天空盒动态变化_unity 绘制包围盒_unity数值平滑变化

星空优化为晚上出现

星空与云不同,它只出现在夜晚。使用 saturate 和世界坐标 y 轴返回 1 或 0 作为乘数。

stars = step(_StarsCutoff, stars) * saturate(-_WorldSpaceLightPos0.y);

unity 天空盒动态变化_unity数值平滑变化_unity 绘制包围盒

云的背后

目前星云叠加效果如下,星云出现在云层前。

unity 绘制包围盒_unity数值平滑变化_unity 天空盒动态变化

unity 绘制包围盒_unity 天空盒动态变化_unity数值平滑变化

决定只画没有云的星星。

stars *= (1 - cloud);

地平线

作为最后一步,添加地平线。可以根据uv.y画一条水平线。然后还是根据白天和黑夜来确定不同的地平线颜色。地平线的另一个作用是模糊上下边界,使云与地面的边界不那么明显。在这里unity 天空盒动态变化,绘制了一条额外的线以赋予它明亮的颜色来阻挡它。

float3 horizon = abs((i.uv.y * _HorizonIntensity) - _HorizonHeight);
horizon = saturate((1 - horizon)) * (_HorizonColorDay * saturate(-_WorldSpaceLightPos0.y) + _HorizonColorNight * saturate(_WorldSpaceLightPos0.y));

unity数值平滑变化_unity 绘制包围盒_unity 天空盒动态变化

时间脚本

功能如下:

结束了!

unity 天空盒动态变化_unity数值平滑变化_unity 绘制包围盒

本期素材小黄人的梦幻天空球

Catlike 编码 · 时钟

ps:感觉是step、smoothstep、saturate、clamp、lerp这五个函数负责shader中的绘制...