游戏引擎Flax Engine分析(八)渲染

news/2024/10/17 4:46:27/

 2021SC@SDUSC


一、简述

        我们继续之前的博客分析2D渲染服务后续的内容。边学习边分析渲染流程。

二、分析

         接下来一些服务主要提供对于变换矩阵、颜色等熟悉的操作,诸如入栈、弹出等,这里不再赘述。

        我们先看一下在之前分析的结束渲染时进行的批处理元素的刷新:

DrawBatch(batchStart, batchSize);

        对于DrawBatch()这个函数: 

    const Render2DDrawCall& d = DrawCalls[startIndex];GPUBuffer* vb = VB.GetBuffer();GPUBuffer* ib = IB.GetBuffer();uint32 countIb = 0;for (int32 i = 0; i < count; i++)countIb += DrawCalls[startIndex + i].CountIB;

        startIndex 是函数的第一个参数batchStart,首先根据该参数获取绘图调用对象;

        VB是允许在单帧期间渲染任何顶点的动态顶点缓冲区(支持动态调整大小);IB是允许在单帧期间呈现任何索引的动态索引缓冲区(支持动态调整大小);它们都继承自DynamicBuffer,是允许在单帧期间更新和使用 GPU 数据(索引/顶点/其他)的动态 GPU 缓冲区(支持动态调整大小)。

        循环中的count为函数的第二个参数,这里使用countIb记录总的IB大小。

    if (d.Type == DrawCallType::ClipScissors){Rectangle* scissorsRect = (Rectangle*)&d.AsClipScissors.X;Context->SetScissor(*scissorsRect);IsScissorsRectEmpty = scissorsRect->Size.IsAnyZero();return;}if (IsScissorsRectEmpty)return;

        判断上面获取的绘图调用的类型,枚举的绘图调用类型如下:

enum class DrawCallType : byte
{FillRect,FillRectNoAlpha,FillRT,FillTexture,FillTexturePoint,DrawChar,DrawCharMaterial,Custom,Material,Blur,ClipScissors,LineAA,MAX
};

        这里首先判断绘图调用类型是否为剪刀,接下来获取绘图调用中的子结构体AsClipScissors的X属性,并设置剪刀矩形。获取值IsScissorsRectEmpty,该值指示任何向量分量是否为零。

        判断剪刀为特殊情况,下面根据绘图调用类型的不同,对Context进行不同的设置:

switch (d.Type){case DrawCallType::FillRect:Context->SetState(CurrentPso->PS_Color);break;case DrawCallType::FillRectNoAlpha:Context->SetState(CurrentPso->PS_Color_NoAlpha);break;case DrawCallType::FillRT:Context->BindSR(0, d.AsRT.Ptr);Context->SetState(CurrentPso->PS_Image);break;case DrawCallType::FillTexture:Context->BindSR(0, d.AsTexture.Ptr);Context->SetState(CurrentPso->PS_Image);break;case DrawCallType::FillTexturePoint:Context->BindSR(0, d.AsTexture.Ptr);Context->SetState(CurrentPso->PS_ImagePoint);break;case DrawCallType::DrawChar:Context->BindSR(0, d.AsChar.Tex);Context->SetState(CurrentPso->PS_Font);break;

        BindSR所做的工作是将纹理绑定到着色器资源槽。

        这里我们重点看一下绘图调用类型 绘制字符材质 时所做的工作:

case DrawCallType::DrawCharMaterial:{// 应用和绑定材料auto material = d.AsChar.Mat;MaterialBase::BindParameters bindParams(Context, *(RenderContext*)nullptr);bindParams.CustomData = &ViewProjection;material->Bind(bindParams);// 绑定字体图集作为材质参数static StringView FontParamName = TEXT("Font");auto param = material->Params.Get(FontParamName);if (param && param->GetParameterType() == MaterialParameterType::Texture){Context->BindSR(param->GetRegister(), d.AsChar.Tex);}// 绑定索引和顶点缓冲区Context->BindIB(ib);Context->BindVB(ToSpan(&vb, 1));// 绘制Context->DrawIndexed(countIb, 0, d.StartIB);// 恢复管道(材料应用覆盖它)const auto cb = GUIShader->GetShader()->GetCB(0);Context->BindCB(0, cb);return;}

        当绘图调用的类型为Material 材质时,流程与 绘制字符材质 大致相同:

case DrawCallType::Material:

        绘图调用类型为 模糊 时:

const Vector4 bounds(d.AsBlur.UpperLeftX, d.AsBlur.UpperLeftY, d.AsBlur.BottomRightX, d.AsBlur.BottomRightY);float blurStrength = Math::Max(d.AsBlur.Strength, 1.0f);auto& limits = GPUDevice::Instance->Limits;int32 renderTargetWidth = Math::Min(Math::RoundToInt(d.AsBlur.Width), limits.MaximumTexture2DSize);int32 renderTargetHeight = Math::Min(Math::RoundToInt(d.AsBlur.Height), limits.MaximumTexture2DSize);

        根据调用的参数定义边界 bounds,blurStrength模糊强度,由GPU实例对象获取GPU限制,

渲染目标宽度和长度取 绘图调用传来的参数 和 GPU限制的2D 纹理的最大尺寸 两者中的最小值

        int32 kernelSize = 0, downSample = 0;CalculateKernelSize(blurStrength, kernelSize, downSample);if (downSample > 0){renderTargetWidth = Math::DivideAndRoundUp(renderTargetWidth, downSample);renderTargetHeight = Math::DivideAndRoundUp(renderTargetHeight, downSample);blurStrength /= downSample;}

        初始化内核大小和下采样为0,再以上面获取的模糊强度为参数计算内核大小,这里具体计算方法我们不在分析。然后判断下采样值,若大于零,则根据下采样的值改变渲染目标的宽度和高度以及模糊强度,这里DivideAndRoundUp()将两个整数相除并向上取整。

        对于模糊,下面还有一系列操作,这里就不再放上代码,而是简单介绍一下进行了哪些操作:

  • 如果没有机会渲染任何内容,则返回;
  • 获取临时纹理
  • 准备模糊数据
  • 缩小(或不缩小)并提取背景图像以进行模糊处理
  • 渲染模糊(第一遍)
  • 渲染模糊(第二遍)
  • 恢复输出
  • 将最终模糊绘制链接为纹理
  • 释放 

         这次的分析就到这里为止。


http://www.ppmy.cn/news/569982.html

相关文章

@Valid接口参数校验怎么做,详细教程

接口参数校验教程 一、在字段上可以使用这个注解来设置校验 Null&#xff1a;被注释的元素必须为null NotNull&#xff1a;被注释的元素不能为null AssertTrue&#xff1a;该字段只能为true AssertFalse&#xff1a;该字段的值只能为false Min("value","messa…

游戏引擎Flax Engine分析(六)渲染

2021SCSDUSC 一、简述 这篇博客继续上一篇未分析完的部分继续分析&#xff0c;分析2D渲染服务。 二、分析 我们先看一下我们曾在Render2D.h这个头文件中介绍过的开始渲染函数&#xff0c;其有多个重载&#xff1a; API_FUNCTION() static void Begin(GPUContext* context, GP…

游戏引擎概述-Part1

一、简述自己的学习心路历程 自从业UNITY以来已经有4个月多了&#xff0c;回想起来自己从工作以来就很少写博客了&#xff0c;也算督促一下自己&#xff0c;回想自己从最早的Unity开始&#xff0c;入手C#和编辑器、Unity开发界面&#xff0c;再到自己学一些Unity的小项目…

Hazel游戏引擎

Hazel游戏引擎 Cherno开源项目gitee版本github到gitee(码云) Cherno开源项目gitee版本 看了b站的游戏引擎开发教学&#xff0c;内附的项目地址是github的&#xff0c;国内访问实在不便&#xff0c;遇到了诸多问题&#xff1a;所以将他的项目从github迁移到了gitee上。2021/10/…

Chrome V8引擎介绍

0.v8引擎出现的原因 这里先说一下什么是编译型语言和解释性语言&#xff1a; 编译型语言&#xff1a; 在程序执行之前必须进行专门的编译过程&#xff0c;有如下特点&#xff1a; 只须编译一次就可以把源代码编译成机器语言&#xff0c;后面的执行无须重新编译&#xff0c;直…

十大最牛游戏引擎

游戏引擎就像是游戏的发动机&#xff0c;好的游戏引擎能够让游戏开发事半功倍。而对玩家们来说&#xff0c;游戏引擎能够带来最直观的感受就是游戏的画面和细节表现。从光影声效到场景细节&#xff0c;从画面触感到各种细腻体验&#xff0c;再到人物表情的捕捉&#xff0c;花草…

HTML5开源RPG游戏引擎lufylegendRPG 0.1发布

一&#xff0c;小小开篇 首先不得不先介绍一下这个引擎&#xff1a; lufylegendRPG是lufylegend的拓展引擎&#xff0c;使用它时&#xff0c;需要引入lufylegend。同时您也需要了解lufylegend语法&#xff0c;这样才能更合理地运用lufylegendRPG。该引擎封装了lufylegend的一些…

游戏引擎简介

目录 什么是游戏引擎游戏引擎模块划分常见的游戏引擎碎碎念 什么是游戏引擎 游戏引擎是由多个子系统共同构成的复杂系统&#xff0c;它几乎涵盖了游戏开发过程中的所有重要环节。 以上来自百度百科&#xff0c;听起来很牛&#xff0c;上次听到这么牛的描述还是上次… 游戏引…