Origin
element3ds.com
Tags
性能优化
渲染
程序化
开放世界
经验分享
项目
地平线:黎明时分
收藏夹
创建时间
收藏类型
Cubox 深度链接
更新时间
原链接
描述
【地平线:黎明】云系统的分解和解释
此幻灯片中有些有视频,有些有音频。
谢谢大家。
在接下来的时间里,我将要分解并解释 Horizon Zero Dawn 的云系统。
正如娜塔莎所说,我的背景是动画电影 VFX,体验包括云在内的体素系统的编程。
这是我和一个名叫 Nathan Vos 的程序员共同开发的。他今天不能在这里,但他的工作是我们能够实现这一目标的重要部分。
Horizon 今年刚刚在 E3 上宣布,这是我们第一次与社区分享我们的一些新技术。您在这里看到的内容大约需要 2 毫秒,需要 20 MB 的内存,并完全取代之前游戏中基于资产的云解决方案。
在我深入研究这些 2 毫秒的方法和理由之前,让我给你一些背景来解释为什么我们最终开始为天空开发程序体积系统。
在过去,Guerrilla 以 KILLZONE 系列游戏而闻名,这是第一人称射击游戏。
FPS usually restrict the player to a predefined track, which means that we could hand place elements like clouds using billboards and highly detailed sky domes to create a heavily art directed sky.
These domes and cards were built in Photoshop by one artist using stock photography. As Time of day was static in the KILLZONE series, we could pre-bake our lighting to one set of images, which kept ram usage and processing low.
By animating these dome shaders we could create some pretty detailed and epic sky scapes for our games.
Horizon is a very different kind of game…
fps 通常将播放器限制在一个预先定义的轨道上,这意味着我们可以使用广告牌和高度详细的天空穹顶来手动放置云等元素,以创建一个高度艺术化的天空。
这些穹顶和卡片是由一位艺术家用普通照片在 Photoshop 中制作的。由于 Killzone 系列中一天中的时间是静态的,所以我们可以将照明预烘焙到一组图像中,这样可以降低 RAM 的使用和处理速度。
通过动画这些圆顶阴影,我们可以为我们的游戏创造一些非常详细和史诗般的天空景观。
Horizon 是一种非常不同的游戏……
Horizon trailer 地平线标记。
So, from that you could see that we have left the world of Killzone behind.
Horizon is a vastly open world where you can pretty much go anywhere that you see, including the tops of mountains.
Since this is a living real world, we simulate the spinning of the earth by having a time of day cycle.
Weather is part of the environment so it will be changing and evolving as well.
There’s lots of epic scenery: Mountains, forests, plains, and lakes.
Skies are a big part of the landscape of horizon. They make up half of the screen. Skies are also are a very important part of storytelling as well as world building.
所以,从这个角度,你可以看到我们已经抛弃了杀戮区的世界。
地平线是一个非常开放的世界,在那里你可以去任何你看到的地方,包括山顶。
因为这是一个真实的生活世界,我们通过一个白天循环的时间来模拟地球的旋转。
天气是环境的一部分,因此它也将不断变化和演变。
这里有很多史诗般的风景:山、森林、平原和湖泊。
天空是地平线景观的重要组成部分。他们占了屏幕的一半。天空也是讲故事和建设世界的重要组成部分。
They are used to tell us where we are, when we are, and they can also be used as thematic devices in storytelling.
它们用来告诉我们我们在哪里,我们在什么时候,它们也可以作为主题设备在讲故事。
For Horizon, we want the player to really experience the world we are building. So we decided to try something bold. We prioritized some goals for our clouds.
Art direct-able
Realistic Representing multiple cloud types
Integrate with weather
Evolve in some way
And of course, they needed to be Epic!
对于地平线,我们希望玩家真正体验我们正在建设的世界。所以我们决定大胆尝试。我们为云确定了一些优先目标。
艺术直接
真实表示多种云类型
与天气融为一体
以某种方式进化
当然,他们需要成为史诗!
Realistic CG clouds are not an easy nut to crack. So, before we tried to solve the whole problem of creating a sky full them, we thought it would be good to explore different ways to make and light individual cloud assets.
现实的 CG 云不容易破解。 因此,在我们尝试解决创建天空的整个问题之前,我们认为探索制作和点亮单个云资产的不同方法会比较好。
Our earliest successful modeling approach was to use a custom fluid solver to grow clouds. The results were nice, but this was hard for artists to control if they had not had any fluid simulation experience. Guerrilla is a game studio after all.
我们最早成功的建模方法是使用自定义流体解算器来生成云。结果很好,但如果没有流体模拟的经验,设计师很难控制。Guerrilla 毕竟是一个游戏工作室。
We ended up modeling clouds from simple shapes,
voxelizing them and then …
Running them through our fluid solver …
Until we got a cloud like shape .
我们最终用简单的形状建模云,
将它们分类然后……
通过我们的流体解算器运行它们……
直到我们得到像云一样的形状。
And then we developed a lighting model that we used to pre-compute primary and secondary scattering,
Ill get into our final lighting model a little later, but the result you see here is computed on the cpu in Houdini in 10 seconds.
然后我们开发了一个用于预先计算一次和二次散射的照明模型,
我稍后会进入我们的最终照明模型,但是你在这里看到的结果是在 10 秒内在 Houdini 的 cpu 上计算出来的。
We explored 3 ways to get these cloud assets into game.
For the first, we tried to treat our cloud as part of the landscape, literally modeling them as polygons from our fluid simulations and baking the lighting data using spherical harmonics. This only worked for the thick clouds and not whispy ones …
我们探索了将这些云资源纳入游戏的 3 种方法。
首先,我们尝试将云作为景观的一部分,将其作为流体模拟中的多边形进行建模,并使用球谐函数烘焙照明数据。 这只适用于厚厚的云层,而不是低温(阴天)的云层……
So, we though we should try to enhance the billboard approach to support multiple orientations and times of day . We succeeded but we found that we couldn’t easily re-produce inter cloud shadowing. So…
所以,我们应该尝试加强广告牌的方法来支持一天中的多个方向和时间。我们成功了,但是我们发现我们不能轻易地重新产生云间阴影。所以…
We tried rendering all of our voxel clouds as one cloud set to produce skydomes that could also blend into the atmosphere over depth. Sort of worked.
At this point we took a step back to evaluate what didn’t work. None of the solutions made the clouds evolve over time. There was not a good way to make clouds pass overhead. And there was high memory usage and overdraw for all methods.
So maybe a traditional asset based approach was not the way to go.
我们尝试将我们所有的体素云渲染为一个云集,以产生天空穹顶,也可以在深度上融入大气层。工作正常。
在这一点上,我们后退了一步来评估什么不起作用。所有的解决方案都不能使云随时间演化。没有一个好办法让云从头顶飞过。所有的方法都有很高的内存使用率和透支。
因此,基于传统资源的方法可能是不可行的。
Well, What about voxel clouds?
OK we are crazy we are actually considering voxel clouds now…
As you can imagine this idea was not very popular with the programmers.Volumetrics are traditionally very expensive
With lots of texture reads
Ray marches
Nested loops
However, there are many proven methods for fast, believable volumetric lighting
There is convincing work to use noise to model clouds . I can refer you to the 2012 Production Volume Rendering course.
Could we solve the expense somehow and benefit from all of the look advantages of volumetrics?
嗯,体素云怎么样?
好吧,我们疯了,我们现在正在考虑体素云……
你可以想象这个想法并不是很受程序员的欢迎。容量传统上非常昂贵
有很多纹理读取
雷游行
嵌套循环
然而,有许多经过验证的方法可用于快速,可信的体积照明
使用噪声来模拟云是有说服力的工作。 我可以推荐你参加 2012 年的生产量渲染课程。
我们可以以某种方式解决费用并从容量的所有外观优势中受益吗?
Our first test was to stack up a bunch of polygons in front of the camera and sample 3d Perlin noise with them. While extremely slow, This was promising, but we want to represent multiple clouds types not just these bandy clouds.
我们的第一个测试是在相机前堆叠一堆多边形并用它们采样 3d Perlin 噪声。 虽然非常慢,但这很有希望,但我们希望代表多种云类型而不仅仅是这些带状云。
So we went into Houdini and generated some tiling 3d textures out of the simulated cloud shapes. Using Houdini’s GL extensions, we built a prototype GL shader to develop a cloud system and lighting model.
所以我们进入 Houdini 并从模拟的云形状中生成一些平铺的 3d 纹理。 使用 Houdini 的 GL 扩展,我们构建了一个原型 GL 着色器来开发云系统和照明模型。
In The end, with a LOT of hacks, we got very close to mimicking our reference. However, it all fell apart when we put the clouds in motion. It also took 1 second per frame to compute. For me coming from animated vfx, this was pretty impressive, but my colleagues were still not impressed.
So I thought, Instead of explicitly defining clouds with pre determined shapes, what if we could develop some good noises at lower resolutions that have the characteristics we like and then find a way to blend between them based on a set of rules. There has been previous work like this but none of it came close to our look goals.
最后,通过大量的黑客攻击,我们非常接近于模仿我们的参考。然而,当我们让云运动时,它都崩溃了。每帧也需要 1 秒钟来计算。对于来自动画特效的我来说,这是相当令人印象深刻的,但我的同事们仍然没有印象。
所以我想,如果我们可以在低分辨率下产生一些好的噪音,这些噪音具有我们喜欢的特性,然后根据一组规则在它们之间找到一种混合的方法,而不是用预先确定的形状明确地定义云,那该怎么办呢?以前有过这样的工作,但是没有一项能达到我们的目标。
This brings us to the clouds system for horizon. To explain it better I have broken it down into 4 sections: Modeling, Lighting, Rendering and Optimization.
Before I get into how we modeled the cloud scapes, it would be good to have a basic understanding of what clouds are and how they evolve into different shapes.
这就把我们带到了云系的地平线上。为了更好地解释它,我将它分为 4 个部分:建模、照明、渲染和优化。
在我了解我们如何模拟云的结构之前,最好先了解一下云是什么,以及它们如何演变成不同的形状。
Classifying clouds helped us better communicate what we were talking about and
Define where we would draw them. The basic cloud types are as follows.
The strato clouds including stratus, cumulus and stratocumulus
The alto clouds, which are those bandy or puffy clouds above the strato layer
And the cirro clouds those big arcing bands and little puffs in the upper atmosphere.
Finally there is the granddaddy of all cloud types, the Cumulonimbus clouds which go high into the atmosphere.
For comparison, mount Everest is above 8,000 meters.
对云进行分类有助于我们更好地沟通我们所谈论的内容定义我们绘制它们的位置。
基本云类型如下:
层云包括层云,积云和层积云
高积云,是层状层上方的那些带状或浮肿的云
卷云笼罩着上层大气中的那些大弧形带和小气泡的圆形云层。
最后,还有所有云类型的祖父,积雨云进入大气层。
相比之下,珠穆朗玛峰海拔 8000 米以上。
After doing research on cloud types, we had a look into the forces that shape them. The best source we had was a book from 1961 by two meteorologists, called “The Clouds” as creatively as research books from the 60’s were titled. What it lacked in charm it made up for with useful empirical results and concepts that help with modeling a cloud system.
Density increases at lower temperatures
Temperature decreases over altitude
High densities precipitate as rain or snow
Wind direction varies over altitude
They rise with heat from the earth
Dense regions make round shapes as they rise
Light regions diffuse like fog
Atmospheric turbulence further distorts clouds.
These are all abstractions that are useful when modeling clouds.
在研究了云的类型之后,我们研究了塑造它们的力量。我们拥有的最好的资料来源是两位气象学家 1961 年出版的一本书,这本书的书名和 60 年代的研究书一样富有创意,被称为 “云”。它所缺乏的魅力弥补了有用的经验结果和有助于云系统建模的概念。
低温下密度增加
温度随高度下降
高密度的雨或雪沉淀下来。
风向随高度变化
它们随着地球的热量而上升。
密集的区域上升时会形成圆形。
灯光区域像雾一样漫射
大气湍流进一步使云变形。
这些都是建模云时有用的抽象。
Our modeling approach uses ray marching to produce clouds.
We march from the camera and sample noises and a set of gradients to define our cloud shapes using a sampler
我们的建模方法使用光线行进来产生云。我们从相机和样本噪声以及一组渐变,用取样器来定义我们的云形状。
In a ray march you use a sampler to…
Build up an alpha channel….
And calculate lighting
在光线游行中你使用一个采样器……
建立一个 alpha 通道….
并计算照明。
There are many examples of real-time volume clouds on the internet. The usual approach involves drawing them in a height zone above the camera using something called fBm, Fractal Brownian Motion. This is done by layering Perlin noises of different frequencies until you get something detailed.
(pause)
This noise is then usually combined somehow with a gradient to define a change in cloud density over height.
互联网上有许多实时卷云的例子。 通常的方法是使用 fBm,Fractal Brownian Motion 的东西将它们绘制在相机上方的高度区域。 这是通过将不同频率的 Perlin 噪声分层来完成的,直到您得到详细信息。
然后,这种噪声通常以某种方式与梯度组合以定义云密度随高度的变化。
This makes some very nice but very procedural looking clouds. What’s wrong? There are no larger governing shapes or visual cues as to what is actually going on here. We don’t feel the implied evolution of the clouds from their shapes.
这使得一些非常漂亮但非常程序化的云。怎么了?对于这里实际发生的事情,没有更大的控制形状或视觉提示。我们没有从云的形状中感受到它们隐含的进化过程。
By contrast, in this photograph we can tell what is going on here. These clouds are rising like puffs of steam from a factory. Notice the round shapes at the tops and whispy shapes at the bottoms.
相比之下,在这张照片中,我们可以看出这里发生了什么。 这些云正在像工厂的蒸汽一样上升。 请注意顶部的圆形形状和底部的圆形形状。
This fBm approach has some nice whispy shapes, but it lacks those bulges and billows that give a sense of motion. We need to take our shader beyond what you would find on something like ShaderToy.
这种 FBM 方法有一些很好的惠斯比形状,但它缺乏那些鼓起和起伏的运动感。我们需要使用我们的着色器超越你在 ShaderToy 之类的东西。
These billows, as Ill call them…
…are packed, sometimes taking on a cauliflower shape.
Since Perlin noise alone doesn’t cut it, we developed our own layered noises.
这些巨浪,我称之为……
… 包装好,有时采用花椰菜形状。
由于 Perlin 噪音本身并没有削减它,我们开发了自己的分层噪音。
Worley noise was introduced in 1996 by Steven Worley and is often used for caustics and water effects. If it is inverted as you see here:
It makes tightly packed billow shapes.
We layered it like the standard Perlin fBm approach
Then we used it as an offset to dilate Perlin noise. this allowed us to keep the connectedness of Perlin noise but add some billowy shapes to it.
We referred to this as
Perlin-Worley
noise。
沃利噪声是由史蒂文 · 沃利于 1996 年引入的,常用于焦散和水效应。如果它是颠倒的,如你所见:
它使紧密的包装翻滚的形状。
我们像标准的 Perlin FBM 方法一样将其分层。
然后我们用它作为偏移来扩张 Perlin 噪音。 这让我们能够保持 Perlin 噪音的连通性,但却增加了一些波涛汹涌的形状。
我们称之为 “Perlin-Worley” 噪音。In games, it is often best for performance to store noises as tiling 3d textures.
You want to keep texture reads to a minimum…
and keep the resolutions as small as possible.
In our case we have compressed our noises to…
two 3d textures…
And 1 2d texture.
在游戏中,将噪声存储为平铺的 3D 纹理通常对性能最好。
您希望将纹理读取量保持在最小…
并尽可能保持较小的分辨率。
在我们的例子中,我们把噪音压缩到…
两个 3D 纹理和 1 个二维纹理。
The first 3d Texture…
has 4 channels…
it is 128^3 resolution…
The first channel is the Perlin - Worley noise I just described.
The other 3 are Worley noise at increasing frequencies. Like in the standard approach, This 3d texture is used to define the base shape for our clouds.
第一个 3D 纹理…
有 4 个频道…
分辨率为 128^3…
第一个通道是我刚才描述的 Perlin-Worldey 噪声。
另外三种是频率增加时的沃利噪声。与标准方法一样,这种 3D 纹理用于定义云的基本形状。
Our second 3d texture…
has 3 channels…
it is 32^3 resolution…
and uses Worley noise at increasing frequencies. This texture is used to add detail to the base cloud shape defined by the first 3d noise.
我们的第二个 3D 纹理…
有 3 个频道…
它是 32^3 分辨率…
并在不断增加的频率下使用沃利噪声。此纹理用于将细节添加到由第一个三维噪波定义的基础云形状。
Our 2D texture…
has 3 channels…
it is 128^2 resolution…
and uses curl noise. Which is non divergent and is used to fake fluid motion. We use this noise to distort our cloud shapes and add a sense of turbulence.
我们的二维纹理…
有 3 个频道…
分辨率为 128^2…
使用卷曲噪声。它是不发散的,用来模拟流体运动。我们使用这种噪声来扭曲我们的云形状,并增加一种湍流的感觉。
Recall that the standard solution calls for a height gradient to change the noise signal over altitude. Instead of 1, we use…
3 mathematical presets that represent the major low altitude…
cloud types when we blend between them at the sample position.
We also have a value telling us how much cloud coverage we want to have at the sample position. This is a value between zero and 1.
回想一下,标准的解决方案需要一个高度梯度来改变高度上的噪声信号。而不是 1,我们使用…
3 个代表主要低空的数学预设…
当我们在样本位置混合云类型时。
我们也有一个值告诉我们在样本位置我们想要有多少云覆盖。这是一个介于 0 和 1 之间的值。
What we are looking at on the right side of the screen is a view rotated about 30 degrees above the horizon. We will be drawing clouds per the standard approach in a zone above the camera.
First, we build a basic cloud shape by sampling our first 3dTexture and multiplying it by our height signal.
The next step is to multiply the result by the coverage and reduce density at the bottoms of the clouds.
我们在屏幕右侧看到的是在地平线上方旋转约 30 度的视图。 我们将在相机上方的区域中按照标准方法绘制云。
首先,我们通过对第一个 3dTexture 进行采样并将其乘以高度信号来构建基本云形状。
下一步是将结果乘以覆盖范围并降低云底的密度。
This ensures that the bottoms will be whispy and it increases the presence of clouds in a more natural way. Remember that density increases over altitude. Now that we have our base cloud shape, we add details.
这样可确保底部产品能够以更自然的方式增加云层的存在。 请记住密度随海拔高度增加。 现在我们有了基础云形状,我们添加了细节。
The next step is to…
erode the base cloud shape by subtracting the second 3d texture at the edges of the cloud. Little tip, If you invert the Worley noise at the base of the clouds you get some nice whispy shapes.
We also distort this second noise texture by our 2d curl noise to fake the swirly distortions from atmospheric turbulence as you can see here…
下一步是……
通过减去云边缘的第二个 3d 纹理来侵蚀基础云形状。 小小的提示,如果你颠倒了云底的 Worley 噪音,你就会得到一些不错的威士忌形状。
我们还通过我们的 2d 卷曲噪声来扭曲这第二个噪声纹理,以伪造来自大气湍流的旋涡扭曲,如您所见……
Here’s that it looks like in game. I’m adjusting the coverage signal to make them thicker and then transitioning between the height gradients for cumulus to stratus.
Now that we have decent stationary clouds we need to start working on making them evolve as part of our weather system.
这就是游戏中的样子。 我正在调整覆盖信号以使它们更厚,然后在积云到层云的高度梯度之间转换。
现在我们拥有了不错的固定云,我们需要开始努力使它们成为我们天气系统的一部分。
These two controls, cloud coverage and cloud type are a FUNCTION of our weather system.
There is an additional control for Precipitation that we use to draw rain clouds.
这两个控件,云覆盖和云类型是我们的天气系统的功能。
我们用来绘制雨云的降水有一个额外的控制。
Here in this image you can see a little map down in the lower left corner. This represents the weather settings that drive the clouds over our section of world map. The pinkish white pattern you see is the output from our weather system. Red is coverage, Green is precipitation and blue is cloud type. The weather system modulates these channels with a simulation that progresses during gameplay. The image here has Cumulus rain clouds directly overhead (white) and regular cumulus clouds in the distance. We have controls to bias the simulation to keep things art direct-able in a general sense.
在这张图片中,你可以在左下角看到一张小地图。这代表了在我们的世界地图上驱动云的天气设置。你看到的粉白图案是我们的天气系统的输出。红色是覆盖,绿色是降水,蓝色是云型。天气系统通过在游戏中进行的模拟来调节这些频道。图中有直接在头顶的积云(白色)和远处规则的积云。我们有控制来偏向模拟,以保持艺术在一般意义上的直接性。
The default condition is a combination of cumulus and stratus clouds. The areas that are more red have less of the blue signal, making them stratus clouds. You can see them in the distance at the center bottom of the image.
默认条件是积云和层云的组合。红色区域的蓝色信号较少,因此形成了层云。您可以在图像中心底部的距离处看到它们。
The precipitation signal transitions the map from whatever it is to cumulonimbus clouds at 70% coverage.
降水信号以 70% 的覆盖率将地图从任何地方转换为积雨云。
If we increase the wind speed and make sure that there is a chance of rain, we can get Storm clouds rolling in and starting to drop rain on us. This video is sped up, for effect, btw. Ahhh… Nature Sounds.
如果我们提高风速,确保有下雨的机会,我们可以让风暴云卷进,开始向我们下雨。这段视频是加速的,为了效果,顺便说一句… 自然声音。
We also use our weather system to make sure that clouds are the horizon are always interesting and poke above mountains.
We draw the cloudscapes within a 35,000 meter radius around the player….
and Starting at a distance of 15,000 meters…
we start transitioning to cumulus clouds at around 50% coverage.
我们还使用我们的天气系统来确保地平线上的云总是很有趣并且在山脉上方捅。
我们在玩家周围 35,000 米范围内绘制了 cloudscapes。
并从 15,000 米的距离开始……
我们开始转换到积云,覆盖率约为 50%。
This ensures that there is always some variety and ‘epicness’ to the clouds on the horizon.
So, as you can see, the weather system produces some nice variation in cloud type and coverage.
这就确保了地平线上的云总是有一些多样性和 “震感”。
所以,正如你所看到的,天气系统在云的类型和覆盖范围上产生了一些很好的变化。
In the case of the e3 trailer, We overrode the signals from the weather system with custom textures. You can see the corresponding textures for each shot in the lower left corner. We painted custom skies for each shot in this manner.
在 e3 预告片的情况下,我们使用自定义纹理覆盖天气系统的信号。 您可以在左下角看到每个镜头的相应纹理。 我们以这种方式为每个镜头绘制了自定义天空。
So to sum up our modeling approach…
we follow the standard ray-march/ sampler framework
but we build the clouds with two levels of detail
a low frequency cloud base shape
and high frequency detail and distortion
Our noises are custom and made from Perlin, Worley and Curl noise
We use a set of presets for each cloud type to control density over height and cloud coverage
These are driven by our weather simulation or by custom textures for use with cutscenes
and it is all animated in a given wind direction.
总结一下我们的建模方法……
我们遵循标准的 ray-march / sampler 框架
但我们用两层细节构建云
低频云底形状
和高频细节和失真
我们的声音是定制的,由 Perlin,Worley 和 Curl 噪音制成
我们为每种云类型使用一组预设来控制高度密度和云覆盖范围
这些是由我们的天气模拟或自定义纹理驱动的,用于过场动画
并且它在给定的风向上都是动画的。
Cloud lighting is a very well researched area in computer graphics. The best results tend to come from high numbers of samples. In games, when you ask what the budget will be for lighting clouds, you might very well be told “Zero”. We decided that we would need to examine the current approximation techniques to reproduce the 3 most important lighting effects for us.
云照明是计算机图形学研究的一个很好的领域。最好的结果往往来自大量的样本。在游戏中,当你问到照明云的预算是多少时,你很可能会被告知 “零”。我们决定,我们需要研究当前的近似技术来重现 3 种最重要的照明效果。
The directional scattering or luminous quality of clouds…
The sliver lining when you look toward the sun through a cloud…
And the dark edges visible on clouds when you look away from the sun.
The first two have standard solutions but the third is something we had to solve ourselves.
云的定向散射或发光质量…
当你透过云看向太阳的时候,银乌云周围的白光…
你远离太阳的时候,在云上可以看到黑暗的边缘。
前两个有标准的解决方案,但第三个是我们必须自己解决的问题。
When light enters a cloud The majority of the light rays spend their time refracting off of water droplets andice inside ofthe cloud before heading to our eyes.
(pause)
By the time the light ray finally exits the cloud it could have been out scattered…
absorbed by the cloud…
or combined with…
other light rays in what is called in-scattering..
In film vfx we can afford to spend time gathering light and accurately reproducing this, but in games we have to use approximations. These three behaviors can be thought of as probabilities and there is aStandard way to approximate the result you would get.
当光线进入云层时,大部分光线都会花费时间从云层内的水滴和冰层中折射出来,然后前往我们的眼睛。
(暂停)
当光线最终离开云层时,它可能已经分散了……
被云吸收……
或与… 结合
所谓的散射中的其他光线..
在电影 vfx 中,我们可以花时间收集光线并准确地再现它,但在游戏中我们必须使用近似值。这三种行为可以被认为是概率,并且有一种标准方法来估计您将获得的结果。
Beer’s law states that we can determine the amount of light reaching a point based on the optical thickness of the medium that it travels through. With Beers law, we have a basic way to describe the amount of light at a given point in the cloud.
If we substitute energy for transmittance ad depth in the cloud for thickness, and draw this out you can see that energy exponentially decreases over depth. This forms the foundation of our lighting model.
比尔定律指出,我们可以根据光通过介质的光学厚度来确定到达某一点的光量。根据比尔斯定律,我们有一个基本的方法来描述云中某一点的光量。
如果我们用云的透射率和深度来代替厚度,然后画出这个图,你可以看到能量随深度呈指数递减。这构成了我们照明模型的基础。
but there is a another component contributing to the light energy at a point. It is the probability of light scattering forward or backward in the cloud. This is responsible for the silver lining in clouds, one of our look goals.
但是在某一点上还有另一个有助于光能的因素。 它是光在云中向前或向后散射的概率。 这是云中的白色光线,这是我们的目标之一。
In clouds, there is a higher probability of light scattering forward. This is called Anisotropic scattering.
In 1941, the Henyey-Greenstein model was developed to help astronomers with light calculations at galactic scales, but today it is used to reliably reproduce Anisotropy in cloud lighting.
在云中,光散射的可能性更高。 这称为各向异性散射。
1941 年,Henyey-Greenstein 模型的开发是为了帮助天文学家在银河系中进行光计算,但今天它被用于可靠地再现云照明中的各向异性。
Each time we sample light energy, we multiply it by The Henyey-Greenstein phase function.
每次我们对光能进行取样时,我们都用 Henyey-Greenstein 函数来乘以它。
Here you can see the result. On the left is Just the beers law portion of our lighting model. On the right we have applied the Henyey-Greenstein phase function. Notice that the clouds are brighter around the sun on the right.
在这里你可以看到结果。左边是我们的照明模型的比尔定律部分。在右边,我们应用了 Henyey-Greenstein 相函数。请注意,右边的云在太阳周围比较明亮。
But we are still missing something important, something that is often forgotten. The dark edges on clouds. This is something that is not as well documented with solutions so we had to do a thought experiment to understand what was going on.
但是我们仍然缺少一些重要的东西,这些东西经常被遗忘。 云上的黑暗边缘。 这是解决方案中没有记录的内容,因此我们必须进行思考实验以了解正在发生的事情。
Think back to the random walk of a light ray through a cloud.
If we compare a point inside of the cloud to one near the surface, the one inside would receive more in scattered light. In other words, Cloud material, if you want to call it that, is a collector for light. The deeper you are in the surface of a cloud, the more potential there is for gathered light from nearby regions until the light begins to attenuate, that is.
This is extremely pronounced in round formations on clouds, so much so that the crevices appear…
to be lighter that the bulges and edges because they receive a small boost of in-scattered light.
Normally in film, we would take many many samples to gather the contributing light at a point and use a more expensive phase function. You can get this result with brute force. If you were in Magnus Wrenninge’s multiple scattering talk yesterday there was a very good example of how to get this. But in games we have to find a way to approximate this.
回想一下光线随机穿过云层的情形。
如果我们将云内部的一个点与靠近表面的一个点进行比较,内部的一个点在散射光下会接收更多的光。换句话说,如果你想称之为云物质,它就是光的收集器。你在云的表面越深,就越有可能聚集附近区域的光,直到光开始减弱,也就是说。
这在云上的圆形构造中非常明显,以至于缝隙出现…
更轻的是凸起和边缘,因为它们在散射光中接收到一个小的增强。通常在胶片中,我们会取许多样品来收集某一点的贡献光,并使用更昂贵的相位函数。你可以用蛮力得到这个结果。
如果你参加了 Magnus Wrenninge 的多次散播谈话,那么就有一个很好的例子来说明如何实现这个目标。 但在游戏中我们必须找到一种近似的方法。
A former colleague of mine, Matt Wilson, from Blue Sky, said that there is a similar effect in piles of powdered sugar. So, I’ll refer to this as the powdered sugar look.
我的一位前同事,蓝天的马特威尔逊说,成堆的糖粉也有类似的效果。 所以,我将这称为糖粉外观。
Once you understand this effect, you begin to see it everywhere. It can not be un-seen.
Even in light whispy clouds. The dark gradient is just wider.
一旦你理解了这种效应,你就会发现它无处不在。看不见。
即使是在云层中。黑暗的梯度只是更宽。
The reason we do not see this effect automatically is because our transmittance function is an approximation and doesn’t take it into account.
The surface of the cloud is always going to have the same light energy that it receives. Lets think of this effect as a statistical probability based on depth.
我们没有自动看到这种效果的原因是因为我们的透射率函数是近似值并且没有考虑到它。
云的表面总是具有与其接收的相同的光能。 让我们将此效应视为基于深度的统计概率。
As we go deeper in the cloud, our potential for in scattering increases and more of it will reach our eye.
If you combine the two functions you get something that describes this…
effect as well as the traditional approach.
I am still looking for the Beer’s-Powder approximation method in the ACM digital library and I haven’t found anything mentioned with that name yet.
随着我们在云中的深入,我们的散射潜力会增加,更多的东西会触及我们的眼球。
如果你将这两个函数结合起来,就会得到一些描述这个函数
效果以及传统方法。
我仍在寻找 ACM 数字图书馆中的 Beer-Powder 近似方法,但我还没有找到任何提及该名称的内容。
Lets visually compare the components of our directional lighting model
The beer’s law component which handles the primary scattering…
the powder sugar effect which produces the dark edges facing the light…
And their combination in our final result.
让我们直观地比较定向照明模型的组件
处理初级散射的比尔定律成分…
粉末糖效应,产生面向光的暗边…
以及它们在我们最终结果中的组合。
Here you can see what the beer’s law and combined beer’s law and powder effect look like when viewed from the light source. This is a pretty good approximation of our reference.
在这里,你可以看到从光源看,贝尔定律混合啤酒粉定律和粉末效应是什么样子的。这是一个很好的近似值。
In game, it adds a lot of realism to the
thicker clouds and helps sell the scale of the scene.
在游戏中,它增加了很多现实主义
更厚的云层,有助于推荐场景的规模。
But we have to remember that this is a view dependent effect. We only see it where our view vector approaches the light vector, so the powder function should account for this gradient as well.
但我们必须记住,这是依赖视图的效果。 我们只看到我们的视图向量接近光矢量的位置,因此粉末函数也应该考虑该梯度。
Here is a panning camera view that shows this effect increasing as we look away from the sun.
这里是一个全景摄像头视图,显示当我们远离太阳时这种效果会增加。
The last part of our lighting model is that we artificially darken the rain clouds by …
increasing the light absorption where they exist.
我们的照明模型的最后一部分是我们通过…… 人为地使雨云变暗。
增加它们存在的光吸收。
So, in review our model has 3 components:
Beer’s LawHenyen-Greensteinour powder sugar effectAnd Absorption increasing for rain clouds。
因此,回顾一下,我们的模型有三个组成部分:
Henyen-Greenste 在我们的粉糖作用下,对雨云的吸收增加了。
I have outlined How our sampler is used to model clouds and how our lighting algorithm simulates the lighting effects associated with them. Now I am going to describe how and where we take samples to build an image. And how we integrate our clouds into atmosphere and our time of day cycle.
我已经概述了如何使用我们的采样器来模拟云以及我们的照明算法如何模拟与它们相关的光照效果。 现在我将描述我们如何以及在何处采集样本来构建图像。 以及我们如何将我们的云融入大气层和时间周期。
The first part of rendering with a ray march is deciding where to start. In our situation, Horizon takes place on Earth and as most of you are aware… the earth ….. Is round.
The gases that make up our atmosphere wrap around the earth and clouds exists in different layers of the atmosphere.
用光线进行渲染的第一部分是决定从哪里开始。在我们的情况下,地平线发生在地球上,正如你们大多数人所知…… 地球…… 是圆的。
构成我们大气的气体包裹着地球,云存在于不同的大气层中。
When you are on a “flat” surface such as the ocean, you can clearly see how the curvature of the earth causes clouds to descend into the horizon.
当你在一个 “平坦” 的表面,如海洋上,你可以清楚地看到地球的曲率是如何使云下降到地平线上的。
For the purposes of our game we divide the clouds into two types in this spherical atmosphere.
The low altitude volumetric strato class clouds between 1500 and 4000 meters…
and the high altitude 2D alto and cirro class clouds above 4000 meters. The upper level clouds are not very thick so this is a good area to reduce expense of the shader by making them scrolling textures instead of multiple samples in the ray march.
为了我们的游戏的目的,我们在这个球形大气中将云分为两种类型。
在 1500 到 4000 米之间的低空层积云…
以及海拔 4000 米以上的高空 2D 圆形云和卷云。上层云不是很厚,因此这是一个很好的区域,通过使它们在光线行进中滚动纹理而不是多个样本来减少着色器的费用。
By ray marching through spherical atmosphere we can…
ensure that clouds properly descend into the horizon.
It also means we can force the scale of the scene by shrinking the radius of the atmosphere.
光线穿过球形大气层,我们可以…
确保云正确地降到地平线上。
这也意味着我们可以通过缩小大气的半径来强制场景的比例。
In our situation we do not want to do any work or any expensive work where we don’t need to. So instead of sampling every point along the ray, we use our samplers two levels of detail as a way to do cheaper work until we actually hit a cloud.
在这种情况下,我们不想在不需要的地方做任何工作或任何昂贵的工作。因此,我们不需要对光线中的每一个点进行采样,而是使用我们的取样器——两个层次的细节作为一种方法来做更便宜的工作,直到我们真正碰到云为止。
Recall that the sampler has a low detail noise that make s basic cloud shape
and a high detail noise that adds the realistic detail we need.
The high detail noise is always applied as an erosion from the edge of the base cloud shape.
回想一下,采样器有一个低细节噪声,使得基本的云形状。
高细节噪音,增加了我们需要的真实细节。
高细节噪声总是作为基础云形状边缘的侵蚀而应用。
This means that we only need to do the high detail noise and all of its associated instructions where the low detail sample returns a non zero result.
This has the effect of producing an isosurface that surrounds the area that our cloud will be that could be.
这意味着我们只需要执行高细节噪声及其所有相关指令,其中低细节样本返回非零结果。
这具有产生围绕我们的云可能的区域的等值面的效果。
So, when we take samples through the atmosphere, we do these cheaper samples at a larger step size until we hit a cloud iso surface. Then we switch to full samples with the high detail noise and all of its associated instructions. To make sure that we do not miss any high res samples, we always take a step backward before switching to high detail samples.
因此,当我们在大气层中采集样品时,我们会以更大的步长进行这些更便宜的样品,直到我们到达云层表面。 然后我们切换到具有高细节噪声及其所有相关指令的完整样本。 为了确保我们不会错过任何高分辨率样本,我们总是向前退一步,然后再切换到高细节样本。
Once the alpha of the image reaches 1 we don’t need to keep sampling so we stop the march early.
一旦图像的 alpha 达到 1,我们就不需要继续采样,所以我们会提前停止行进。
If we don’t reach an alpha of one we have another optimization.
After several consecutive samples that return zero density, we switch back to the cheap march behavior until we hit something again or reach the top of the cloud layer.
如果我们没有达到 alpha 的 alpha 值,我们会进行另一次优化。
在几个连续的样本返回零密度之后,我们切换回廉价行进行为,直到我们再次遇到某些东西或到达云层的顶部。
Because of the fact that the ray length increases as we look toward the horizon, we start with …
an initial potential 64 samples and end with a …
potential 128 at the horizon. I say potential because of the optimizations which can cause the march to exit early. And we really hope they do.
This is how we take the samples to build up the alpha channel of our image. To calculate light intensity we need to take more samples.
由于我们看向地平线时光线长度增加的事实,我们从… 开始
初始潜在的 64 个样本并以… 结束
潜力 128 在地平线上。 我说潜力是因为优化可能导致游行提前退出。 我们真的希望他们这样做。
这就是我们如何采集样本来构建图像的 alpha 通道。 要计算光强度,我们需要采集更多样本。
Normally what you do in a ray march like this is to …
take samples toward the light source, plug the sum into your lighting equation and then attenuate this value using the alpha channel until you hopefully exit the march early because your alpha has reached 1.
通常你在这样的光线游行中做的是……
将样本取向光源,将总和插入到您的光照方程中,然后使用 Alpha 通道衰减此值,直到您希望提前退出游行,因为您的 alpha 已达到 1。
In our approach, we sample 6 times in a cone toward the sun. This smooth’s the banding we would normally get with 6 simples and weights our lighting function with neighboring density values, which creates a nice ambient effect. The last sample is placed far away from the rest …
in order to capture shadows cast by distant clouds.
在我们的方法中,我们在朝向太阳的圆锥体中采样 6 次。这个平滑的带状,是我们通常会得到的 6 个简单的条带,并将我们的照明功能与相邻的密度值进行加权,从而产生良好的环境效果。 最后一个样本远离其他样本…
为了捕捉远处云层投射的阴影。
Here you can see what our clouds look like with just alpha samples….
With our 5 cone samples for lighting.
And the long distance cone sample.
To improve performance of these light samples, we switched to sampling the cheap version of our shader once the alpha of the image reached 0.3. , this made the shader 2x faster
在这里你可以看到我们的云只有 alpha 样本的样子……
我们的 5 个锥形样品用于照明。
和长距离锥形样本。
为了提高这些光样本的性能,一旦图像的 alpha 值达到 0.3,我们就开始对我们着色器的廉价版本进行采样。 ,这使得着色器速度提高了 2 倍。
The lighting samples replace the lower case d, or depth in the beers law portion of our lighting model. This energy value is then attenuated by the depth of the sample in the cloud to produce the image as per the standard volumetric ray-marching approach.
照明样品取代了小写的 D,或在我们的照明模型的比尔定律部分的深度。然后,该能量值被云中样品的深度衰减,以按照标准体积射线行进方法生成图像。
The last step of our ray march was to…
sample the 2d cloud textures for the high altitude clouds
我们射线游行的最后一步是……
为高海拔云层采样 2d 云纹理。
These were a collection of the various types of cirrus and alto clouds that were tiling and scrolling at different speeds and directions above the volumetric clouds.
这些是各种各样卷云和积云的集合,它们以不同的速度和方向在体积云之上平铺和滚动。
In reality light rays of different frequencies are mixing in a cloud producing very beautiful color effects. Since we live in a world of approximations, we had to base cloud colors on some logical assumptions.
We color our clouds based on the following model:
Ambient sky contribution increases over heightDirect lighting would be dominated by the sun colorAtmosphere would occlude clouds over depth.
We add up our ambient and direct components and attenuate to the atmosphere color based on the depth channel.
事实上,不同频率的光线在云中混合,产生非常漂亮的色彩效果。因为我们生活在一个近似的世界中,所以我们必须根据一些逻辑假设来确定云颜色。
我们根据以下模型对云进行着色:
周围天空的贡献随高度的增加而增加,直接照明将主要由太阳色所控制,大气将云层遮挡在深度上。
我们将环境和直接成分相加,并根据深度通道衰减到大气颜色。
Now, you can change the time of day in the game and the lighting and colors update automatically. This means no pre-baking and our unique memory usage for the entire sky is limited to the cost of 2 3d textures and 1 2d texture instead of dozens of billboards or sky domes.
现在,您可以在游戏中更改一天中的时间,并且灯光和颜色会自动更新。这意味着没有预烘焙,我们对整个天空的独特记忆使用仅限于 2 个 3D 纹理和 1 个 2D 纹理的成本,而不是几十个广告牌或天空穹顶。
To sum up what makes our rendering approach unique:
Sampler does “cheap” work unless it is potentially in a cloud
64-128 potential march samples, 6 light samples per march in a cone, when we are potentially in a cloud.
Light samples switch from full to cheap at a certain depth
总结一下我们的渲染方法的独特之处:
除非可能存在于云中,否则采样器会 “廉价” 工作
当我们可能处于云中时,64-128 个潜在的行进样本,每个行进 6 个轻量级样本。
光样本在一定深度从完全切换到便宜。
The approach that I have described so far costs around 20 milliseconds.
Which means it is pretty but, it is not fast enough to be included in our game. My co-developer and mentor on this, Nathan Vos, Had the idea that…
到目前为止,我描述的方法大约需要 20 毫秒。
这意味着它很漂亮,但速度不够快,无法加入我们的游戏。我的合作开发人员和导师 Nathan Vos 有这样的想法…
Every frame we could use a quarter res buffer…
to update 1 out of 16 pixels for each 4x4 pixel bl.ock within our final image.
We reproject the previous frame to ensure we have something persistent.
每帧我们都可以使用四分之一分辨率的缓冲…
为最终图像中的每 4x4 像素 bl.ock 更新 16 个像素中的 1 个。
我们重新投影前一帧以确保有持久的内容。
…and where we could not reproject, like the edge of the screen, We substitute the result from one of the low res buffers.
Nathan’s idea made the shader 10x faster or more when we render this at half res and use filters to upscale it.
It is pretty much the whole reason we are able to put this in our game. Because of this our target performance is around 2 milliseconds, most of that coming from the number of instructions.
… 当我们不能像屏幕边缘那样重新投影时,我们用一个低分辨率缓冲区的结果来代替。
Nathan 的想法使着色速度提高了 10 倍甚至更多,当我们以半分辨率渲染它并使用过滤器来提高它。
这几乎就是我们能够把它放在游戏中的全部原因。因此,我们的目标性能大约是 2 毫秒,其中大部分来自指令的数量。
In review we feel that
We have largely achieved our initial goals. This is still a work in progress as there is still time left in the production cycle so we hope to improve performance and direct-ability a bit more. We’re also still working on our atmospheric model and weather system and we will be sharing more about this work in the future on our website and at future conferences.
All of this was captured on a playstation 4
And this solution was written in PSSL and C++
回顾一下,我们觉得
我们基本上实现了最初的目标。这仍然是一项正在进行中的工作,因为在生产周期中还有时间,所以我们希望提高性能和直接能力多一点。我们还在研究我们的大气模型和天气系统,未来我们将在我们的网站和未来的会议上分享更多关于这项工作的信息。
所有这些都是在一个游戏站 4 上捕获的
这个解决方案是用 PSSL 和 C++ 编写的。
A number of sources were utilized in the development of this system. I have listed them here.
I would like to thank My co-developer, Nathan vos most of allAlso some other Guerrillas..
Elco – weather system and general help with transition to games
Michal – supervising the shader development with me and Nathan
Jan Bart, - for keeping us on target with our look goals
Marijn – for allowing me the time in the fx budget to work on this and for his guidance
Maarten van der Gaag for some optimization ideas
Felix van den Bergh for slaving away at making polygon clouds and voxel clouds in the early days
Vlad Lapotin, for his work testing out spherical harmonicsAnd to Hermen Hulst, manager of Guerrilla for hiring me and for allowing us the resources and time to properly solve this problem for real-time.
在该系统的开发中使用了许多来源。 我在这里列出了它们。
我要感谢我的合作开发者,Nathan vos 最重要的还有一些其他的开发人员……
Elco - 天气系统和过渡到游戏的一般帮助
Michal - 与我和 Nathan 一起监督着色器的开发
Jan Bart, - 用我们的目标保持目标
Marijn - 允许我在 fx 预算中花时间来处理这个问题并为他提供指导
Maarten van der Gaag 提出了一些优化想法
Felix van den Bergh 在早期擅长制造多边形云和体素云
Vlad Lapotin,他的工作测试球谐函数和 Herer Hulst,Guerrilla 的经理雇用我,并允许我们的资源和时间来实时正确地解决这个问题。
> 本文由简悦 SimpRead 转码