着色器是一个神奇的存在。官方资料看这里
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