前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LayaAir2.11新特性:Blinnphong增加光透射功能、增加drawMeshInstance指令等,大幅提升渲染效果

LayaAir2.11新特性:Blinnphong增加光透射功能、增加drawMeshInstance指令等,大幅提升渲染效果

作者头像
Layabox Charley
发布2021-02-23 10:08:16
8270
发布2021-02-23 10:08:16
举报
文章被收录于专栏:LayaboxLayabox

本次LayaAir 2.11.0beta版是鼠年的最后一个版本,同时也是2021年的第一个版本。所以本次的更新内容也是干货满满,再次大幅提升了3D渲染能力。本文将逐个详细介绍。

提示: 1、本文中涉及的代码,均会省略大量代码,仅为介绍功能使用的核心代码, 2、代码的API使用方式为基于引擎源码的使用方式,与开放下载版本的Laya.xxx的写法不同, 3、各不同语言引擎版本API的使用方式、以及完整的示例代码请前往Layabox官网示例栏目查看。

Blinnphong支持光透射功能

从LayaAir2.11 beta版本开始,Blinnphong材质支持了光线透射功能,也就是当光线射入半透明材质,会产生光线透射的效果。例如下图的效果:

(来自官网BlinnPhong_Transmission示例截图)

或者查看视频动态效果:

(视频画质已被压缩,仅用于效果预览)

当我们想使用Blinnphong的光线透射效果时,将Blinnphong的 enableTransmission 属性设置为true即可。

示例代码为:

代码语言:javascript
复制
//打开兔子材质的次表面散射功能
this.rabbitMaterial.enableTransmission = true;

//打开猴子材质的次表面散射功能
this.monkeyMaterial.enableTransmission = true;

(点击代码,左右滑动查看全文)

下面我们继续介绍一下Blinnphong材质光线透射功能相关的其它属性,

厚度图属性thinknessTexture用于加载一张描述物体厚度信息的贴图,这是一张会描述物体各个地方透光比例的材质贴图。例如兔子的耳朵比较薄,透光会强一些,兔子的身体比较厚,透光会弱一些。

厚度图并非普通的贴图,需要找3D美术同学生成

有无厚度图的对比效果如下图所示:

示例代码为:

代码语言:javascript
复制
this.rabbitMaterial.enableTransmission = true;
//为兔子材质添加厚度贴图
this.rabbitMaterial.thinknessTexture = Loader.getRes("xxx/xxx.jpg");

(点击代码,左右滑动查看全文)

由于入射光分为透射部分和反射部分,透射率属性transmissionRate用于描述透射光占总光量的比例,该属性同时也会影响反射光部分的强度。

透射率属性值分别为0、0.5、1的对比效果如下图所示:

示例代码为:

代码语言:javascript
复制
this.rabbitMaterial.enableTransmission = true;
this.rabbitMaterial.thinknessTexture = Loader.getRes("xxx/xxx.jpg");
//设置兔子材质的透射率为0.1
this.rabbitMaterial.transmissionRata = 0.1;

(点击代码,左右滑动查看全文)

backDiffuse属性用于设置透射扩散范围系数,系数的范围是1-10,值越大范围越小,1是最大扩散范围值,10是最小扩散范围值。效果如下图所示:

示例代码为:

代码语言:javascript
复制
this.rabbitMaterial.enableTransmission = true;
this.rabbitMaterial.thinknessTexture = Loader.getRes("xxx/xxx.jpg");
this.rabbitMaterial.transmissionRata = 0.1;
//设置透射扩散范围系数为3.88
this.rabbitMaterial.backDiffuse = 3.88;

(点击代码,左右滑动查看全文)

transMissionColor是透射颜色属性,用于调整透光的颜色,下图分别是

Vector4(1,1,1,1)与Vector4(1,0,0,1) 的对比效果:

示例代码为:

代码语言:javascript
复制
this.rabbitMaterial.enableTransmission = true;
this.rabbitMaterial.thinknessTexture = Loader.getRes("xxx/xxx.jpg");
this.rabbitMaterial.transmissionRata = 0.1;
this.rabbitMaterial.backDiffuse = 3.88;
//设置透射光的颜色
this.rabbitMaterial.transmissionColor = new Vector4(1,1,1,1);

(点击代码,左右滑动查看全文)

backScale属性用于描述光透射后的强度,值越大,透射的光越强。效果如下图所示:

示例代码为:

代码语言:javascript
复制
this.rabbitMaterial.enableTransmission = true;
this.rabbitMaterial.thinknessTexture = Loader.getRes("xxx/xxx.jpg");
this.rabbitMaterial.transmissionRata = 0.1;
this.rabbitMaterial.backDiffuse = 3.88;
this.rabbitMaterial.transmissionColor = new Vector4(1,1,1,1);
//设置透射光的强度
this.rabbitMaterial.backScale = 1.2;

(点击代码,左右滑动查看全文)

除了引擎上的光线透射功能支持外,我们还为LayaAir的Unity插件也新增了对应的功能使用和导出。当开发者使用了LayaAir提供的Blinnphong材质,并为其设置了贴图后,直接在Unity中勾选Enable Transmission,调整相关的参数,导出即可直接使用。

渲染指令drawMeshInstance

LayaAir2.11版本另一个重磅功能是CommandBuffer增加了渲染指令drawMeshInstance,以及增加了DrawMeshInstancedCMD渲染命令类。

增加渲染指令DrawMeshInstance后,开发者可以用来渲染自定义instance属性,进行instance渲染。这种渲染相比普通的渲染会较大的提高渲染性能。

例如官网示例中的CommandBuffer_DrawCustomInstance就是自定义instance的优化示例,示例中自定义了小球的颜色,并且在满帧的情况下,实现了用一个渲染批次画出900个颜色不同的小球效果,体现了渲染优化的能力。

(通过drawMeshInstance渲染自定义instance示例效果的视频)

那我们应该如何使用drawMeshInstance渲染命令呢?

由于drawMeshInstance渲染命令在CommandBuffer中集成,所以当开发者实例化创建好CommandBuffer后,直接调用CommandBuffer的drawMeshInstance()方法在渲染命令流中添加DrawMeshInstanceCMD渲染指令。

示例代码为:

代码语言:javascript
复制
private instanceCMD:DrawMeshInstancedCMD;
private materialBlock:MaterialInstancePropertyBlock;

createCommandBuffer(camera:Camera){
    //创建渲染命令流
    let buf:CommandBuffer = new CommandBuffer();

    this.createMatrixArray();
    this.materialBlock= new MaterialInstancePropertyBlock();
    this.materialBlock.setVectorArray("a_InstanceColor",this.colors1,InstanceLocation.CUSTOME0);

    //创建渲染命令,渲染900个小球
    this.instanceCMD = buf.drawMeshInstance(PrimitiveMesh.createSphere(0.5),0,this.matrixs1,this.mat,0,this.materialBlock,900);
    camera.addCommandBuffer(CameraEventFlags.BeforeTransparent,buf);
    return;
}

(点击代码,左右滑动查看全文)

在上面的示例代码中,除了drawMeshInstance的基础使用流程外,还有一个要点(MaterialInstancePropertyBlock类)。这个类是用来描述instance自定义属性,比如给每一个Mesh分配一个不同的颜色。当然也可以是金属度、粗糙等任何材质描述属性。

开发者在更新instance自定义属性数据的时候,需要用对应的方法来更新对应类型的数据。方法与类型的对应列表如下所示:

在上面的示例中,渲染每一个Mesh的时候需要传入一个不同的颜色,而每一个颜色其实就是一个Vector4类型的属性。所以,我们要用setVectorArray()方法,传入一个Vector4的数组,或者是Vector4转换好的Float32Array,来设置shader中的CUSTOME0槽位名字为a_InstanceColor的instance属性。

示例代码就是这一段:

代码语言:javascript
复制
//改变900小球的颜色
this.materialBlock.setVectorArray("a_InstanceColor",this.currentColor,InstanceLocation.CUSTOME0);

(点击代码,左右滑动查看全文)

要注意的是,每一个槽位和属性名字要一一对应,属性名字和槽位也要对应声明shader中的顶点槽位,

例如下图中的shader顶点Attribute声明:

然后,我们再通过另一个截图看一下在Shader中的应用:

既然讲到shader相关,那我们再提一下,drawMeshInstance命令流设置对应的世界矩阵Matrix数组和自定义材质在shaderVS中的应用。

当大量渲染同一个Mesh的时候,需要用世界矩阵数组来描述每个Mesh的位置,引擎会更新对应的世界矩阵buffer,来保证每一个实例都能得到正确的worldMatrix。

在自定义材质中,声明attributeMap中需要写死a_WorldMat:VertexMesh.Mesh_WORLDMATRIX_ROW0,这样在shader中就可以接收到参数传入的矩阵。如下图所示。

按上面的步骤完成后,在顶点shaderVS中就可以对应使用了,使用的代码如下图所示。

drawMeshInstance功能知识点的最后,再介绍一下如何高性能的修改渲染个数drawNums、位置,以及修改自定义Instance属性。

首先,我们要更新修改位置,就需要调用DrawMeshInstanceCMD类的setWorldMatrix(worldMatrixArray:Matrix4x4[]))方法,然后传入最新的矩阵数组。

如果要更新修改渲染个数,我们还需要调用DrawMeshInstanceCMD类的setDrawNums(drawNums:number)方法,传入需要渲染的个数。

但需要注意的是,渲染个数(drawNums)不可以超过最大的instance数(DrawMeshInstancedCMD.maxInstanceCount)。

maxInstanceCount默认值为1024,开发者可以动态的修改。官网示例中同样使用到了drawMeshInstance的草地示例GrassDemo,就将这个值改为了1000000,草地示例的效果非常炫,欢迎大家前往官网示例中查看代码和效果,这里就不过多介绍了。

(用LayaAir引擎实现草地效果的视频)

除了修改渲染个数与位置外,如果我们要动态修改自定义Instance属性,我们需要调用MaterialInstancePropertyBlock中的方法setVectorArray、setVector3Array、setVector2Array、setNumberArray来设置更新类型为Vector4,Vector3,Vector2,number的自定义属性的数据,但是name和attributeLocation必须和之前设置的自定义属性匹配。

其它重要的3D功能更新

除了上面介绍的两个重要新特性之外,还有一些3D实用功能的更新。

首先是增加了打印Webgl指令的功能。

在以前的版本中,由于webgl报错并不能定位到准确位置,所在在本次版本中,我们提供了一种可以定位到哪个Webgl指令报错的方法。

开发者只需要将Config类中的静态属性printWebglOrder设置为true,就可以将webgl指令替换为LayaAir引擎内部指令方法,当webgl报错时,会直接暂停到报错的具体指令,更加方便的分析出现错误原因。

使用代码如下所示:

代码语言:javascript
复制
//在引擎init前设置
Config.printWebglOrder = true;

我们还在WebGLContext中增加_maxUniformFragMentVectors,用于描述uniform最大Vector数。可以在WebGLContext类中查到此设备的传入Shader的最大Vector数,传入的数据超过这个值会报webgl错误。

为Effect unlit材质增加U_ViewProjection,调整支持Instance的时候的计算方案,优化了效率。在这些材质的shader中传入Uniform U_ViewProjection,用来计算projectionPosition。

最后是优化了显存,删除InstanceMVPMatrix所需要的顶点buffer。

在原本的Instance方案中,我们会在CPU端,将所有的渲染实例MVP矩阵算好后,使用一个公用的VertexBuffer传入Shader中,修改后的方案将省去这个计算,减少了CPU端的压力,将计算分给GPU。

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Layabox 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档