着色器(Shader)只能在使用WebGL渲染时才能使用。由于WebGL是基于OpenGL ES的,因此着色器一般使用GLSL来编写,直接使用JavaScript API会比较麻烦,而Phaser已经帮我们封装好了,因此我们只需要关心GLSL了。
一般而言,着色器有顶点着色器和片元着色器,我们一般关心后者。顺便说一句,自3.60版本开始,Phaser内置了一些基于着色器的特殊效果,这些特效我们就可以不用自己写了。不过本文的重点在于怎么根据Phaser提供的API自己编写着色器。
添加着色器
添加着色器和普通的GameObject类似:
this.add.shader(基础着色器,x,y,宽,高);
其实后面还有几个参数,不过对于简单的着色器而言,这些参数足够了。
其中,基础着色器(BaseShader)可以传入片元着色器和顶点着色的代码(一般只需要前者就能看到效果了),该着色器会使用传入这个基础着色器的程序进行处理,而后面四个参数就是说明这个着色器要在场景中的哪一个矩形区域进行处理。
基础着色器的格式之一:
new Phaser.Display.Shader(键名,片元着色器,顶点着色器);
GLSL片元着色器简介
一个例子
const src=`void main(){gl_FragColor=vec4(1,0,1,1);}`;
const baseShader=new Phaser.Display.BaseShader("baseshader",src);
this.add.shader(baseShader,0,0,100,100).setOrigin(0);
上述例子,会在以(0,0)为左上角,宽高都为100的矩形区域中使用着色器进行处理。着色器默认也是以矩形中心(即0.5)为定位点的,所以上面还设置了一个定位点改为矩形的左上角。
很明显,这个着色器的代码就是字符串src
中的内容。这个程序会在着色器的处理区域中输出一个紫色的矩形。
接着,我们来看着色器代码。编写着色器代码的这种语言叫做GLSL,类似于C语言,但并不一样。着色器是在GPU而不是CPU上处理的,CPU的特点是顺序处理,而GPU则是对于处理区域中的每一个像素同时进行处理。
无论顶点还是片元着色器,都是要写在main()
函数中的,上述很明显是一个片元着色器。着色器中的语句需要以分号结尾。gl_FragColor
顾名思义就是用来设置像素的颜色的。vec4
是GLSL中的一个数据类型代表4维向量,颜色RGBA四个值正好可以用一个4维向量来表示。vec4
除了是一个数据类型之外,也是一个构造vec4
类型的函数。
GLSL中大多数函数的参数都应当是一个0~1之间的浮点数,至于为什么上述代码没有加小数点也能正常运行,大概是因为JS中,默认都是以浮点型存储的。当然加上小数点也能正常运行。因此白色的RGBA值在GLSL中,不应该写作vec4(255,255,255,255)
,而应该是vec4(1,1,1,1)
之类的。虽然大于1的值会变为类似于1的效果,小于0的值会变为类似于0的效果。
GLSL中的uniform
Phaser为我们定义好了很多自动传入着色器中的变量,比如说time,它会根据时间自动传入着色器中,我们可以在GLSL中通过声明uniform float time;
来表示需要用到这个变量,然后在主函数中就可以使用这个变量了。
在使用float类型时,需要在GLSL代码的最上面声明精度:
precision mediump float;
mediump就是中精度,当然还有高精度(highp)和低精度(lowp)。
可以试试将片元着色器换成以下的GLSL代码,看看会发生什么:
precision mediump float;
void main(){
gl_FragColor=vec4(abs(sin(time)),1,1,1);
}
在GLSL中,可以使用很多数学函数,由于正弦函数是周期函数,因此颜色的第一个分量会从0逐渐变为1,再变为0,再到-1的绝对值(也就是1),再到0,如此循环往复,这样子看到的着色器效果也是动态的。
除了有time
这个uniform之外,还有很多,具体请看文档。
关于GLSL的一些说明
GLSL是和数学有强烈相关性的,因此精通它会很复杂。但是,也可以体会到数学的美妙之处。这里推荐一个叫做ShaderToy的网站,这是一个分享GLSL代码的网站,上面有很多惊艳的效果。GLSL也是可以在很多基于OpenGL或类似的引擎上使用的。
网友评论