使用“相机前纹理”方法的问题在于,纹理是2D的,但您想要可视化3D体积的一个切片。对于您提到的关于头部穿过墙壁的想法,我会向您指出“3D /体积纹理”。对于半身浸入水中的情况,您需要使用“吸收”的“体积渲染”(由@user3670102讨论)。
3D纹理
这里的一般思想是您有一些函数,它定义了3D空间中的每个位置的颜色,而不仅仅是表面上的颜色(与常规纹理映射不同)。这很好,因为您可以将几何图形放置在任何位置,并根据3D位置在片段着色器中着色。想象一下通过体积进行切片并查看交点颜色。
对于头部进入墙壁的效果,您可以在玩家前面绘制一个全屏多边形(就在近裁剪平面上,尽管您可能希望将其向前推一点,以使其不太小),并根据3D函数对其进行着色。现在它看起来会适当地坚固,并随着玩家的移动而移动,而不像您只是便宜地将纹理贴在屏幕上。
![enter image description here](https://istack.dev59.com/dyskm.webp)
实际函数可以用三维纹理来定义,但这会占用大量内存。相反,您可以尝试使用过程化的三维颜色(例如过程化木材或砖块着色器)。即使是假设一个二维纹理通过体积“挤压”也可以工作,或者更好的方法是基于您正在绘制的交点/表面的角度对三个纹理(每个轴一个)进行加权。
在这里检测几何图形和近裁剪平面的交点可能是最难的部分。如果我是你,我会看看z缓冲区的技巧,并确保将所有内容都绘制为实心的非自交几何。一个简单的想法可能是在绘制完所有正面后仅绘制背面。如果您能看到背面,则该近平面的某个部分必须在某物体内部。对于这些像素,您可以计算世界空间中的近裁剪平面位置并应用三维纹理。虽然我怀疑除了两次绘制所有内容之外,还有更快的方法。
实际上,可能没有光线照射到您所看到的物体,因此应该是黑色的,但我想只需忽略这一点并直接呈现颜色,无需照明。
吸收
这听起来比实际困难得多。如果你有一些完全相同颜色(“均匀”的)透明固体,那么它会移除光线,光线需要通过它传播的距离越远。想象许多α-透明表面,取极限,就得到一个指数函数。剩余的光线接近于
1/exp(dist)
或
exp(-dist)
。谷歌“比尔定律”。从
这里。
vec3 Absorbance = WaterColor * WaterDensity * -WaterDepth;
vec3 Transmittance = exp(Absorbance);
一种通过渲染背面(或海床/水底)来找到距离的好方法是使用着色器以浮点纹理绘制距离,使用加法混合。然后切换到减法混合并渲染所有正面(或水面)。这样你就得到了一个包含上述方程距离/深度的纹理。
体积渲染
将这两个想法结合起来,物质既是透明的固体,但颜色(和可能的密度)在整个体积中变化。如果数据量很大且需要快速处理,则会变得非常复杂。直接渲染它的一种简单方法是在三维纹理(或过程函数,无论你使用什么)中数值积分射线,同时应用吸收函数。基本的暴力欧拉积分可以为近平面上的每个像素启动一条射线,然后以均匀距离向前移动。在每个步骤中,您假设颜色保持不变并应用吸收,跟踪剩余的光量。快速搜索
this。