Godot Shader笔记:读屏着色器(上)

原文地址:Docs » Shading » Screen-reading shaders

导论

我们经常会渴望能够在shader中读取当前正在绘制的屏幕信息。然而诸如OpenGL DirectX 等3D API由于内部硬件的限制实现这个功能都非常困难。GPU是极端并行性的,所以读写屏幕会引发各种各样的缓存以及同一性问题。因此即使现在最先进的硬件设备也没有很好地支持这个机制。

替代方法是制作一个全屏幕或者部分屏幕的拷贝,存储到后台缓冲区(back-buffer),渲染的时候从中读取。Godot提供了几个工具可以使这个处理变得简单。

SCREEN_TEXTURE内置纹理

Godot的着色器语言有一个特殊的纹理,“SCREEN_TEXTURE”(以及“DEPTH_TEXTURE”存储深度,在3D情况下)。

我们结合屏幕的UV可以获得vec3类型的屏幕RGB颜色。一个内置的varying型属性SCREEN_UV可以为当前的片元函数获取UV。代码如下所示;

void fragment() {}
 COLOR = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
}

这样会得到一个不可见的对象,因为它显示的底层的内容。

之所以要使用textureLod函数,是因为Godot会复制一个屏幕块,并且会对它的mipmap产生一个高效的高斯模糊。

译者注:textureLod函数的注释

  • vec4_type textureLod ( sampler2D_type s, vec2 uv, float lod ) //基于自定义深度读取并生成一个2D纹理
  • vec4_type textureLod ( samplerCube s, vec3 uv, float lod ) //基于自定义深度读取并生成一个立方体

这种机制不仅可以读取屏幕还可以在毫无额外计算的情况下基于不同的模糊度来读取。

一个SCREEN_TEXTURE的范例

SCREEN_TEXTURE可以使用在很多场景。Demo中有一个屏幕空间着色器的实例,你可以下载并学习。其中一个例子是用shader调节亮度(brightness),对比度(contrast)和饱和度(saturation):

shader_type canvas_item;
​
uniform float brightness = 1.0;
uniform float contrast = 1.0;
uniform float saturation = 1.0;
​
void fragment() {
 vec3 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0).rgb;
​
 c.rgb = mix(vec3(0.0), c.rgb, brightness);
 c.rgb = mix(vec3(0.5), c.rgb, contrast);
 c.rgb = mix(vec3(dot(vec3(1.0), c.rgb) * 0.33333), c.rgb, saturation);
​
 COLOR.rgb = c;
}

译者注:mix函数的注释:线性插值函数

你可能感兴趣的:(Godot Shader笔记:读屏着色器(上))