图元和顶点构建指南

本指南简要介绍如何使用自定义顶点格式顶点缓冲区构建和使用图元(primitives,原语,基元)。

一般来说,当你开始使用3D,特效,复杂的绘图过程或着色器时,你不需要太担心使用的顶点格式,因为GameMaker会自动设置并传递顶点数据。但是,有时需要创建自己的顶点数据并将其格式化,特别是当你需要提高速度时,或者希望传递额外的信息。例如,标准顶点格式包括x,y,z 3D位置,颜色(带alpha)和UV纹理坐标,如果您自己创建它,看起来像这样:

直通顶点格式:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_texcoord();
my_format = vertex_format_end();

然而,如果你只是使用(例如)着色器来操纵顶点的位置,那么就不需要传递颜色或纹理数据。在这种情况下,你可以创建自己的格式,如下所示:

自定义顶点格式:

vertex_format_begin();
vertex_format_add_position_3d();
my_format = vertex_format_end();

在定义顶点格式时,总共可以使用五种不同的顶点属性:

通常情况下,您必须 始终 提供位置或3D位置作为格式的一部分,但其他所有都是可选的。

您应该注意,创建顶点格式后,在构建图元必须遵守定义顶点属性的顺序。 因此,如果您已将顶点格式定义为位置、颜色和纹理坐标,则必须以相同的顺序将这些属性添加到图元,否则您将收到错误。 另请注意,与任何其他动态资源一样,顶点格式需要内存,因此在不需要时应使用函数 vertex_format_delete 删除。

您构建的任何基元都保存在顶点缓冲区中。 必须事先创建它,然后由用于构建原语的函数引用。 顶点缓冲区可以根据需要多次重复使用以创建不同的图元,或者可以“冻结”它以在游戏或关卡持续时间内维护特定的图元类型(这是最快的方法,因此如果您知道 您构建的原语不会改变,那么您应该始终使用此选项)。

下面的代码显示了构建单个三角形图元的示例:

Create Event

v_buff = vertex_create_buffer();
vertex_begin(v_buff, global.my_format);
vertex_position(v_buff, 10, 10);
vertex_colour(v_buff, c_white, 1);
vertex_texcoord(v_buff, 0, 0);
vertex_position(v_buff, 110, 10);
vertex_colour(v_buff, c_white, 1);
vertex_texcoord(v_buff, 1, 0);
vertex_position(v_buff, 110, 110);
vertex_colour(v_buff, c_white, 1);
vertex_texcoord(v_buff, 1, 1);
vertex_end(v_buff);

Draw Event


var tex = sprite_get_texture(spr_Background, 0);
shader_set(shd_shimmer);
vertex_submit(v_buff, pr_trianglelist, tex);
shader_reset();

在这里,我们首先在实例的创建事件中创建了顶点缓冲区,然后开始定义组成三角形图元的不同顶点,为要使用的三个点中的每一个点提供位置、颜色和纹理UV坐标。然后结束顶点定义,并且我们知道具有该顶点数据的顶点缓冲存储在变量"v_buff"中。

注意如果顶点缓冲区的内容将不断更新,它将被创建,给定顶点数据,然后再次被销毁-在它被绘制之后-所有这些都在同一步骤中。

然后我们使用着色器在绘制事件中绘制顶点缓冲区的内容。这是一个非常简单的示例,基本上是GameMaker内部的工作方式,即:绘制精灵时,GameMaker会创建一个顶点缓冲区,其中四个顶点可创建两个三角形(这使得一个正方形,也被称为"四边形"),并纹理这两个三角形与精灵图像。当我们绘制这个精灵,我们提交的顶点缓冲区,其中绘制其内容到屏幕上。

你会注意到,当我们提交顶点缓冲区进行绘图时,我们提供了一个图元类型。你使用的图元类型可以是点、线条列表或条带,或者三角形列表或条带,但你不是因为大多数移动的硬件不接受这种基本类型,所以允许三角形风扇。不要忘记为将要用于绘制它的基本类型正确格式化顶点缓冲区。例如,将两个三角形的图元绘制为三角形列表需要6个点,而将其绘制为三角形条带只需要4个点。使用哪种类型取决于您,取决于您想要绘制的内容和想要达到的效果。

以这种方式使用您自己的顶点缓冲区时要注意的最后一点是它如何影响发送到 GPU 的顶点批次。 创建顶点缓冲区时,您创建的是最低级别的图形数据,因此当您绘制时,GameMaker 会将您的缓冲区直接发送到显卡。 因此,如果你想要更好的批处理,你必须自己解决并将你想要批处理的东西存储在同一个缓冲区中。

正如我们上面已经提到的,顶点格式是通过一起使用以下5种属性类型(通过适当的vertex_format_add_*函数添加)构建的:

在 GLSL ES 着色器中,使用以下4个属性可以识别这些类型:

现在,这可能看起来很奇怪,因为我们似乎可以在顶点格式中指定比在顶点着色器中更多的属性种类。 但是,在着色器中,Position3D Position 被视为相同的属性,除了 Position 预计只有“x”和“y”坐标,而 3D 位置具有“x”、“y”和“z”坐标。 那么如何将顶点格式中的内容映射到着色器中定义属性的方式呢? 让我们从默认着色器的一组典型属性开始:

 

attribute vec3 in_Position;        // (x,y,z)
//attribute vec3 in_Normal;        // (x,y,z) unused in this shader.
attribute vec4 in_Colour;          // (r,g,b,a)
attribute vec2 in_TextureCoord;    // (u,v)

下面是一段代码,它建立了与这个着色器兼容的顶点格式:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_texcoord();
my_format = vertex_format_end();

现在,shader 属性是如何与顶点格式类型匹配的? 它只是基于变数命名原则:

现在,当您拥有多个同类属性时,事情会变得更加棘手,但事情仍然基于相同的命名约定。 我们现在将考虑提供额外的颜色纹理坐标,因为在着色器或顶点格式中只能有一个位置和一个法线属性,但有  可以 是多个颜色或纹理属性。

向着色器添加其他颜色属性时,需要在着色器属性的末尾添加一个数字,以指示该属性映射到顶点格式中的哪个特定条目。 这是一个示例 - 首先是顶点格式:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_colour();
vertex_format_add_texcoord();
my_format = vertex_format_end();

现在是相关的着色器属性:

attribute vec3 in_Position;      // (x,y,z)
attribute vec4 in_Colour0;       // (r,g,b,a)
attribute vec4 in_Colour1;       // (r,g,b,a)
attribute vec2 in_TextureCoord;  // (u,v)

在这种情况下,in_Colour0 映射到第一个 vertex_format_add_colour()in_Colour1 映射到第二个。

纹理坐标的处理与颜色略有不同。基本上,任何不被称为in_Positionin_Normalin_Colour[0...]属性之一的东西都被视为纹理坐标。它们在着色器中的属性列表中定义的顺序,表示它们映射到顶点格式中的哪个属性。请参见以下GML代码示例:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_texcoord();
vertex_format_add_texcoord();
vertex_format_add_texcoord();
my_format = vertex_format_end();

着色器代码应该是这样的:

attribute vec3 in_Position;      // (x,y,z)
attribute vec4 in_Colour;        // (r,g,b,a)
attribute vec2 in_myTexcoord;    // (u,v)
attribute vec2 in_TextureCoord;  // (u,v)
attribute vec2 in_Something;     // (u,v)

在此示例中,in_myTexcoordin_TextureCoordin_Something 映射到顶点格式中定义的三个连续纹理坐标属性。

您可以从以下页面找到创建顶点格式、顶点缓冲区和图元所需的所有函数的完整列表: