IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 游戏引擎Flax Engine分析(八)渲染 -> 正文阅读

[游戏开发]游戏引擎Flax Engine分析(八)渲染

?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()将两个整数相除并向上取整。

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

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

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

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章           查看所有文章
加:2021-11-17 13:04:30  更:2021-11-17 13:06:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 23:33:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码