着色器学习(零) 基础简介
前一篇
参考地址:https://docs.godotengine.org/en/4.1/tutorials/shaders/shader_reference/shading_language.html
# 什么是着色器
着色器(Shader)是一种在图形处理单元(GPU)上运行的特殊程序。他们最初使用来为 3D 场景着色的,不过现在能做的事情就更多了。你可以用它们来控制引擎在屏幕上绘制几何体以及像素的方式,可以用来实现各种特效。
类似 Godot 的现代渲染引擎都会用着色器来执行所有绘制操作:图形卡可以并行执行成千上万条指令,可以达到惊人的渲染速度。
因为天生就是并行的,所以着色器处理信息的方式与普通的程序有所不同。着色器代码是单独针对顶点或像素执行的。你也无法在帧与帧之间存储数据。因此,使用着色器时,你需要使用与其他编程语言不同的编码和思考方式。
# Godot着色器
在Godot中,着色器由称为“处理器函数”的主要函数组成。处理器函数是着色器进入程序的入口点。有七个不同的处理器函数。
vertex()函数: 遍历网格中的所有顶点,设置它们的位置和一些其他顶点相关的变量。用于canvas_item着色器和spatial着色器。
fragment()函数: 对网格覆盖的每个像素运行。它使用vertex()函数输出的值,在顶点之间进行插值。用于canvas_item着色器和spatial着色器。
light()函数: 对每个像素和每个光源运行。它使用fragment()函数和之前运行的light()函数的变量。用于canvas_item着色器和spatial着色器。
start()函数: 对粒子系统中的每个粒子运行一次,当粒子首次生成时。用于粒子着色器。
process()函数: 对粒子系统中的每个粒子在每一帧运行。用于粒子着色器。
sky()函数: 对辐射立方体贴图中的每个像素在需要更新辐射立方体贴图时运行,并对当前屏幕上的每个像素运行。用于天空着色器。
fog()函数: 对体积雾froxel缓冲区中与雾体积相交的每个froxel运行。由雾着色器使用。
在这些处理器函数中,你可以实现各种效果,从顶点变换到像素处理,再到光照、粒子系统和天空效果。这使得在Godot中编写复杂的图形效果变得相对简单。
# 着色器类型
有以下类型可用:
用于 3D 渲染的 spatial。
用于 2D 渲染的 canvas_item。
用于粒子系统的 particles。
sky to render Skies.
fog to render FogVolumes
在 Godot 中,所有的着色器都需要在第一行指定它们的类型,类似这样:
shader_type spatial;
# 顶点处理器
在 spatial 和 canvas_item 着色器中,每个顶点都会调用 vertex()
处理函数,而在 particles 着色器中则会为每个粒子调用一次。
在你的世界中,几何体的每个顶点都具有位置、颜色等属性。vertex()
函数用于修改这些值,并将其传递给片段函数。你还可以使用 varying
关键字将额外的数据传递到片段着色器。
默认情况下,Godot会为你执行顶点信息的变换,将几何体投影到屏幕上。你也可以使用渲染模式自行变换数据,有关示例,请参阅 Spatial 着色器文档。
# 片段处理器
fragment()
处理函数用于为每个像素设置 Godot 材质参数。这段代码在对象或图元绘制的每个可见像素上运行。它仅在 spatial、canvas_item 和 sky 着色器中可用。
片段函数的标准用途是设置用于计算光照的材质属性。例如,你可以为 ROUGHNESS
、RIM
、TRANSMISSION
等设置值,告诉光照函数如何处理相应的片段。这样可以控制复杂的着色管线,而无需用户编写大量代码。如果你不需要这一内置功能,可以忽略它,自行编写光照处理函数,Godot会进行优化。
# 光照处理器
light()
处理器也会在每个像素上运行,同时还会在影响对象的每个灯光上运行。如果没有灯光影响对象,则不会执行。它通常用于在 fragment()
函数中进行材质属性设置时执行。
light()
处理器在2D和3D中的工作方式不同;有关每种工作方式的详细描述,请参阅相应的 CanvasItem 着色器 和 Spatial 着色器文档。
# 渲染模式
可以在着色器的第二行,也就是在着色器类型之后,指定渲染模式,类似这样:
shader_type spatial;
render_mode unshaded, cull_disabled;
2
渲染模式会修改 Godot 应用着色器的方式。例如,unshaded
模式会让引擎跳过内置的光线处理器函数。