自定义后期处理
前言
Godot提供许多开箱即用的后期处理效果, 包括Bloom, DOF和SSAO. 有时你想编写自己的自定义效果. 下面介绍如何做到这一点.
Viewport, 然后在 ViewportTexture 中渲染 Viewport 并在屏幕上显示它.
屏幕阅读着色器教程 .
注解
在撰写本文时,Godot不支持同时对多个缓冲区进行渲染. 处理之后着色器将无法访问法线或其他渲染通道. 你只能访问已渲染的帧.
单通后期处理
Viewport 来渲染场景, 一个场景在屏幕上渲染您的 Viewport . 您可以使用 ViewportContainer 在整个屏幕上或另一个屏幕内显示您的 Viewport Control 节点.
注解
Viewport 进行渲染可以控制场景的渲染方式, 包括帧率, 你可以使用 ViewportContainer 来渲染2D场景中的3D对象.
Node2D 与一个 ViewportContainer 和一个 Viewport . 你的 Scene 选项卡应该看起来像这样:
Viewport 内, 你可以有任何你想要的东西. 这将包含你的主场景. 在本教程中, 我们将使用一个随机盒子的领域:
ShaderMaterial 到 ViewportContainer , 并给它分配一个新的着色器资源. 你可以通过内置的 TEXTURE 制式来访问你渲染好的 Viewport .
注解
ViewportContainer , 但如果这样做, 将需要在着色器中创建你自己的uniform, 并手动传递 Viewport 纹理, 像这样:
// Inside the Shader.uniform sampler2D ViewportTexture;
您可以将纹理从GDScript传递到着色器中, 如下所示:
# In GDScript.func _ready(): $Sprite.material.set_shader_param("ViewportTexture", $Viewport.get_texture())
Sobel 滤波器 .
shader_type canvas_item;void fragment() { vec3 col = -8.0 * texture(TEXTURE, UV).xyz; col += texture(TEXTURE, UV + vec2(0.0, SCREEN_PIXEL_SIZE.y)).xyz; col += texture(TEXTURE, UV + vec2(0.0, -SCREEN_PIXEL_SIZE.y)).xyz; col += texture(TEXTURE, UV + vec2(SCREEN_PIXEL_SIZE.x, 0.0)).xyz; col += texture(TEXTURE, UV + vec2(-SCREEN_PIXEL_SIZE.x, 0.0)).xyz; col += texture(TEXTURE, UV + SCREEN_PIXEL_SIZE.xy).xyz; col += texture(TEXTURE, UV - SCREEN_PIXEL_SIZE.xy).xyz; col += texture(TEXTURE, UV + vec2(-SCREEN_PIXEL_SIZE.x, SCREEN_PIXEL_SIZE.y)).xyz; col += texture(TEXTURE, UV + vec2(SCREEN_PIXEL_SIZE.x, -SCREEN_PIXEL_SIZE.y)).xyz; COLOR.xyz = col;}
注解 Sobel滤波器读取当前像素周围9x9网格中的像素, 并使用权重将它们加在一起. 令人感兴趣的是它为每个像素分配权重; 围绕中心的八个中的每一个都是+1, 对于中心像素是-8. 权重的选择称为 “核心”. 您可以使用不同的内核来创建边缘检测过滤器, 轮廓和各种效果.
多通后期处理
像模糊这样的后期处理效果是资源密集型的. 但是如果您在多次通过中将它们分解, 您可以让它们运行得更快. 在多通道材质中, 每次传递都将前一次传递的结果作为输入并对其进行处理.
Viewport 节点堆叠起来. 在上面的例子中, 通过一个 ViewportContainer 节点, 将一个 Viewport 对象的内容渲染到根 Viewport . 通过将一个 Viewport 的内容渲染到另一个 Viewport 中, 然后将最后一个 Viewport 渲染到根 Viewport 中, 对一个多通道着色器做相同的操作.
您的场景层次结构将如下所示:
Viewport 节点. 因此, 如果遍历的顺序对着色器很重要, 请确保将要首先应用的着色器指定给树中最低的 ViewportContainer .
注解
您也可以单独渲染视区, 而不必像这样嵌套它们. 您只需要使用两个视区并一个接一个地渲染它们.
除了节点结构外, 其步骤与单通道后期处理着色器相同.
ViewportContainers. 应用着色器的顺序无关紧要:
shader_type canvas_item;// Blurs the screen in the X-direction.void fragment() { vec3 col = texture(TEXTURE, UV).xyz * 0.16; col += texture(TEXTURE, UV + vec2(SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.15; col += texture(TEXTURE, UV + vec2(-SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.15; col += texture(TEXTURE, UV + vec2(2.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.12; col += texture(TEXTURE, UV + vec2(2.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.12; col += texture(TEXTURE, UV + vec2(3.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.09; col += texture(TEXTURE, UV + vec2(3.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.09; col += texture(TEXTURE, UV + vec2(4.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.05; col += texture(TEXTURE, UV + vec2(4.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.05; COLOR.xyz = col;}
shader_type canvas_item;// Blurs the screen in the Y-direction.void fragment() { vec3 col = texture(TEXTURE, UV).xyz * 0.16; col += texture(TEXTURE, UV + vec2(0.0, SCREEN_PIXEL_SIZE.y)).xyz * 0.15; col += texture(TEXTURE, UV + vec2(0.0, -SCREEN_PIXEL_SIZE.y)).xyz * 0.15; col += texture(TEXTURE, UV + vec2(0.0, 2.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.12; col += texture(TEXTURE, UV + vec2(0.0, 2.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.12; col += texture(TEXTURE, UV + vec2(0.0, 3.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.09; col += texture(TEXTURE, UV + vec2(0.0, 3.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.09; col += texture(TEXTURE, UV + vec2(0.0, 4.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.05; col += texture(TEXTURE, UV + vec2(0.0, 4.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.05; COLOR.xyz = col;}
使用上面的代码, 您应该得到如下所示的全屏模糊效果.
Viewport 节点如何工作的更多信息,请参阅 Viewport 教程。
