尚未完成,漏洞连篇。
后处理是个麻烦活。在戈多里,最方便的办法是添加一个camera,在这个camera下,添加一个MeshInstance, 添加QuadMesh,然后为这个mesh附加shader即可。
上述过程可能有些"Hacky"。
我尝试自己按照戈多的官方文档提供的最佳方案进行后处理:
https://docs.godotengine.org/en/stable/tutorials/shaders/advanced_postprocessing.html
获取深度
这种方案可以获取深度缓冲区(也就是对于每个像素,你都能获取到对应的像素点)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| shader_type spatial; render_mode unshaded; uniform sampler2D depth_texture : hint_depth_texture; // 深度纹理 uniform sampler2D screen_texture : hint_screen_texture; // 屏幕纹理
void vertex() { POSITION = vec4(VERTEX, 1.0); // 向POSITION写入数据,这样能禁用Godot的变换。 }
void fragment() { float depth = texture(depth_texture, SCREEN_UV).x; // 获取顶点深度 vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth); // 获取CLIP_SPACE内点的位置 vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0); // 获取CAMERA_SPACE内点位置(齐次坐标) view.xyz = view.xyz / view.w; // 归一化:将齐次坐标转换为笛卡尔坐标 float linear_depth = -view.z; // 此时的深度是线性的。(但不是[0-1]区间内,不能直接显示) vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0); // 世界空间的坐标 vec3 world_position = world.xyz / world.w; // 归一化,转为笛卡尔坐标 // 深度范围 float near = 0.1; // 最近深度 float far = 100.0; // 最远深度 // 将深度从它原本的范围,缩放到[0, 1] float depth01 = clamp((linear_depth - near) / (far - near), 0.0, 1.0); ALBEDO = vec3(depth01); }
|
Godot会在内部处理物体在三维空间内的变换。Godot会处理Model Space, World Space, View Space, Clip Space, Screen Space的变换。这就是为什么你放置一个cube后,能在编辑器里看到这个方块的原因。戈多首先获得这个方块的模型数据,然后把方块的顶点的坐标由局部坐标(相对模型中心的坐标)变换为世界坐标(相对世界原点的坐标),然后变换为视图坐标(相对相机的坐标)。再然后会通过视图变换变为裁剪空间内的坐标,最后将裁剪空间内的坐标转换成屏幕坐标。
POSITION是一个可在vertex()里修改的vec4量。修改POSITION的值,会禁用引擎内部上述的模型视图变换。这样一来,你塞在场景内那个充当后处理工具的平面就会时刻贴在你的相机上。它相对世界的位置已经不再可用(?是这样吗?)。
有了上述的代码,我们就很容易把相机面前的物体的距离,用黑白图的形式显示在我们面前了:

不够,直接拿深度来判断似乎有些不妥。我们还得想办法搞到法线才行。