(摘) Godot 免费跨平台游戏引擎: Shader 着色器

声明:内容源自网络,版权归原作者所有。若有侵权请在网页聊天中联系我

着色器是一个神奇的存在。官方资料看这里

一个老外的分步视频

The Book of Shaders

Shader,是运行在GPU上的程序,中文称为着色器。它的主要用途是对三维物体进行着色处理,对光与影进行计算,以及控制纹理颜色的呈现等,最终,将游戏引擎中的几何数据转化为屏幕上的模型、场景以及特效。

着色器被誉为照亮虚拟世界的"魔法"。 着色器还可以用来做后期处理,类似PS。

着色器shader的编写需要使用着色语言GL Shader Language(GLSL),GLSL的语法与C语言很类似。

GLSL 代表 openGL Shading Language,openGL 着色语言

Godot所使用的的着色器语言和GLSL非常相似,并且增加了一些功能又稍稍降低了复杂度。

入口:例如sprite中,Material –> 新建ShaderMaterial –> 新建Shader 即进入编辑环境

它能做什么

快速定位顶点
快速计算颜色
快速计算光照
进行大量的数学计算

它不能做什么

绘制外部网格
从当前像素(或顶点)访问其他像素
储存之前的迭代
动态更新(可以,但是需要编译)

Godot中,你可以重写三个函数来控制着色器的运作:

vertex()  顶点函数用于修改每个顶点信息,运行在网格中的所有顶点上

fragment() 片段函数

light() 光照函数,用于每个像素和每束光照
shader_type canvas_item;

uniform float time_factor = 0.80;
uniform vec2 amplitude = vec2(5.0,20.0);

void vertex(){
	//VERTEX.x += cos(TIME * time_factor + VERTEX.y + VERTEX.x) * amplitude.x;
	//VERTEX.y += sin(TIME * time_factor + VERTEX.x + VERTEX.y) * amplitude.y;
}

COLOR = texture(TEXTURE, UV); //从纹理读取

COLOR.b = 1.0; //设置蓝色通道值为1.0

简单的两句话,就让它“摇摆”

它的语法就不是GDScript那样类似python了。语句后带分号,象是c系列。也使用{}进行区隔。

varying 变量声明:varying float a;

float bool Vec2 Vec3 int

在函数内声明的变量没有varying关键字,是内部变量。用varying声明的为全局变量。

函数

float sum(float a, float b){
	float o;
}

spatial 3D渲染

canvas_item 2D渲染

particles 粒子渲染

//顶点处理器

void vertex() { 
   
	VERTEX.y += 0.5;    //VERTEX是获取这个mesh所有顶点的局部坐标

}  

uniform用于逻辑语言与着色器之间传递数据

shader_type canvas_item;

//每个像素点都会进行一次fragment函数
void fragment(){

}

COLOR shader内置属性,表示像素点的颜色

UV shader内置属性,表示当前像素点的坐标。它是一个常量,不能修改。 左上角为(0.0,0.00),右下角(1.0,1.0),正中(0.5,0.5)

texture函数是shader内置函数,传入纹理和UV值,可以返回UV坐标上的颜色(vec4)

COLOR.rgb=vec3(1.0,1.0,1.0); 这是一种简洁的写法,给当前点一个rgb颜色

内置函数

函数 描述
vec_type radians (vec_type degrees) 将度数转换为弧度
vec_type degrees (vec_type radians) 将弧度转换为度数
vec_type sin (vec_type x) 正弦
vec_type cos (vec_type x) 余弦
vec_type tan (vec_type x) 正切
vec_type asin (vec_type x) 反正弦
vec_type acos (vec_type x) 反余弦
vec_type atan (vec_type y_over_x) 反正切
vec_type atan (vec_type y, vec_type x) 将矢量转换为角度的反正切
vec_type sinh (vec_type x) 双曲正弦
vec_type cosh (vec_type x) 双曲余弦
vec_type tanh (vec_type x) 双曲正切
vec_type asinh (vec_type x) 反双曲正弦
vec_type acosh (vec_type x) 反双曲余弦
vec_type atanh (vec_type x) 反双曲正切
vec_type pow (vec_type x, vec_type y) 幂 (undefined if x < 0 or if x = 0 and y <= 0)
vec_type exp (vec_type x) 基e指数
vec_type exp2 (vec_type x) 基2指数
vec_type log (vec_type x) 自然对数
vec_type log2 (vec_type x) Base-2 logarithm
vec_type sqrt (vec_type x) Square root
vec_type inversesqrt (vec_type x) Inverse square root
vec_type abs (vec_type x) 绝对
ivec_type abs (ivec_type x) 绝对
vec_type sign (vec_type x) 符号
ivec_type sign (ivec_type x) 符号
vec_type floor (vec_type x) 向下取整
vec_type round (vec_type x) 四舍五入
vec_type roundEven (vec_type x) 四舍五入到最接近的偶数
vec_type trunc (vec_type x) 截断
vec_type ceil (vec_type x) Ceil
vec_type fract (vec_type x) 分数
vec_type mod (vec_type x, vec_type y)
vec_type mod (vec_type x , float y)
vec_type modf (vec_type x, out vec_type i) Fractional of x, with i as integer part
vec_type min (vec_type a, vec_type b) 最小值
vec_type max (vec_type a, vec_type b) 最大值
vec_type clamp (vec_type x, vec_type min, vec_type max) 限制在最大和最小值之间
float mix (float a, float b, float c) 线性插值
vec_type mix (vec_type a, vec_type b, float c) 线性插值 (标量系数)
vec_type mix (vec_type a, vec_type b, vec_type c) 线性插值(向量系数)
vec_type mix (vec_type a, vec_type b, bvec_type c) 线性插值(布尔向量选择
vec_type step (vec_type a, vec_type b) b[i] < a[i] ? 0.0 : 1.0
vec_type step (float a, vec_type b) b[i] < a ? 0.0 : 1.0
vec_type smoothstep (vec_type a, vec_type b, vec_type c) Hermite 插值
vec_type smoothstep (float a, float b, vec_type c) Hermite 插值
bvec_type isnan (vec_type x) 当标量或者向量分量为nan时,返回true
bvec_type isinf (vec_type x) 当标量或者向量分量为inf时,返回true
ivec_type floatBitsToInt (vec_type x) 将Float按字节复制成Int, 不做类型转换
uvec_type floatBitsToUint (vec_type x) 将Float按字节复制成UInt, 不做类型转换
vec_type intBitsToFloat (ivec_type x) 将Int按字节复制成Float, 不做类型转换
vec_type uintBitsToFloat (uvec_type x) 将UInt按字节复制成Float, 不做类型转换
float length (vec_type x) 向量长度
float distance (vec_type a, vec_type b) 向量间距离(a - b)
float dot (vec_type a, vec_type b) 点乘
vec3 cross (vec3 a, vec3 b) 叉乘
vec_type normalize (vec_type x) 标准化为单位长度
vec3 reflect (vec3 I, vec3 N) 反映
vec3 refract (vec3 I, vec3 N, float eta) 折射
vec_type faceforward (vec_type N, vec_type I, vec_type Nref) If dot(Nref, I) < 0, return N, otherwise –N
mat_type matrixCompMult (mat_type x, mat_type y) 矩阵分量乘法
mat_type outerProduct (vec_type column, vec_type row) Matrix outer product
mat_type transpose (mat_type m) Transpose matrix
float determinant (mat_type m) Matrix determinant
mat_type inverse (mat_type m) Inverse matrix
bvec_type lessThan (vec_type x, vec_type y) Bool vector comparison on < int/uint/float vectors
bvec_type greaterThan (vec_type x, vec_type y) Bool vector comparison on > int/uint/float vectors
bvec_type lessThanEqual (vec_type x, vec_type y) Bool vector comparison on <= int/uint/float vectors
bvec_type greaterThanEqual (vec_type x, vec_type y) Bool vector comparison on >= int/uint/float vectors
bvec_type equal (vec_type x, vec_type y) Bool vector comparison on == int/uint/float vectors
bvec_type notEqual (vec_type x, vec_type y) Bool vector comparison on != int/uint/float vectors
bool any (bvec_type x) 有任何一个分量为true,则值为true
bool all (bvec_type x) 所有分量均为true
bvec_type not (bvec_type x) 所有分量均为false
ivec2 textureSize (sampler2D_type s, int lod) 获取纹理大小
ivec3 textureSize (sampler2DArray_type s, int lod) 获取立方映射(cubemap)的大小
ivec3 textureSize (sampler3D s, int lod) Get the size of a 3D texture
ivec2 textureSize (samplerCube s, int lod) Get the size of a cubemap texture
vec4_type texture (sampler2D_type s, vec2 uv [, float bias]) 执行2D纹理读取
vec4_type texture (sampler2DArray_type s, vec3 uv [, float bias]) Perform a 2D texture array read
vec4_type texture (sampler3D_type s, vec3 uv [, float bias]) Perform a 3D texture read
vec4 texture (samplerCube s, vec3 uv [, float bias]) Perform a cubemap texture read
vec4_type textureProj (sampler2D_type s, vec3 uv [, float bias]) Perform a 2D texture read with projection
vec4_type textureProj (sampler2D_type s, vec4 uv [, float bias]) Perform a 2D texture read with projection
vec4_type textureProj (sampler3D_type s, vec4 uv [, float bias]) Perform a 3D texture read with projection
vec4_type textureLod (sampler2D_type s, vec2 uv, float lod) 在自定义mipmap上执行2D纹理读取
vec4_type textureLod (sampler2DArray_type s, vec3 uv, float lod) Perform a 2D texture array read at custom mipmap
vec4_type textureLod (sampler3D_type s, vec3 uv, float lod) Perform a 3D texture read at custom mipmap
vec4 textureLod (samplerCube s, vec3 uv, float lod) Perform a 3D texture read at custom mipmap
vec4_type textureProjLod (sampler2D_type s, vec3 uv, float lod) Perform a 2D texture read with projection/LOD
vec4_type textureProjLod (sampler2D_type s, vec4 uv, float lod) Perform a 2D texture read with projection/LOD
vec4_type textureProjLod (sampler3D_type s, vec4 uv, float lod) Perform a 3D texture read with projection/LOD
vec4_type texelFetch (sampler2D_type s, ivec2 uv, int lod) Fetch a single texel using integer coordinates
vec4_type texelFetch (sampler2DArray_type s, ivec3 uv, int lod) Fetch a single texel using integer coordinates
vec4_type texelFetch (sampler3D_type s, ivec3 uv, int lod) 用整数坐标获取一个纹理影像元件(texel)
vec_type dFdx (vec_type p) 用局部差分对x求导
vec_type dFdy (vec_type p) 用局部差分对y求导
vec_type fwidth (vec_type p) x和y的绝对导数之和

render_mode 渲染模式

UV 取值在0-1之间,从左到右,由上到下。

先指定着色器类型,再通过fragment函数为每个像素设置一个颜色。

shader_type canvas_item;

void fragment(){
	COLOR = vec4(UV,0.5,1.0);
}

COLOR即为当前点的颜色值,也可以单独设置rgba: COLOR.r = 1.0;

通过语句读取当前点的颜色: COLOR = texture(TEXTURE, UV);

uniform 统一值输入,用于在界面中设置着色器的变量

在脚本中,可以进行参数设置

#着色器
shader_type canvas_item;

uniform float al = 0.8;

void fragment(){
	COLOR = vec4(UV.y,UV.y,UV.y,al);
}

#脚本中
xx.material.set_shader_param("al",0.1)

设置顶点的偏移

void vertex() {
	VERTEX += vec2(0.0,10.0);
}

通过与时间的结合,实现了一个圆形围绕移动

void vertex() {
   VERTEX += vec2(cos(TIME)*50.0, sin(TIME)*50.0);
}

UV: 点坐标

sampler2D: 用于绑定2D纹理的采样器类型,浮点值

SCREEN_TEXTURE: 屏幕截图纹理

SCREEN_PIXEL_SIZE:

SCREEN_UV: 屏幕UV坐标

COLOR: 每个像素的输出颜色

VERTEX: 顶点的位置

POINT_SIZE: Point原语的大小

POINT_COORD: 绘制Point基元时在点上的位置。

FRONT_FACING: 如果原始的正面,则为真。

TIME: 着色器启动后的时间

COLOR = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);

mat2 2x2矩阵,按主要顺序排列。

uniform 外部可设置参数

varying 变量

const 常量

fragment函数中

VIEWPORT_SIZE 视区大小(以像素为单位)

VERTEX 来自顶点函数的顶点(默认情况下,在视图空间中)

NORMAL 来自于顶点函数的法向量(默认情况下,在视图空间中)

UV 来自顶点功能的UV

COLOR 来自顶点功能的颜色

ALPHA 透明度

SCREEN_TEXTURE 内置纹理,用于从屏幕上读取

SCREEN_UV 屏幕当前像素的UV坐标

相关代码

vec2 uv = fragCoord.xy/iResolution.xy; // 将像素位置映射到0-1

vec4 fragColor = texture(iChannel0, uv); // 获取纹理在uv出的像素颜色

fragColor.r = abs(sin(iTime)); // 让红色分量的值随时间改变。

fragCoord.xy / iResolution.xy 会将坐标转换到 [0, 1] 之间。

uv = 2.0 * uv - 1.0 将坐标转换到 [-1, 1] 之间,中央为原点(0,0)


这里讲了一个烧纸效果,空了学习一下 https://www.jianshu.com/p/bb09ccd7f82f

最简单的几个效果学习一下 https://www.jianshu.com/p/a7e1b82eeb37

基础知识 https://www.jianshu.com/p/9b2c81d4c07e

探寻着色器shader编程的本质 https://www.bilibili.com/video/av969443112/

fragment 内建函数:

COLOR = texture(TEXTURE, UV); //默认值

NORMALMAP = texture(NORMAL_TEXTURE, UV).rgb; //法线贴图

in vec4 FRAGCOORD 片段坐标,像素调整。

in sampler2D TEXTURE 默认的2D纹理

in vec2 UV 来自顶点功能的UV。

in sampler2D NORMAL_TEXTURE 默认2D法线纹理。

in sampler2D SCREEN_TEXTURE 屏幕纹理


godot的shader中没有提供鼠标位置相关函数或语句,我们暂时只能通过参数的方式传值。

//旋转效果
shader_type canvas_item;
render_mode unshaded;

uniform float pivot_x : hint_range(0.01,0.99) = 0.5;
uniform float pivot_y : hint_range(0.01,0.99) = 0.5;
uniform float angular_speed  = 1.0;

void vertex(){
    vec2 pivot = vec2(pivot_x, pivot_y);
    float rot = TIME * angular_speed; 
    UV -= pivot;
    UV *= mat2(vec2(sin(rot), -cos(rot)), vec2(cos(rot), sin(rot)));
    UV += pivot;
}

实现图片随着窗口放大缩小

shader_type canvas_item;

uniform float scale_ratio = 1.0;

vec2 rot(vec2 uv, float a){
    return vec2(uv.x * cos(a) - uv.y * sin(a), uv.y * cos(a) + uv.x * sin(a));  
}

void fragment(){
    vec2 uv = UV/scale_ratio;
    uv.y*=scale_ratio;
    vec4 cc = texture(TEXTURE, rot(uv, 30)); 
    COLOR = cc;
}

在gd脚本中修改参数

extends TextureRect

var scaleRatio = 0;

func _ready():
    var winSize = OS.window_size;
    scaleRatio = winSize.x/winSize.y;

func _on_game_bg_resized():
    var winSize = OS.window_size;
    var newScaleRatio = winSize.x/winSize.y;
    material.set_shader_param('scale_ratio', scaleRatio/newScaleRatio);

2D游戏中制作动态水效果 https://www.jianshu.com/p/f1f244364ee8

相关文章