关于Laya引擎的一些思考

列表中是怎么优化drawcall?

cacheAs是LayaAir引擎中提供的一个性能优化功能。在绘图或动画显示对象(如Sprite)频繁重绘时,对于一些不经常变化的内容,可以利用cacheAs属性将它们缓存起来,从而提高渲染效率。缓存后,这部分内容将会被绘制到一张位图上,之后的渲染将直接使用这张位图,减少了实时渲染的计算消耗。

cacheAs有三个参数可供选择:

  1. “none” :默认值,不进行缓存。
  2. “normal” :正常模式下的缓存,适用于大部分平稳变化的内容。缓存时会根据对象的实际内容尺寸,创建对应的缓存位图。
  3. “bitmap” :将显示对象及其子对象绘制到一张位图上,通常用于静态内容或者变化不频繁的内容。这种方式能大幅降低Sprite的渲染次数,节省性能开销,但也会增加内存的使用量。

使用cacheAs的时候需要注意以下几点:

  • 不是所有情况都适合开启cacheAs,如果一个对象频繁变化,那么反复重新缓存可能会消耗更多的性能。
  • cacheAs会根据设置不同,选择适当的时机来更新缓存。例如,当显示对象的子对象变化时,如果设置为normalbitmap模式,缓存才会更新。
  • 对于bitmap模式,缓存的尺寸会影响内存的使用,尽量不要缓存大尺寸的内容,否则会大量消耗内存资源。
  • 动态文本(例如频繁变化的计分板)不适合使用cacheAs进行优化,因为它们的内容变化会导致缓存频繁更新。
  • 设置cacheAs属性后,有些性能优化如“alpha = 0”时不渲染的特性会失效,因为即使是看不见的,它也会在缓存的位图中被绘制出来。
  • 在实际应用中,应合理利用并测试其性能优化效果,对于复杂动画或者交互密集的游戏,需要更细致地评估cacheAs的使用。

下面是一个简单的代码示例,说明如何设置cacheAs属性:

var sprite = new Laya.Sprite();

// 加载图片资源后,执行回调方法
Laya.loader.load("res/image.png", Laya.Handler.create(this, function() {
    var texture = Laya.loader.getRes("res/image.png");
    sprite.graphics.drawTexture(texture);

    // 设置缓存为normal
    sprite.cacheAs = "normal";

    Laya.stage.addChild(sprite);
}));

上述代码创建了一个名为sprite的显示对象,并加载了一张图片资源。在资源加载完成后,将图片绘制到sprite对象上,并且将cacheAs属性设置为normal模式,这样sprite的内容会被缓存在一张位图上,之后如果sprite不发生变化,LayaAir引擎就可以直接渲染这个缓存位图,而不需要重新计算绘制过程。

在使用cacheAs时,始终要记得衡量效能与内存开销,并寻找最佳的平衡点。

怎么优化动态合批?

  1. 共享材质:如果渲染的多个对象可以使用相同的着色器(Shader)和材质(Material),则这些对象可以被合并成一个批次进行渲染。尽量降低应用中使用的材质种类,可以有效提升合批的机会。

  2. 顶点属性和缓存限制:合批时顶点的数量不应超过硬件限制,否则不能合批。例如,许多硬件对单个Draw Call中顶点的数量有限制,通常是64K个顶点。

  3. 合理使用网格:合理设计和使用网格(Mesh),使得具有相似属性的网格可以被有效合并,这样做可以减少Draw Call的数量。

  4. 减少状态改变:渲染状态的改变(如混合模式、剔除模式、深度测试等)会阻断合批。应最小化这些状态的变化,以便更多对象能够合批。

  5. 注意透明度排序:对于有alpha或者透明度的物体,它们需要进行正确的深度排序,因为不正确的顺序可能会导致合批失败。

  6. 避免频繁的动态变化:频繁变动的对象(如位置、缩放或者旋转经常变化的对象)不容易进行合批处理,尽量将静态对象和动态对象分开来管理和渲染。

  7. 不要频繁修改对象子集:如果经常增加或删除对象的子对象,这将迫使引擎重新计算合批,从而造成性能损耗。

  8. 利用引擎提供的合批工具和功能:LayaAir引擎提供了一些内置工具和设置来帮助开发者进行合批,如Sprite3D的enableMerageInAtlas属性等。

  9. 做好性能剖析和测试:合理地使用引擎提供的性能分析工具,测试不同的设置和优化策略带来的性能变化,找出最适合你的游戏或应用的合批策略。

  10. 适当使用动态合批和静态批处理:除了动态合批之外,静态批处理也是一个有效的优化方法,特别适用于不会改变的场景元素。可以将静态对象做静态批处理,动态对象尽量减少绘制状态的改变以利于动态合批。

总的来说,优化动态合批的关键是减少渲染状态改变、共享材质和着色器、以及减少顶点数据大小和数量。采取上述策略时,始终记住测试性能以保障优化效果,优化策略需要根据具体项目和运行环境进行调整。

透明物体的渲染是怎么实现的?

透明物体的渲染是图形编程中的一个基本但不简单的主题,因为它涉及到复杂的透明度和深度测试问题。在2D和3D渲染中,透明效果通常是通过以下几个步骤实现的:

  1. Blending(混合)
    混合是实现透明物体渲染的核心。混合是一种图形技术,指的是将源颜色(即当前要渲染的像素颜色)和目标颜色(即帧缓冲区已有的像素颜色)按照某种方式混合在一起以生成最终的像素颜色。

混合通常由以下公式定义:

finalColor = (sourceColor * sourceFactor) + (destinationColor * destinationFactor)

其中,sourceFactor和destinationFactor是根据当前混合模式设定的值,用以控制源颜色和目标颜色的权重。

  1. 深度排序
    对于3D图形,深度排序极为重要。由于混合模式通常是非交换的(即A混合B可能与B混合A得到不同结果),为了正确地渲染透明对象,需要确保透明物体按从远到近的顺序绘制。

  2. 深度写入
    在渲染透明物体时,通常关闭深度写入(depth write)或者在混合操作之后进行,保证透明物体不会影响后面物体的渲染。如果不这样做,一个透明物体可能会意外地阻挡整个场景中后续的绘制。

  3. Alpha测试
    Alpha测试是一种过滤片段的方法,根据片段的alpha值(透明度)决定是否丢弃该片段。例如,片段的alpha值低于某个阈值时便丢弃,不执行混合。

  4. 预乘Alpha(Pre-Multiplied Alpha)
    预乘Alpha是一种优化透明度渲染的技术,即在存储颜色信息时,颜色分量已经乘以了Alpha值。它可以简化混合操作,同时在某些情况下提供更好的视觉效果。

  5. 渲染队列
    3D引擎中通常使用渲染队列来管理不同材质和物体的渲染顺序。不透明物体先渲染,透明物体后渲染。透明物体又按照从后往前的顺序排序渲染,以使得混合效果正常。

实现透明渲染还需要引擎或应用来协调合适的渲染状态和设置,以确保算法在各种渲染情况下都能妥善工作。在复杂场景中,正确渲染透明物体可能要求更多高级技术和算法,例如深度剔除、权重混合、双边透明或透明度遮罩等技术。

文本的进阶使用

1.文本的底层渲染机制

LayaAir引擎在文本的底层渲染上,有两种方式。

分别是Text文本类的文本统一提交方式,和Graphics类的fillText文本单字符绘制提交方式。

如果采用了Text文本,那每一个Text文本对象中的文本字符会一起形成小图集提交到大图合集中,比如游戏中某个文本对象有300字,其中一个字符发生改变,也会对该文本对象的300字整段文本图集重新提到大图合集中。

又假如,在一个剧情游戏中,两人在对话。那其中一个文本对象,要不断的重新取值和赋值操作,使得该文本对象的显示内容频繁发生改变。此时,Text文本对象,就会不断的向大图合集进行文本图集的提交,占满大图集后,又需要创建一个新的图集继续提交,而不用的旧图集,如果没达到GC条件,也会一直存在,所以如果此次查看内存占用统计信息,就可以看到会一直在涨内存,直到GC条件达到之后,才会被销毁。并且GC在清空垃圾内存的时候,还有可能会导致瞬间的卡顿。

而采用Graphics类的fillText文本绘制,则是按单个字符向大图合集中进行提交,并且大图合集中已经存在的字符不会重复提交。所以对于图集的利用率比较好,即便是发生文本改变的时候,也不会向Text文本那样,创建很多垃圾图集。

这样看来,是不是fillText就是最好用的呢?

如果文本不需要改变,那按单字提交图集的效率是不如一次性直接提交的。

所以,我们还是要看文本的类型,对应文本使用时的类型,选用相应的引擎API,才会更好。

2. 静态文本与动态文本

基于上一小节的文本渲染提交的机制,以及文本仅用于展示或用于交互的区别,我们分成两种概念,就是把仅用于显示,文本内容无需改变的文本叫静态文本。对于文本内容需要改变的文本叫动态文本。

Text和Label都属于处理静态文本的类,它们都是把文本的每次改动都统一提交大图集的渲染机制。

fillText、fillBorderText、strokeText等,都是Graphics类中用于单字符提交的文本绘制方法。

在LayaAirIDE中,Text和Label属于静态文本组件,而LayaAir引擎中Graphics类的fillText、fillBorderText、strokeText等文本绘制方法,在IDE中是没有封装为组件的,需要在项目代码中直接使用引擎的API。

3. 不同的文本API的使用区别与选择

如果我们已经理解了什么是静态文本和动态文本,那使用起来的选择就比较简单了,例如,一些导航和标签按钮等,他在UI上完全没有必要进行改变,完全可以使用静态文本。文字剧情和任务等,就需要动态文本了。

那静态文本组件有Text和Label两种,那是怎么选择呢。

其中Text是最基础的文本组件,他直接继承于Sprite,而Label继承于UIComponent再往上才是Sprite,从原理上,路径越短,性能自然越好。所以,比较简单的文本,当Text可以满足时,原则上优先使用Text,而Label由于属性非常丰富,适用于相对布局等等Text无法满足的应用场景。

对于fillText而言,我们不仅要了解它的优势,也要了解他的不足。fillText文本由于是引擎自己绘制的,目前只适用于中英文等主流国家语言,对于泰国语、阿拉伯语等复杂的语言,显示可能会有异常。所以对于这些排版复杂的国际语言游戏,那只能是采用静态文本组件的系统字或者是位图字,尽可能减少文本动态修改的产品需求。

4. 使用时要注意的

静态的文本优先使用Text组件,因为只显示静态文本的时候性能最好。动态文本优先使用fillText,除非是国际化等需求不能满足的时候。

静态文本,对于有相对布局等复杂需求时,Label组件的功能比较强大。

fillText的代码使用方法说明如下:

 /**
     * 在画布上绘制文本。
     * @param text 在画布上输出的文本。
     * @param x 开始绘制文本的 x 坐标位置(相对于画布)。
     * @param y 开始绘制文本的 y 坐标位置(相对于画布)。
     * @param font 定义字号和字体,比如"20px Arial"。
     * @param color 定义文本颜色,比如"#ff0000"。
     * @param textAlign 文本对齐方式,可选值:"left","center","right"。
     */
    fillText(text: string | WordText, x: number, y: number, font: string, color: string, textAlign: string): FillTextCmd {
        return this.addCmd(FillTextCmd.create(text, x, y, font, color, textAlign, 0, ""));
    }

这里重点介绍一下fillText中font属性与其它几个文本font属性区别,fillText示例代码如下:

    /**
     * 组件被激活后执行,此时所有节点和组件均已创建完毕,此方法只执行一次
     */
    onAwake(): void {
        let sprite = new Laya.Sprite();
        Laya.stage.addChild(sprite);
        sprite.graphics.fillText("fillText:引擎绘制的文本,适合简单的单行文本", 100, 300, " 60px  simHei  ", "#ff0000", "left");
    }

在Text与Label中,font仅仅是指系统字体,例如该文本是Microsoft YaHei还是Arial,选择或者输入对应的字体就可以。而fillText中,font是字体与字体大小的设置值,也可以把所有相关的文本样式(大小、字体、斜体、加粗)也在这里指定。

例如,当值为 60px simHei ,是将文本大小设置为60像素大小,采用simHei字体。
在这里插入图片描述
值为60px simHei italic 增加了斜体效果。
在这里插入图片描述
值为bold 60px simHei italic 增加了文本加粗效果。
在这里插入图片描述

Tips:
大小与字体是必须设置的,并且在字体必需要放到文本px大小的后面。
bold需要放到文本px大小的前面。

事件通信的底层原理是什么?

LayaAir 中的事件系统基本原理如下:

  1. 事件监听器(Event Listeners):
    在LayaAir中,事件系统允许你为特定对象注册事件监听器,这些监听器会在特定事件发生时响应。事件监听器通常是函数或者方法,它们会被绑定到特定对象和特定的事件类型。

  2. 事件对象(Event Objects):
    事件对象包含了关于该事件的所有信息。当事件发生时(例如:鼠标点击、键盘按下、触摸等),事件对象会被创建并传递给所有监听该事件的回调函数。

  3. 事件分发(Event Dispatching):
    当事件发生时,事件源会分发事件对象给所有注册的监听器。事件源可以是任何对象,比如DisplayObject,也可以是全局的对象,比如stage。

  4. 事件冒泡(Event Bubbling):
    LayaAir 支持事件冒泡,事件可以从产生事件的最深层节点开始,逐层向上传递至舞台(stage)。监听器可以在事件穿过其所在的层级时接收并处理事件。

  5. 事件捕获(Event Capturing):
    相对于事件冒泡,事件捕获是事件从顶层节点向下传递到事件源的过程。虽然在DOM事件模型中,事件捕获是一个重要概念,但在LayaAir中,事件主要还是通过冒泡进行传递。

  6. 事件优先级(Event Priority):
    如果有多个监听器监听相同的对象和事件,可以为这些监听器设置优先级以确定它们的调用顺序。

LayaAir 的事件系统是基于观察者模式的实现。观察者模式是一个对象(称为“subject”或“observable”)维护一系列依赖于它的对象(称为“observers”),并在其状态发生变化时自动通知它们。在LayaAir中,任何一个DisplayObject都可以被视为subject,能够维护一系列观察者(事件监听器)。

这样的事件通信系统设计使得游戏中的各种组件之间能够低耦合地相互交互,提高了代码的模块性、可重用性和可维护性。

ReflectionProbe

什么是ReflectionProbe:
反射探针可以从各个方向捕获周围的环境,然后将捕获到的内容存储为CubeMap(立方体贴图),可供给具有反射材料的对象使用。在一个场景中可以使用多个反射探针,探针可在场景中的关键点对视觉环境进行采样。当反射对象靠近探针时,探针采样的反射可用于对象的反射贴图。此外,当几个探针位于彼此附近时,引擎可在它们之间进行插值,从而实现反射的逐渐变化。因此,使用反射探针可以产生非常逼真的反射,同时将处理开销控制在可接受的水平。

反射探针的工作原理:
探针的捕获环境可由CubeMap表示,CubeMap在概念上很像一个在内部表面绘制有立方体六个面图像的盒子,需要Shader必须能够采样CubeMap的图像。对象表面的每个点都可在表面朝向的方向(即表面法向矢量的方向)上“看到”立方体贴图的一小块区域。着色器在此处使用立方体贴图的颜色来计算对象表面应该是什么颜色,下图展示了CubeMap和天空盒的对比结果。
在这里插入图片描述

GLSL的数据传递

1.应用处理阶段

模型在应用处理阶段被整合为基本片元(三角形),从模型中获取到不同的属性坐标信息,红色框选部分为应用处理阶段。
在这里插入图片描述

2.顶点着色器阶段

应用阶段完成计算后的一些值作为uniform传入顶点着色器参与计算,然后再通过varing类型的形式传入到光栅化以及后面的片段着色器部分,红色框选部分为顶点着色器阶段。
在这里插入图片描述
3.片段着色器片段
在光栅化阶段完成颜色插值之后的varing类型结果,传入到片段着色器中,片段着色器对颜色值进行处理,将结果输出到对应的缓冲区(分为颜色缓冲区和深度缓冲区),这个步骤为图中的红色框选部分。
在这里插入图片描述

材质的渲染模式

在LayaAir中不同的材质有着不同的渲染模式,不同的模式下的渲染结果是不相同的,常见的渲染模式如下图红色框选内容所示:
在这里插入图片描述

模式描述
OPAQUE(不透明)无任何透明效果,即使贴图中有半透明,模型也不会发生半透明效果,Alpha值不影响最终渲染效果,始终为1
CUTOUT(镂空)根据包含Alpha信息的贴图中采样出来的Alpha值进行透明裁剪,也可以根据图13-2中的AlphaTest的值与贴图中采样的Alpha值进行对比来进行裁切,这样裁剪出来的结果造成的空洞部分与正常部分会产生严重的锯齿,但效率高,如果锯齿效果影响严重,建议是采样TRANSPARENT模式,透明的结果就会比较线性。
TRANSPARENT(半透明)根据贴图中Alpha值来进行半透明的渲染或者给定固定的Alpha值来进行渲染。
ADDTIVE(加色混合)主要用于一些透明并颜色亮度较高的材质,它会根据贴图像素的亮度进行加色混合,模型正面与背面贴图颜色、相重叠的模型的贴图颜色会相互叠加,形成高亮半透明效果。
ALPHABLENDED(透明混合)这意味着对象为半透明的模式,但是最终像素的着色的混合模式不同,AlphaBlended混合方式为SrcAlpha SrcColor + (1 - SRCAlpha) DstColor,通常来说SrcAlpha来自纹理的Alpha值。

UI滤镜效果

滤镜,主要是用来实现图像的各种特殊效果,使图像取得最佳艺术效果。滤镜的类型有很多,但是营造不同的效果需要不同的滤镜功能。

LayaAir提供了创建颜色滤镜(ColorFilter)、模糊滤镜(BlurFilter)、发光滤镜(GlowFilter)三种效果,其中模糊滤镜与发光滤镜对性能的消耗较大。

不同滤镜效果可以叠加使用并同时生效,开发者可以根据需要进行设置。

在这里插入图片描述

1.颜色滤镜

ColorFilter是颜色滤镜,颜色滤镜是图像后期处理中非常重要的一部分,它可以改变原有图像中的各种参数,从而在不改变图像大体的前提下,使其呈现出不同的风格。在实际操作时,颜色滤镜主要改变的参数为亮度、对比度、饱和度、色调等,整体来讲只改变颜色,并不对图像进行任何变形处理。正确地使用颜色滤镜,可以修正图像非正常曝光、缓解图片失真现象,从而突出主要细节,弱化掉一些不太好的部分。在艺术领域,颜色滤镜还被用来呈现不同的美学风格。

颜色滤镜有5个属性:
在这里插入图片描述

  • Color:设置滤镜颜色。
  • Brightness:调整亮度。
  • Contrast:调整对比度。
  • Saturation:调整饱和度。
  • Hue:调整色调。

使用ColorFilter类直接创建滤镜,示例代码如下:

const { regClass, property } = Laya;

@regClass()
export class NewScript extends Laya.Script {

    // 获得Image组件
    @property({ type: Laya.Image })
    public img: Laya.Image;

    //组件被激活后执行,此时所有节点和组件均已创建完毕,此方法只执行一次
    onAwake(): void {
        //创建一个颜色滤镜对象
        let colorFilter: Laya.ColorFilter = new Laya.ColorFilter();
        //给Image组件添加颜色滤镜
        this.img.filters = [colorFilter];
        //设置滤镜颜色
        colorFilter.color(0.5, 0.5, 0.5, 1);
        //设置滤镜亮度
        colorFilter.adjustBrightness(-50);
        //设置滤镜对比度
        colorFilter.adjustContrast(8);
        //设置滤镜饱和度
        colorFilter.adjustSaturation(30);
        //设置滤镜对比度
        colorFilter.adjustHue(-15);
    }
}

2.模糊滤镜

BlurFilter是模糊滤镜,能够产生模糊的效果。

模糊滤镜只有1个属性:
在这里插入图片描述

  • Strength:模糊滤镜的模糊强度值,数值越大越模糊。

使用BlurFilter类直接创建滤镜,示例代码如下:

const { regClass, property } = Laya;

@regClass()
export class NewScript extends Laya.Script {

    // 获得Image组件
    @property({ type: Laya.Image })
    public img: Laya.Image;

    //组件被激活后执行,此时所有节点和组件均已创建完毕,此方法只执行一次
    onAwake(): void {
        let blurFilter: Laya.BlurFilter = new Laya.BlurFilter();
        // 设置模糊强度
        blurFilter.strength = 5;
        // 给Image组件添加模糊滤镜
        this.img.filters = [blurFilter];
    }
}

3.发光滤镜

GlowFilter是发光滤镜,就是创建放光效果或者阴影的效果,比如外发光。

发光滤镜有3个属性:
在这里插入图片描述

  • Offset:发光滤镜相对于组件的偏移,X轴方向和Y轴方向。
  • Blur:发光滤镜的边缘模糊大小,数值越大,边缘越模糊。
  • Color:发光滤镜的颜色。

使用GlowFilter类直接创建滤镜,示例代码如下:

const { regClass, property } = Laya;

@regClass()
export class NewScript extends Laya.Script {

    // 获得Image组件
    @property({ type: Laya.Image })
    public img: Laya.Image;

    //组件被激活后执行,此时所有节点和组件均已创建完毕,此方法只执行一次
    onAwake(): void {
        // 创建发光滤镜,创建时初始化滤镜
        let glowFilter: Laya.GlowFilter = new Laya.GlowFilter("#ffff00", 10, 0, 0);
        // 给Image组件添加发光滤镜
        this.img.filters = [glowFilter];
    }
}

纹理压缩

纹理是指物体表面的纹路样式和细腻程度等外观效果。在计算机图形学中,常用于描述三维模型表面图案的二维图形。

我们日常见到和使用的图片格式,主要为PNG和JPG,虽然在三维和二维的某些情况下,也会把这些图片称为纹理,但他们并不是纹理格式,不能被GPU直接读取并显示。因此,这些图片文件要先经过CPU解码成纹理格式,再传送到GPU进行使用。

而纹理格式,自然就是可以被GPU直接读取并显示的格式。所以,一方面,避免CPU解码可以减少运算带来的性能压力。另一方面,就是直接读取并渲染,也可以避免图像解压到内存的占用开销。

纹理压缩的目的
1:降低内存,特别是移动端应用,内存占用不应过大,否则低端机很容易崩溃。
2:降低带宽,手游类应用,在渲染时会有大量贴图传输到GPU,不限制的话不仅会严重影响渲染性能,同时会带来很严重的发热。

纹理格式种类

  1. ASTC(Adaptive Scalable Texture Compression)是一种世界领先的新型纹理压缩格式。ASTC由ARM和AMD联合开发,2012年发布。是一种基于块的有损压缩算法。它的压缩分块从4x4到12x12最终可以压缩每个像素占用1bit以下,并且ASTC格式支持RGBA。以ASTC 4x4 Block Size为例,可以看到每个像素占用8bits即1个字节。因此一张1024x1024的RGBA图片按照该格式压缩后占用的内存大小为1MB。如果你的纹理是选择了生成mipmap的话,那么最终的资源大小还需要乘以1.333也就是大约1.333MB。而相对应的如果采用了ASTC 8x8的格式进行压缩的话,最终纹理资源的大小就应该是 1024 × 1024 × 2 × 1.333333 ÷ 8 ≈ 341K。所以如果想要使用10x10或12x12这种更小的压缩格式的话,选用这两种格式基本也就意味着放弃对画质的基本要求了。因此我们推荐使用6x6的压缩格式。
  2. ETC(Ericsson Texture Compression)最初为移动设备开发,如今它是安卓的标准压缩方案,ETC1在OpenGL和OpenGL ES中都有支持。 RGB ETC1 4 bit:4 bits/pixel,对RGB压缩比6:1,不支持Alpha,绝大部分安卓设备都支持。 RGB ETC2 4 bit:4 bits/pixel,对RGB压缩比6:1。不支持Alpha,ETC2兼容ETC1,压缩质量可能更高,但对于色度变化大的块误差也更大,需要在OpenGL ES 3.0和OpenGL 4.3以上版本。 RGBA ETC2 8bit:8 bits/pixel,对RGBA压缩比4:1。支持完全的透明通道,版本要求同上。
  3. PVRTC(PowerVR Texture Compression)由Imagination公司专为PowerVR显卡核心设计,由于专利原因一般它只被用于苹果的设备,仅iPhone、iPad和部分PowerVR的安卓机支持。
  4. DXTC(或BC)是微软为DX而推出的基于block的贴图压缩格式,其主要采用调色板的原理来进行压缩。BC1(Block Compression)是最小的一种变体,也是转换比最高的一种,在不需要高精度也不需要a值时可以使用。它将4x4个像素作为一个块(block)存储64位数据,不含有alpha通道,每个block内记录两个16bits的颜色做为基准颜色,然后解压时再使用两个基准色调制出另外两个颜色做为块内4个压缩颜色。
  5. BC3在BC1的基础上支持alpha通道。首先,颜色的存储方式与BC1相同,需要64bits;对于alpha部分,使用与颜色部分相同的策略来处理。在block存储两个基准的alpha值,然后在其基础上插值得到其它6个共计8个alpha值,来做为alpha的调色板;然后对于每个texel存储一个3bits的索引,用来指向到这8个alpha中的一个。

后处理

后处理是现代游戏中必不可少的技术之一,PostProcessing,通常在普通的场景渲染结束后对结果进行处理,将一张或数张Texture处理得到一张新的Texture。

PostProcessing的渲染Pipeline普通的模型渲染一样,不同之处在于在顶点着色器中通常只是简单的拷贝,主要的逻辑写在片段着色器中

下面的图像展示了应用和未应用后期处理的场景。
在这里插入图片描述

未应用后期处理的场景

在这里插入图片描述

应用后期处理后的场景

引擎内置后处理类型:

1.ScalableAO

环境光遮蔽效果用于计算场景中暴露在环境照明下的点。然后,它会使隐藏在环境光之外的区域变暗,例如折痕、孔洞和靠近的物体之间的空间。

您可以通过两种方式实现环境光遮蔽效果:作为全屏后期处理效果实时实现。实时环境光遮蔽效果可能会占用大量资源。它对处理时间的影响取决于屏幕分辨率和效果属性。
在这里插入图片描述
可拓展环境光遮蔽参数类型:

参数类型参数解释
AO Color设置环境光遮挡的颜色
Intensity环境光遮挡产生强度
Radius设置采样点的半径,以控制环境光遮蔽区域的范围
AO Quality环境光遮蔽效果质量(高-中-低三档)

2.Bloom

Bloom效应使图像中的明亮区域发光。为了做到这一点,它创建的边缘光从明亮的领域扩展到你的形象。这模拟了真实世界中的照相机在光线淹没镜头时所产生的效果。布鲁姆效果也有一个肮脏的功能,你可以用它来应用一个全屏幕层的污迹或灰尘来衍射Bloom效果。
在这里插入图片描述
Bloom参数类型:

参数类型参数解释
Clamp设置钳制像素的值以控制 Bloom 数量
Color选择 Bloom 的颜色
Fast Mode快速模式
Dirt Texture选择一个肮脏的纹理添加污迹或灰尘的镜头
Intensity设置镜头肮脏的强度
Threshold设置亮度级别以过滤掉此级别下的像素
Soft Knee为低于/超过阈值(0 = 硬阈值,1 = 软阈值)之间的转换设置渐进阈值。
Diffusion与屏幕分辨率无关的方式设置面纱效果的范围。
Anamorphic Ratio设置比例以垂直(范围[ -1,0])或水平(范围[0,1])缩放 Bloom。这模拟了变形透镜的效果。

3.GaussianDoF

景深是一种常见的模拟相机镜头焦距特性的后处理效果。在现实生活中,相机只能在一定距离内对物体进行锐利的聚焦; 离相机较近或较远的物体会有点失焦。这种模糊不仅提供了一个关于物体距离的视觉线索,而且还引入了 Bokeh,这是一个术语,用来描述当图像的明亮区域失焦时出现的令人愉快的视觉伪影。

在这里插入图片描述
GaussianDoF参数类型:

参数类型参数解释
Far Start景深开始值
Far End景深结束值
Max Radius最大模糊景深半径
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值