首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么是与api无关的顶点处理的好代码结构?

什么是与api无关的顶点处理的好代码结构?
EN

Stack Overflow用户
提问于 2010-02-03 11:30:50
回答 2查看 1.3K关注 0票数 12

目前,我和C#正在开发一个3D媒体引擎,我遇到了一个小难题。我已经弄清楚了我的渲染循环,我有一个很棒的插件架构和内容管理系统,甚至还有一个材料管道都计划好了。然后引擎计划使用DirectX和OpenGL (通过“渲染器”插件),以及这两个API的可编程管道。

无论如何,在本周初,我开始了处理顶点的引擎抽象层的工作(我已经担心这个问题好几周了)。正如你们中的一些人所知道的,图形API之间的顶点处理是完全不相关或相同的。有点关系;),但不是一样的。在OpenGL中处理顶点非常简单,您可以创建自定义顶点结构,将其发送到图形处理器,然后让着色器处理其余部分。这对于灵活的图形管线是完美的,OpenGL不需要知道每个顶点包含什么元素。另一方面,DirectX要求我们为每个顶点结构创建声明,然后将它们发送到图形处理器。

问题是,我不知道传递的是哪种类型的顶点结构,我肯定希望避免创建抽象层,该抽象层涉及通过枚举和一些抽象的'VertexDeclaration‘类声明顶点的每个元素;这将导致一些问题:

1)至少可以说,获取顶点元素是一件痛苦的事情。我可以使用一些'VertexSemantic‘来询问顶点'a - z’的位置,但是当处理很多像骨骼动画这样的顶点时,它可能会有很多开销。

2)考虑到引擎的主要关注点是“新手”,用户不是很友好。我希望用户能够创建自定义顶点和网格缓冲区,而不必声明大量对象,从而消耗宝贵的开发时间。

3)更多?

现在,我可以对属性做一些操作,然后在DirectX渲染器中为顶点结构创建声明。例如,继续创建一些枚举:

代码语言:javascript
复制
// 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
}

现在我可以创建一个属性,用户可以将其应用于顶点结构中每个元素的‘field’:

代码语言:javascript
复制
    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
    }

自定义顶点结构的示例如下:

代码语言:javascript
复制
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插件(渲染器)中,我只需创建一个实用程序类,它可以为每种结构类型创建语义,然后缓存数据,这样就不必为每个顶点重新创建声明。

我甚至可以向ELementUsage添加一个NONE枚举值,这样自定义值就可以用于任何意义上……但话又说回来,它们只能在OpenGL中工作,因为DirectX要求您标记每个顶点……除非我漏掉了什么。

我的问题:

有没有更好的方法(除了使用attirbutes)?有没有办法避免在DirectX中使用VertexDeclarations?关于“我的”问题,有没有什么你可能不明白的?

编辑:

使用属性的一个问题是从每个顶点获取元素数据。假设我想要得到网格缓冲区中每个顶点的位置。因为我使用了属性,所以我不能只做'vertex.Position',我必须创建一个实用方法,它可以从顶点结构中提取字段引用,比如'Utility.GetElement( vertex,ElementUsage.POSITION)‘。此方法需要首先使用反射来查找属性,然后返回对字段值的引用。设置这个值甚至(我认为)是不可能的?

另一种方法是创建一个IElement接口并实现每个元素(Positon、Normal等)。接口可以有Name属性,我可以直接在继承的元素结构中返回,就像PositionElements的Name属性只返回"Positon“一样。

接下来,我可以将IElement数组放在顶点结构中,该结构包含AddElement(IElement)、GetElement(字符串名)、GetElement(整数索引)、Insert、Replace等方法。我将实现DirectX已知的所有元素,以便渲染器插件可以解析顶点结构来创建顶点声明数组。

这样做的问题是我不确定数组'[]‘是否可以用作顶点元素数据。比如,一个数组还包含哪些字节(如果有的话)会阻止我直接将顶点结构(包含IElement数组)传递给DirectX,然后再传递给GPU?

以这种方式实现它将是我需要它的绝对完美的方式。另一个问题是,IElement的继承类型(元素)是否可以是类,或者元素值是否必须是值类型?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-03-04 01:20:09

我已经很长时间没有做过任何directx或opengl了,所以对我的建议持保留态度,但我记得不久前我做过这样的事情。

我想我做了这样的事情:

代码语言:javascript
复制
var graphicsStream = new GraphicsStream();

var elements = graphicsStream.Create<Vector3>(Usage.Position);
graphicsStream.Create<Color>(Usage.Color);
graphicsStream.Create<Quaternion>(Usage.Fribble);

elements.SetData(new[] { new Vector3(), new Vector3() });

var vertexFormat = graphicsStream.GetFormat();
graphicsStream.Validate();  // ensure all the streams have the same length

// get a particular element by type
var p = graphicsStream.GetData(Usage.Position, 1);

你会有一个图形流,它是一组应用了用法的类型化数据集。由此,您可以生成适当的顶点格式。API将允许您更改单个元素或一次性上载和替换整个顶点缓冲区。

最大的缺点是在顶点结构中没有一个表示“列”的结构。

我不知道这是不是你要找的东西。为什么这样的设计是不合适的?

票数 1
EN

Stack Overflow用户

发布于 2011-03-22 18:52:57

你可以看看OGRE是如何处理这个问题的。特别是关于VertexElement和vertex buffer classesThe render system documentation。C#是C++,但我相信您可以轻松地将设计模式转换为OGRE。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2189494

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档