像在《我的世界》中一样,如何使水随着深度变深?


24

在《我的世界》中,当您注视水面时,您所看到的越暗。有人知道如何编写类似的代码吗?

我的世界 我的世界

没有效果的类似游戏 没有效果的类似游戏


18
因为水立方的材料是半透明的,这不是自动完成的吗?
pek

我不这么认为。我添加了没有效果的图片进行比较。
Xavier

2
也许这是仅适用于水立方的添加剂混合效果?同样,这应该很容易,因为该材料是半透明的。
2011年

1
您还可以根据深度更改盒子的颜色。
Ali1S232 2011年

Answers:


51

根据深度,本质上有两种不同的照明水的方法:

体素照明

Minecraft使用基于体素的照明,其工作原理是将光传播到相邻的立方体,从而根据块类型降低亮度。黑暗的海洋是该系统的副作用。

水可以阻挡阳光并将每块光线减少3级(而不是默认的1级),这意味着海洋与表面的每个距离的亮度为:

0 (surface): 15 (direct sunlight)
1:           12
2:            9
3:            6
4:            3
5 and below:  0 (darkness)

资料来源:Minecraft Wiki-Light

基于距离的阴影

在具有传统照明模型的游戏中,可以通过测量光源和海底之间的水量来产生这种效果。然后根据该距离使光衰减。有几种方法可以做到这一点:

直接计算

如果您拥有平坦的表面,则可以通过将表面法线从水体中通过\ vec {n},并将该法线的点积与表面位置传递s到几何着色器中,轻松地计算光线在水中的传播距离。

有效水距为

\ max(\ left(s-\ vec {n} \ cdot \ vec {p} \ right),0)\ cdot \ left(1 + \ tan(\ alpha)\ right)

其中\ vec {p}的位置是顶点,α是表面下方的光线方向与水表面朝向水体的法线之间的角度。

在日落时,α由于光线在进入水中时会发生折射,因此只能到达不到50度的位置。
这是一篇博客文章,有一个很好的解释:数码相机:全内反射
另一篇更多详细信息:数码相机:斯涅尔折射定律

如果您在与水平行的表面上使用高度图,则\ left(s-\ vec {n} \ cdot \ vec {p} \ right)变为\ left(s-h \ right)。如果太阳位于水面正上方,则正确系数等于1。
对于点光源,必须α根据与光源的相对位置为每个顶点计算。

在固定水位或固定光方向的情况下,方程的某些部分恒定不变,出于性能考虑,不应在着色器中对其进行计算。

优点:

  • 快速准确

缺点:

  • 仅适用于平坦的水面或仅适用于正上方的光线,因为通常只考虑一个水面。(粗糙表面和倾斜光的组合可以在一定程度上扩展视差贴图。)
  • 无腐蚀性

阴影贴图

如果将水表面渲染到单独的深度图(从光源看),则可以使用该深度纹理来计算光在撞击水面之前在水中传播的距离。
为此,您可以将每个顶点投影到顶点着色器中光源的视图投影中,并在像素着色器中进行纹理查找。

如果表面相对平坦,则应使用折射光源以获得更好的结果。

优点:

  • 只要不遮挡自身,就可以处理相对复杂的水几何形状。*
  • 几乎可以用于几乎任何类型的部分透明卷。

缺点:

  • 比直接计算慢。
  • 需要用于深度图的附加VRAM。
  • 并非100%准确。

*您可以通过计算从光源的POV开始的深度来确定最近的固体表面前面的水量,如下所示:

  1. 照常渲染场景中的实体几何。对于每个片段,将深度值添加到结果纹理中。
  2. 渲染水的正面而不更新深度缓冲区,并从结果中减去片段的深度。
  3. 以相同的方式渲染背面,但是将片段深度添加到结果中。

现在,结果纹理包含在光照视图空间中的光照前的水量,因此在使用它之前必须先将其转换回原来的值。这种方法可以计算定向光(负折射),但是如果表面非常不规则,并且水体之间有大量空气影响相同的碎片,则会导致不正确的环境光。
利弊与普通阴影贴图相同,不同之处在于,在计算深度时您需要一个额外的缓冲区,并且由于必须绘制更多的几何图形,因此性能较差。

射线追踪

到目前为止,光线跟踪是渲染透明卷的最准确但也是最昂贵的解决方案。有两种方法:1.从海底向海面跟踪; 2.从光源向水向跟踪。地板上的每个点都需要多条光线才能计算亮度。

优点:

  • 可以正确处理每种几何图形。
  • 正确的腐蚀!

缺点:

  • 慢!

附加效果

提水时还需要考虑以下几点:

多雾路段

水中的光在传播到观察者时再次散射,因此您应该将其混合为纯色。

如果观察者被淹没了,您可以根据深度缓冲区的最终结果渲染雾。雾的颜色,但其密度不应随观察者与地面的距离而变化!(《我的世界》仅使用效果的这一部分。)

如果观察者从上方注视着水,则需要根据表面和水下几何图形之间的深度差来计算雾。雾的颜色应随深度差的增加而稍微变暗,但应仅更改为雾完全不透明的点。

雾的颜色还应该取决于每个像素的视图方向,因此在两种情况下向下观看时,雾的颜色都会稍暗。

伪装焦散

如果您使用无缝平铺3D纹理代替假冒腐蚀剂的贴花,则可以避免在垂直表面上拉伸。靠近表面的散射光的强度在三个维度上变化,因此使用2D纹理通常会在场景中的某个位置产生拉伸。您可以通过将地板的顶点位置投影到其他坐标系中来建模变化的灯光角度。

另一种可能性是根据光线坐标系中的表面位置来计算光线密度,尽管这很可能会降低性能。

随着深度的增加,苛性碱的褪色速度应快于漫射光。

颜色渐变

颜色的分散程度不同,因此浅色应随深度的增加而变化。这也防止了例如海滩与水面相交的陡峭边缘。

入射角

由于折射,光照射到海底的距离比通常要陡得多。在约斯涅耳定律,维基百科的文章有角度和矢量公式。


6

我相信《我的世界》中的天空照明效果是直下的-无论太阳在哪里,事物都被其上方的阴影所遮蔽。然后,从手电筒等发出的局部照明具有衰减效果-距离光源越远,立方体得到的光越少。

如果采用这种方式,则每一层水都会累积遮盖其下方的一层,因此每一层都会逐渐变暗。树木的叶子提供了这样的阴影,但是不是累积的。无论是1还是100个树叶立方体,您都可以在树下得到相同的阴影。

这是使用的方法的一个线索是,离观看者越远,水不会变得越暗-仅当您下楼时。是的,远处确实会起雾效果,但水暗效果不会。

因此,用伪代码计算照明的基本公式将是这样的……

light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
   if cube being examined is tree foliage
      light_on_cube = 0.5
   else if cube being examined is water
      light_on_cube = light_on_cube - 0.1
   else if cube being examined is solid 
      light_on_cube = 0
}

这对于计算悬垂处或洞穴中的光照不是完美的,因为使用此方法在悬垂处会变暗。但是,既可以添加本地光源(手电筒,火等),也可以将被阳光照亮的块作为光源。这样的事情可能会做...

  1. 从每个立方体的正上方(通过伪代码)计算来自太阳的光。
  2. 如果多维数据集旁边有一个光源,则认为它已完全点亮(1.0)
  3. 如果一个立方体正上方没有阳光,请根据其与完全照明的立方体之间的距离来给它一些光线。距离越近意味着光线越多,距离越远意味着光线越少(直到零)。

这里的想法是,如果一个立方体被太阳或手电筒照亮,它旁边的那个立方体也将以某种方式被照亮。而且,您离那个发光的立方体越远,光线就越少。这是一种估计漫射照明的模糊方式,但我认为(?)可行。


1
是的,我很确定那是票。我在游戏中做过类似的事情。
MichaelHouse

顺便说一句,我刚刚将您的博客添加到了我的Google阅读器列表Byte56-开发者博客FTW!
蒂姆·霍尔特

哦,为什么谢谢你。仍然没有这个问题的话题,但是我刚刚读了您关于Bailey教授课程的博客。去年我在那堂课上!我很确定你去年也做了那个演讲。我以为你的名字很熟悉。小世界:)
MichaelHouse

3

也许我对这个问题有误解,但是为什么不能仅根据块的深度更改块的颜色呢?

如果您具有深度d(以块为单位,从0开始),则亮度的合理公式为:

L =(1- e - kd + m

码: L = (1.0 - m) * exp(-k * d) + m;

k控制变暗的速度(越高=越快)。合理的值为0.5。
m是您想要的最小亮度。
L从0到1。

如果您不知道如何在使用的任何图形API中更改块的颜色,请作为一个单独的问题(说明使用的API,以及是否使用着色器)进行询问。


我根本没有想到这样做。只是出于好奇,您从哪里得到方程式的?
Xavier

1
@Xavier:我刚刚做了。该e^-kd位只是指数衰减,对于在某个值(深度)上逐渐趋于零的事物,这是标准功能。与的相乘(1-m)和相乘m只是按比例缩放并抵消了衰减,因此衰减以的最小值结束,m但仍从开始1zh.wikipedia.org/wiki/Exponential_decay
Peter Alexander

事实是,只有色块具有alpha颜色时,才能看到较深色块。在这种情况下,无需更改块的颜色,alpha将自动创建效果。
乔纳森·康奈尔

@乔纳森:您不渲染水块,而是在海底渲染颜色变深的水块,然后在水面上只有一个alpha层。
彼得·亚历山大

@Peter Alexander Ok,我以为在这些积木式游戏中,连水都是由积木制成的。
乔纳森·康奈尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.