CocosCreatorShader学习

CocosCreatorShader学习

Effect结构

# 声明流程控制清单
CCEffect %{
  #YAML语法
}%
  
# 顶点着色器
CCProgram vs %{

}%
  
# 片段着色器
CCProgram fs %{

}%

Shader 片段:Shader 片段在语法上基于 GLSL 300 ES,在资源加载时有相应的预处理编译流程。在标准 GLSL 语法上,Creator 引入了以下几种非常自然的 C 风格语法扩展。详细见官网

CocosCreator - YAML注意事项

CocosCreatorShader的定义部分使用的是YAML

  • key冒号后的空格不可省略

    	key1: 1
    
  • 缩进要正确,缩进表示层级

  • - +空格 表示数组

    - 42
    - 43
    
  • 引用:&标记 *引用

    object1: &o1
      key1: value1
    object2:
      key2: value2
      key3: *o1
    
  • 继承:&标记 << 继承

    object1: &o1
      key1: value1
      key2: value2
    object2:
      <<: *o1
      key3: value3
    
  • 注释:#

基础概念

这里主要讲的是Cocos Creator会用到的概念

Uniform

对于所有的线程(像素)都是统一作用的变量的一种格式。比如贴图或时间等。

CocosCreator 常用 shader 内置 Uniform

自带的常用的有:

  • cc_time 游戏运行时间(秒)
  • cc_screenSize 屏幕尺寸
  • cc_matView 视图矩阵
  • ...

UBO(Uniform Buffer Object)

用来存储着色语言中Uniform类型变量的缓冲区对象。

Creator 规定在 shader 中所有非 sampler 的 uniform 都应以 block 形式声明,且对于所有 UBO:

  1. 不应出现 vec3 成员;
  2. 对数组类型成员,每个元素 size 不能小于 vec4;
  3. 不允许任何会引入 padding 的成员声明顺序。

具体描述,详见官网

openGL之API

step(a,x) 规整函数

如果x >= a? 1 : 0,规整函数

相当于把,变成<=

参考shader常用数学函数

smoothstep 平滑规整函数

float smoothstep(float t1, float t2, float x) {
  // Scale, bias and saturate x to 0..1 range
  // 还记得么?在remap算法中接触过
  x = clamp((x - t1) / (t2 - t1), 0.0, 1.0); 
  // Evaluate polynomial
  return x * x * (3 - 2 * x);
}

其他:

在着色器中我们一般都会声明变量来在程序中使用,但是着色器中还有一些特殊的变量,不声明也可以使用。这些变量叫做内建变量。內建变量,相当于着色器硬件的输入和输出点,使用者利用这些输入点输入之后,就会看到屏幕上的输出。通过输出点可以知道输出的某些数据内容。当然,实际上肯定不会这样简单,这么说只是为了帮助理解。在顶点着色器中的内建变量和片元着色器的内建变量是不相同的。着色器中的内建变量有很多,在此,我们只列出最常用的集中内建变量。

顶点着色器的内建变量
输入变量:
gl_Position:顶点坐标
gl_PointSize:点的大小,没有赋值则为默认值1,通常设置绘图为点绘制才有意义。

片元着色器的内建变量
输入变量:
gl_FragCoord:当前片元相对窗口位置所处的坐标。
gl_FragFacing:bool型,表示是否为属于光栅化生成此片元的对应图元的正面。
输出变量:
gl_FragColor:当前片元颜色
gl_FragData:vec4类型的数组。向其写入的信息,供渲染管线的后继过程使用。

常见函数

radians(x):角度转弧度
degrees(x):弧度转角度
sin(x):正弦函数,传入值为弧度。相同的还有cos余弦函数、tan正切函数、asin反正弦、acos反余弦、atan反正切
pow(x,y):xy
exp(x):ex
exp2(x):2x
log(x):logex
log2(x):log2x
sqrt(x):x√
inversesqr(x):1x√
abs(x):取x的绝对值
sign(x):x>0返回1.0,x<0返回-1.0,否则返回0.0
ceil(x):返回大于或者等于x的整数
floor(x):返回小于或者等于x的整数
fract(x):返回x-floor(x)的值
mod(x,y):取模(求余)
min(x,y):获取xy中小的那个
max(x,y):获取xy中大的那个
mix(x,y,a):返回x∗(1−a)+y∗a
step(x,a):x< a返回0.0,否则返回1.0
smoothstep(x,y,a):a < x返回0.0,a>y返回1.0,否则返回0.0-1.0之间平滑的Hermite插值。
dFdx(p):p在x方向上的偏导数
dFdy(p):p在y方向上的偏导数
fwidth(p):p在x和y方向上的偏导数的绝对值之和

矩阵函数

length(x):计算向量x的长度
distance(x,y):返回向量xy之间的距离
dot(x,y):返回向量xy的点积
cross(x,y):返回向量xy的差积
normalize(x):返回与x向量方向相同,长度为1的向量

矩阵函数

matrixCompMult(x,y):将矩阵相乘
lessThan(x,y):返回向量xy的各个分量执行x< y的结果,类似的有greaterThan,equal,notEqual
lessThanEqual(x,y):返回向量xy的各个分量执行x<= y的结果,类似的有类似的有greaterThanEqual
any(bvec x):x有一个元素为true,则为true
all(bvec x):x所有元素为true,则返回true,否则返回false
not(bvec x):x所有分量执行逻辑非运算

texture表示纹理采样,2D表示对2D纹理采样,3D表示对3D纹理采样
Lod后缀,只适用于顶点着色器采样
Proj表示纹理坐标st会除以q
纹理采样函数中,3D在OpenGLES2.0并不是绝对支持。我们再次暂时不管3D纹理采样函数。重点只对texture2D函数进行说明。texture2D拥有三个参数,第一个参数表示纹理采样器。第二个参数表示纹理坐标,可以是二维、三维、或者四维。第三个参数加入后只能在片元着色器中调用,且只对采样器为mipmap类型纹理时有效。

理解cc.SpriteFrame的uv

_calculateUV() 源码

uv8个值对应着如下图,数字代表着uv的index:

[0,1]
[0,1]
[2,3]
[2,3]
[4.5]
[4.5]
[6,7]
[6,7]
0→
0→
4→
4→
6→
6→
2→
2→
5
5↑
1
1↑
3
3↑
7
7↑
Viewer does not support full SVG 1.1

其中0==4、2==6、1==5、3==7,所以知道了一张图的leftrighttopdown的值,就能算出uv,同样知道了uv就知道了这几个值。

源码解析

  • 定义
let rect = this._rect,					// rect
		texture = this._texture,		// 贴图
		uv = this.uv,								// uv
		texw = texture.width,				// 贴图宽
		texh = texture.height;			// 贴图高
  • 写入uv
// 先计算上下左右,然后写入到uv
let l = texw === 0 ? 0 : rect.x / texw;
let r = texw === 0 ? 0 : (rect.x + rect.width) / texw;
let b = texh === 0 ? 0 : (rect.y + rect.height) / texh;
let t = texh === 0 ? 0 : rect.y / texh;
uv[0] = l;
uv[1] = b;
uv[2] = r;
uv[3] = b;
uv[4] = l;
uv[5] = t;
uv[6] = r;
uv[7] = t;
  • 处理反转情况
if (this._flipX){// 如果x翻转
	// ...交换对应点
}
if (this._flipY){// 如果y翻转
	// ...交换对应点
}

按BookOfShader的写

u_resolution是传入的

gl_FragCoord


vec2 st = gl_FragCoord.xy/u_resolution;
// v_uv0 只不过 与 st算出来的y颠倒

评论