目前正在使用c开发一个3d媒体引擎,我遇到了一个小难题。我有我的渲染循环,我有一个伟大的插件架构和内容管理系统,甚至一个材料管道都计划好了。然后,引擎计划使用directx和opengl(通过“renderer”插件),以及两个api的可编程管道。
无论如何,在本周初,我开始研究处理顶点的引擎抽象层(我已经害怕了好几个星期了)。正如你们中的一些人所知道的,图形api之间的顶点处理根本不相关,也不相同。有点关系;),但不一样。在opengl中处理顶点是非常直接的,您可以创建自定义顶点结构,将其发送到gpu,然后让着色器处理其余的顶点。这对于一个灵活的图形管线来说是完美的,opengl不需要知道每个顶点包含什么元素。另一方面,directx要求我们为每个顶点结构创建声明,然后将它们发送到gpu。
问题是,我不知道传递的是哪种类型的顶点结构,我绝对希望避免创建抽象层,该抽象层涉及通过枚举和一些抽象的“vertexdeclaration”类声明顶点的每个元素;这将导致一些问题:
1)获取顶点元素至少是一件痛苦的事。我可以使用一些“vertexsemantic”并请求顶点“a-z”的位置,但是在处理大量顶点以进行骨骼动画之类的操作时,可能会有很多开销。
2)考虑到发动机的主要关注点是“新手”,因此用户不太友好。我希望用户能够创建自定义顶点和网格缓冲区,而不必声明大量的对象,这将耗费宝贵的开发时间。
3)更多?
现在我可以对属性做一些事情,然后在directx渲染器中为顶点结构创建声明。例如,继续创建一些枚举:
// for getting the format layout of the element
public enum ElementFormat
{
Float, Float2, Float3, Byte, etc, etc
}
// for determining the 'usage'
// (here is 'another' where DirectX limits vertex structures ><)
public enum ElementUsage
{
Position, Normal, Color, TextureCoord, etc, etc
}
现在我可以创建一个属性,用户可以将其应用于顶点结构中每个元素的“字段”:
public class VertexElementAttribute : Attribute
{
#region Properties
/// <summary>
/// Gets the total size (in bytes) of the element.
/// </summary>
public int Size
{
get;
set;
}
/// <summary>
/// Gets the number of values contained with-in the element.
/// </summary>
public int Count
{
get;
set;
}
/// <summary>
/// Gets the type semantic of the element.
/// </summary>
public ElementType Type
{
get;
set;
}
/// <summary>
/// Gets the usage semantic of the element.
/// </summary>
public ElementUsage Usage
{
get;
set;
}
#endregion
#region Init
/// <summary>
/// Creates a new vertex element attribute.
/// </summary>
/// <param name="count">The number of values contained within the element.</param>
/// <param name="size">The total size (in bytes) of the element.</param>
/// <param name="type">The type semantic of the element.</param>
/// <param name="usage">The usage semantic of the element.</param>
public VertexElementAttribute(int count, int size, ElementType type, ElementUsage usage)
{
Count = count;
Size = size;
Type = type;
Usage = usage;
}
#endregion
}
自定义顶点结构的外观示例:
public struct VertexPositionColor
{
[VertexElement(3, sizeof(Vector3), ElementType.FLOAT3, ElementUsage.POSITION)]
public Vector3 Xyz;
[VertexElement(4, sizeof(Color), ElementType.FLOAT4, ElementUsage.COLOR)]
public Color Rgba;
... etc
}
这太好了。在directx插件(renderer)中,我可以创建一个实用程序类,它可以为每个结构类型创建语义,然后缓存数据,这样就不必为每个顶点重新创建声明。
我甚至可以向elementUsage添加一个none枚举值,以便自定义值可以用于任何意义上的…但是它们只在opengl中工作,因为directx要求您标记每个顶点…除非我少了什么。
我的问题:
有没有更好的方法来解决这个问题(除了使用阁楼外)?
有没有办法避免在DirectX中使用VertexDeclarations?
关于“我的”问题,你有什么不明白的吗?
编辑:
使用属性的一个问题是从每个顶点获取元素数据。假设我想得到网格缓冲区中每个顶点的位置。由于我使用了属性,我不能只做“vertex.position”,我必须创建一个实用程序方法,可以从顶点结构中提取字段引用,比如“utility.getelement(vertex,elementusage.position)”。此方法需要使用反射首先查找属性,然后返回对字段值的引用。设定这个值是不可能的吗?
另一种方法是创建一个IElement接口并实现每个元素(position、normal等)。接口可以有name属性,我可以直接在继承的元素结构中返回,就像positionelements的name属性只返回“position”。
接下来,我可以将IElement数组保存在一个顶点结构中,该结构包含addelement(IElement)、getelement(string name)、getelement(int index)、insert、replace等方法。顶点声明数组。
这个问题是,我不确定数组'[]'是否可以用作顶点元素数据。例如,一个数组还包含哪些字节(如果有的话),这些字节会阻碍我将顶点结构(包含IElement数组)直接传递给DirectX,然后再传递给GPU?
以这种方式实现它绝对是我所需要的完美。另一个问题是,IElement的继承类型(元素)是类,还是元素值必须是值类型?