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源码分析(十)渲染

一、概述

? ? ? ? 这篇博客我们继续之前的内容,分析2D渲染。

二、分析

? ? ? ? 接下来的大多数渲染方法,诸如?绘制纹理,绘制Sprite,绘制纹理(使用点采样器),绘制Sprite(使用点采样器)(关于Sprite在游戏引擎中的含义这里不再赘述,若是感兴趣的话可以自己去搜索一下),本质上都调用了一个WriteRect()方法。

static void DrawTexture(GPUTextureView* rt, const Rectangle& rect, const Color& color = Color::White);
static void DrawSprite(const SpriteHandle& spriteHandle, const Rectangle& rect, const Color& color);
static void DrawTexturePoint(GPUTexture* t, const Rectangle& rect, const Color& color = Color::White);

? ? ? ? 首先,我们?看一下DrawTexture()方法是如何一步一步调用WriteRect()的:

void Render2D::DrawTexture(GPUTextureView* rt, const Rectangle& rect, const Color& color)
{
    RENDER2D_CHECK_RENDERING_STATE;

    Render2DDrawCall& drawCall = DrawCalls.AddOne();
    drawCall.Type = DrawCallType::FillRT;
    drawCall.StartIB = IBIndex;
    drawCall.CountIB = 6;
    drawCall.AsRT.Ptr = rt;
    WriteRect(rect, color);
}

? ? ? ? 这里可以很简单的看到在判断当前渲染状态之后,创建了一个2D绘图调用的对象,对对象内部的参数进行了配置之后就调用了WriteRect()。

????????我们再看一下DrawSprite()方法:

void Render2D::DrawSprite(const SpriteHandle& spriteHandle, const Rectangle& rect, const Color& color)
{
    RENDER2D_CHECK_RENDERING_STATE;
    if (spriteHandle.Index == INVALID_INDEX || !spriteHandle.Atlas || !spriteHandle.Atlas->GetTexture()->HasResidentMip())
        return;

    Sprite* sprite = &spriteHandle.Atlas->Sprites.At(spriteHandle.Index);
    Render2DDrawCall& drawCall = DrawCalls.AddOne();
    drawCall.Type = DrawCallType::FillTexture;
    drawCall.StartIB = IBIndex;
    drawCall.CountIB = 6;
    drawCall.AsTexture.Ptr = spriteHandle.Atlas->GetTexture();
    WriteRect(rect, color, sprite->Area.GetUpperLeft(), sprite->Area.GetBottomRight());
}

? ? ? ? 与DrawTexture()方法大致相同,因此接下来我们直接看最关键的WriteRect()方法:

? ? ? ? 首先WriteRect()共三个重载:

void WriteRect(const Rectangle& rect, const Color& color1, const Color& color2, const Color& color3, const Color& color4);
void WriteRect(const Rectangle& rect, const Color& color, const Vector2& uvUpperLeft, const Vector2& uvBottomRight);
FORCE_INLINE void WriteRect(const Rectangle& rect, const Color& color);

? ? ? ? 前两个重载所做的事情差不多,而第三个重载函数调用第二的重载函数,因此这里我们只看第二个重载函数:

void WriteRect(const Rectangle& rect, const Color& color, const Vector2& uvUpperLeft, const Vector2& uvBottomRight)
{
    Render2DVertex quad[4];
    quad[0] = MakeVertex(rect.GetBottomRight(), uvBottomRight, color);
    quad[1] = MakeVertex(rect.GetBottomLeft(), Vector2(uvUpperLeft.X, uvBottomRight.Y), color);
    quad[2] = MakeVertex(rect.GetUpperLeft(), uvUpperLeft, color);
    quad[3] = MakeVertex(rect.GetUpperRight(), Vector2(uvBottomRight.X, uvUpperLeft.Y), color);
    VB.Write(quad, sizeof(quad));

    uint32 indices[6];
    RENDER2D_WRITE_IB_QUAD(indices);

    VBIndex += 4;
    IBIndex += 6;
}

? ? ? ? 对顶点进行运算后存入缓冲区中。?


? ? ? ? ?然后是其他几个诸如使用 9 切片绘制纹理,使用 9 切片(使用点采样器)绘制纹理,使用 9 切片绘制Sprite,使用 9 切片(使用点采样器)绘制Sprite。

static void Draw9SlicingTexture(TextureBase* t, const Rectangle& rect, const Vector4& border, const Vector4& borderUVs, const Color& color = Color::White);
static void Draw9SlicingTexturePoint(TextureBase* t, const Rectangle& rect, const Vector4& border, const Vector4& borderUVs, const Color& color = Color::White);
static void Draw9SlicingSprite(const SpriteHandle& spriteHandle, const Rectangle& rect, const Vector4& border, const Vector4& borderUVs, const Color& color = Color::White);
static void Draw9SlicingSpritePoint(const SpriteHandle& spriteHandle, const Rectangle& rect, const Vector4& border, const Vector4& borderUVs, const Color& color = Color::White);

? ? ? ? ?同样的我们据其中一个为例子看一下它的执行过程,这里我们选择Draw9SlicingTexturePoint():

void Render2D::Draw9SlicingTexturePoint(TextureBase* t, const Rectangle& rect, const Vector4& border, const Vector4& borderUVs, const Color& color)
{
    RENDER2D_CHECK_RENDERING_STATE;

    Render2DDrawCall drawCall;
    drawCall.Type = DrawCallType::FillTexturePoint;
    drawCall.StartIB = IBIndex;
    drawCall.CountIB = 6 * 9;
    drawCall.AsTexture.Ptr = t ? t->GetTexture() : nullptr;
    DrawCalls.Add(drawCall);
    Write9SlicingRect(rect, color, border, borderUVs);
}

? ? ? ? 可以看到实际的执行过程与之前我们分析的DrawTexture()并无太大区别,那让我们看一下Write9SlicingRect():

void Write9SlicingRect(const Rectangle& rect, const Color& color, const Vector4& border, const Vector4& borderUVs)
{
    const Rectangle upperLeft(rect.Location.X, rect.Location.Y, border.X, border.Z);
    const Rectangle upperRight(rect.Location.X + rect.Size.X - border.Y, rect.Location.Y, border.Y, border.Z);
    const Rectangle bottomLeft(rect.Location.X, rect.Location.Y + rect.Size.Y - border.W, border.X, border.W);
    const Rectangle bottomRight(rect.Location.X + rect.Size.X - border.Y, rect.Location.Y + rect.Size.Y - border.W, border.Y, border.W);

    const Vector2 upperLeftUV(borderUVs.X, borderUVs.Z);
    const Vector2 upperRightUV(1.0f - borderUVs.Y, borderUVs.Z);
    const Vector2 bottomLeftUV(borderUVs.X, 1.0f - borderUVs.W);
    const Vector2 bottomRightUV(1.0f - borderUVs.Y, 1.0f - borderUVs.W);

    WriteRect(upperLeft, color, Vector2::Zero, upperLeftUV);
    WriteRect(upperRight, color, Vector2(upperRightUV.X, 0), Vector2(1, upperLeftUV.Y));
    WriteRect(bottomLeft, color, Vector2(0, bottomLeftUV.Y), Vector2(bottomLeftUV.X, 1));
    WriteRect(bottomRight, color, bottomRightUV, Vector2::One);

    WriteRect(Rectangle(upperLeft.GetUpperRight(), upperRight.GetBottomLeft() - upperLeft.GetUpperRight()), color, Vector2(upperLeftUV.X, 0), upperRightUV);
    WriteRect(Rectangle(upperLeft.GetBottomLeft(), bottomLeft.GetUpperRight() - upperLeft.GetBottomLeft()), color, Vector2(0, upperLeftUV.Y), bottomLeftUV);
    WriteRect(Rectangle(bottomLeft.GetUpperRight(), bottomRight.GetBottomLeft() - bottomLeft.GetUpperRight()), color, bottomLeftUV, Vector2(bottomRightUV.X, 1));
    WriteRect(Rectangle(upperRight.GetBottomLeft(), bottomRight.GetUpperRight() - upperRight.GetBottomLeft()), color, upperRightUV, Vector2(1, bottomRightUV.Y));

    WriteRect(Rectangle(upperLeft.GetBottomRight(), bottomRight.GetUpperLeft() - upperLeft.GetBottomRight()), color, upperRightUV, bottomRightUV);
}

九切片:

????????背景:很多用于背景显示的图片,本身内容很简单,有规律的重复,那么,没有必要做一张很大的图片,可以将图片切割成不同的区域,有的区域保持不变,有的区域进行复制或拉伸,从而实现通过编程的手段,来实现图片的有规律的方法或缩小

????????解释:将图片横向切两刀,纵向切两刀,就分成了9个区域,其中最外边的四个角区域,属于不会被改变,保持原样的区域,其余的5个区域,就可以进行复制或拉伸,从而实现图片变大或缩小

? ? ? ? 很明显能看出使用九切片绘制时一共调用了九次上面我们分析过的WriteRect()方法?


? ? ? ? 还有一个执行自定义渲染(DrawCustom)的方法,同样是最后调用了WriteRect()方法,仅仅是对2D绘制调用的参数设置不同,关于调用的具体执行我们在后面会进行分析,这篇博客就到这里。

? ? ? ? 感谢。

  游戏开发 最新文章
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-12-07 12:21:59  更:2021-12-07 12:22:40 
 
开发: 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 20:20:55-

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