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
对于所有的线程(像素)都是统一
作用的变量的一种格式。比如贴图或时间等。
自带的常用的有:
- cc_time 游戏运行时间(秒)
- cc_screenSize 屏幕尺寸
- cc_matView 视图矩阵
- ...
UBO(Uniform Buffer Object)
用来存储着色语言中Uniform类型变量的缓冲区对象。
Creator 规定在 shader 中所有非 sampler 的 uniform 都应以 block 形式声明,且对于所有 UBO:
- 不应出现 vec3 成员;
- 对数组类型成员,每个元素 size 不能小于 vec4;
- 不允许任何会引入 padding 的成员声明顺序。
具体描述,详见官网
openGL之API
step(a,x) 规整函数
如果x >= a? 1 : 0,规整函数
相当于把,
变成<=
号
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
uv8个值对应着如下图,数字代表着uv的index:
其中0==4、2==6、1==5、3==7,所以知道了一张图的left
、right
、top
、down
的值,就能算出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颠倒
评论