Egret的shader入门

        Egret的shader支持glsl语言进行编写,原因应该在于webgl是基于opengl的基础上进行开发的,所以我们在学习的时候完全可以惨遭opengl的glsl语言进行学习。本篇文章不在于讲述glsl语言的介绍,而是着重于在Egret中如何通过glsl来实现shader,并且探讨一些在Egret中需要注意的事项。所以此篇文章针对于略有glsl语言基础的读者。

以下提供两篇着色器的介绍以及glsl常用的函数以及其他api

https://blog.csdn.net/u014291990/article/details/103112914

https://blog.csdn.net/dengfuxing3570/article/details/101250127

        由于Egret将WebGLRenderingContext封装在了其底层渲染,所以正常情况下我们不需要直接采用WebGLRenderingContext来进行shader渲染。而是通过Egret定义的egret.CustomFilter来执行自定义的shader。

        本文将介绍如何在Egret中实现简单Shader,以及如何让两张纹理进行混合

简单用法是:

let _shader:egret.CustomFilter = new egret.CustomFilter(vertexSrc,fragmentSrc);

let _bmp:egret.Bitmap = new egret.Bitmap( RES.getRes(“bg_png”));

this.addChild(_bmp);

_bmp.filters=[shader];

        即我们必须通过设置滤镜的方式在Egret中来实现Shader。接下来我们参照官方demo修改一段比较简单的shader来分析分析,注意此处的字符串使用的是``来表示,这样就避免了增加换行符,同时阅读起来也方便,当然也可以在vscode里面添加glsl插件进行编写。

let vertexSrc = `

attribute vec2 aVertexPosition;

attribute vec2 aTextureCoord;

attribute vec2 aColor;

uniform vec2 projectionVector;

const vec2 center = vec2(-1.0, 1.0);

varying vec2 vTextureCoord;

varying vec4 vColor;

void main(){

gl_Position=vec4((aVertexPosition/projectionVector) + center,0.0,1.0);

vTextureCoord = aTextureCoord;

vColor = vec4(aColor.x,aColor.x,aColor.x,aColor.x);

}

`

let fragmentSrc = `

precision lowp float;

varying vec2 vTextureCoord;

varying vec4 vColor;

uniform sampler2D uSampler;

void main(){

gl_FragColor = texture2D( uSampler,vTextureCoord) * ( vTextureCoord.x > 0.5 ? 1.0 : 0.5 );

}

`

废话少说,看上面的代码编译后得到


运行后效果图

        可以看到我们实现了左半边部分为半透明,右半边部分为非透明的效果。上面的代码意思是我们能够遍历整张图片的所有像素点,并判断如果x坐标小于整张图的一半,那么设置0.5的透明度,否则颜色值不变。

        不过此时我们可能会发现有几个变量貌似根本没有赋值就能直接用,难道说webgl的底层会给我们自动赋值吗,看网上的其他教程貌似都没讲到自动赋值这个。如果能有这个想法,说明你并没有依葫芦画瓢。证明你还是有探索精神的。下面我们看看这是哪几个变量

顶点着色器中有

attribute vec2 aVertexPosition;

attribute vec2 aTextureCoord;

attribute vec2 aColor;

uniform vec2 projectionVector;

片段着色器中有

uniform sampler2D uSampler;

        这几个变量之所有能够在Egret中直接使用,是因为Egret的webgl渲染底层在执行渲染时自动给这几个变量进行了值绑定,即赋值。所以我们能够直接使用。

而他们分别代表的的是

aVertexPosition顶点位置

aTextureCoord纹理坐标

aColor 顶点颜色值

projectionVector画布的尺寸大小

uSampler 2d纹理在webgl渲染通道里面的索引值默认为0

除此之外还有其他Egret自定义并有默认值的变量


至此一个简单在Egret中的实现Shader的demo就算完成了。

        那么如果我们要在Egret中实现两张或者多张纹理混合怎么办?

        通过查看源码发现Egret始终只是激活了TEXTURE0通道,而且默认情况下如上图uniforms[key].setValue(0),这里就是将通过0的纹理绑定在uSampler上,而下面的uSamplerAlphaMask 则对应了通道1。可能有人就觉得我们是否可以利用这个来实现?其实一开始我也这么想的,不过发现根本行不通。其实解决办法也简单,只要我们能够拿到webgl原生渲染上下文对象即可(WebGLRenderingContext)所以这个时候我们又得查看源码。

        果然功夫不负有心人我们可以通过以下代码来获得(5.3以上直接egret.sys.WebGLRenderContext[“getInstance”]())

let _gl = egret.web["WebGLRenderContext"]["getInstance"]();

let _webgl:WebGLRenderingContext = _gl.context;

所以编写两个纹理混合可有以下代码,修改片段着色器

fragmentSrc = `

precision lowp float;

varying vec2 vTextureCoord;

varying vec4 vColor;

uniform sampler2D uSampler;

uniform sampler2D uSampler1;

void main(){

gl_FragColor = mix( texture2D( uSampler,vTextureCoord),texture2D( uSampler1,vTextureCoord),0.4 );

}

`

代码如下:

let _texture:egret.Texture = RES.getRes("egret_icon_png");

let _gl = egret.web["WebGLRenderContext"]["getInstance"]();

let _render:Function = ( _tex:egret.Texture)=>{

        let  _context:WebGLRenderingContext = _gl.context;

        _context.activeTexture(_context.TEXTURE2);

        _context.bindTexture(_context.TEXTURE_2D, _gl.getWebGLTexture(_tex.bitmapData ));

};

let _bm: egret.Bitmap = new egret.Bitmap(RES.getRes("bg_jpg"));

 this.addChild(_bm);

let filter = new egret.CustomFilter(vertexSrc, fragmentSrc,{uSampler1:2});

_bm.filters = [filter];

//此处需要延迟才能实现效果,或者在帧循环里面调用

egret.setTimeout(()=>{

        _render(_texture);

},this,1);


效果图如下:


两张纹理混合后的效果

至此一个Egret中的入门shader已经完成。

值得注意的是由于glsl采用的是 类c语法,所以我们在书写时需要严格注意每一行结束后需添加冒号,以及浮点数的小数位。

你可能感兴趣的:(Egret的shader入门)