2021SC@SDUSC
一、概述
这篇博客继续分析2D渲染的后续内容。
二、分析
函数DrawBezier()绘制贝塞尔曲线。参数:p1起点、p2第一个控制点、p3第二个控制点、终点、color线条颜色、thickness线条粗细。
static void DrawBezier(const Vector2& p1, const Vector2& p2, const Vector2& p3, const Vector2& p4, const Color& color, float thickness = 1.0f);
以下内容转载自:链接:https://www.jianshu.com/p/4966455cfcaa
贝赛尔曲线是应用于二维图形应用程序的数学曲线。贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋。它通过控制曲线上的四个点(起始点、终止点以及两个相互分离的中间点)来创造、编辑图形。其中起重要作用的是位于曲线中央的控制线。这条线是虚拟的,中间与贝塞尔曲线交叉,两端是控制端点。移动两端的端点时贝塞尔曲线改变曲线的曲率(弯曲的程度);移动中间点(也就是移动虚拟的控制线)时,贝塞尔曲线在起始点和终止点锁定的情况下做均匀移动。
下面是Flax Engine绘制贝赛尔曲线的方法:
- 查找要使用的段数。
- 绘制分段曲线。
void Render2D::DrawBezier(const Vector2& p1, const Vector2& p2, const Vector2& p3, const Vector2& p4, const Color& color, float thickness)
{
RENDER2D_CHECK_RENDERING_STATE;
const Vector2 d1 = p2 - p1;
const Vector2 d2 = p3 - p2;
const Vector2 d3 = p4 - p3;
const float len = d1.Length() + d2.Length() + d3.Length();
const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
const float segmentCountInv = 1.0f / segmentCount;
Vector2 p;
AnimationUtils::Bezier(p1, p2, p3, p4, 0, p);
Lines2.Clear();
Lines2.Add(p);
for (int32 i = 1; i <= segmentCount; i++)
{
const float t = i * segmentCountInv;
AnimationUtils::Bezier(p1, p2, p3, p4, t, p);
Lines2.Add(p);
}
DrawLines(Lines2.Get(), Lines2.Count(), color, color, thickness);
}
2D渲染服务剩余的一些函数如下:
static void DrawMaterial(MaterialBase* material, const Rectangle& rect, const Color& color);
static void DrawBlur(const Rectangle& rect, float blurStrength);
static void DrawTexturedTriangles(GPUTexture* t, const Span<Vector2>& vertices, const Span<Vector2>& uvs);
static void DrawTexturedTriangles(GPUTexture* t, const Span<Vector2>& vertices, const Span<Vector2>& uvs, const Color& color);
static void DrawTexturedTriangles(GPUTexture* t, const Span<Vector2>& vertices, const Span<Vector2>& uvs, const Span<Color>& colors);
static void FillTriangles(const Span<Vector2>& vertices, const Span<Color>& colors, bool useAlpha);
static void FillTriangle(const Vector2& p0, const Vector2& p1, const Vector2& p2, const Color& color);
};
这里我们只介绍函数的具体作用以及参数的含义,而具体的实现则通过其中一到两个举例。(1) DrawMaterial绘制 GUI 材质。
- "material"要渲染的材料。 必须是 GUI 材质类型。
- "rect"要绘制的目标矩形。
- "color"要使用的颜色。
(2)DrawBlur 绘制背景模糊。
- "rect"要绘制的目标矩形(模糊其背景)
- "blurStrength"模糊强度定义了背景的模糊程度。 较大的数字会增加模糊,从而导致 GPU 上的运行时成本更高。
(3)DrawTexturedTriangles绘制顶点数组。
- "t"纹理。
- "vertices"顶点数组。
- "uvs"uvs 数组。(Span<>任意内存连续区域的通用表示。)
- colors"颜色数组
- "useAlpha"如果真正的 alpha 混合将被启用。
(4)FillTriangle填充三角形区域。
- 参数分别是第一二三个顶点以及颜色
以DrawMaterial为例:
void Render2D::DrawMaterial(MaterialBase* material, const Rectangle& rect, const Color& color)
{
RENDER2D_CHECK_RENDERING_STATE;
if (material == nullptr || !material->IsReady() || !material->IsGUI())
return;
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = DrawCallType::Material;
drawCall.StartIB = IBIndex;
drawCall.CountIB = 6;
drawCall.AsMaterial.Mat = material;
WriteRect(rect, color);
}
仍然是在进行一些参数有效性判断后对2D绘图调用进行设置,然后再使用之前我们分析过的诸如WriteRect(),WriteTri()等方法进行具体计算。
再比如FillTriangles()方法:
void Render2D::FillTriangles(const Span<Vector2>& vertices, const Span<Color>& colors, bool useAlpha)
{
CHECK(vertices.Length() == colors.Length());
RENDER2D_CHECK_RENDERING_STATE;
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = useAlpha ? DrawCallType::FillRect : DrawCallType::FillRectNoAlpha;
drawCall.StartIB = IBIndex;
drawCall.CountIB = vertices.Length();
for (int32 i = 0; i < vertices.Length(); i += 3)
WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], colors[i], colors[i + 1], colors[i + 2]);
}
三、总结
到这里,有关Render2D.h和Render2D.cpp大部分内容都已经分析完毕,可以看到在这个部分基本完成了2D渲染的大部分操作,关于2D渲染的其他部分,还有字体以及Sprite图集等,之后的博客会针对这些部分再做分析。
由于游戏引擎太过庞大,Flax Engine更像Unity和UE4(虚幻)的结合,所以其源码量也是较大,有关3D渲染的部分可能在这次分析中不再涉及,但是在分析完2D渲染的剩余内容后可能对3D渲染的源代码进行一个大体的分析。
好了这次分析就到这里,感谢。