草庐IT

c# - api-independent 顶点处理的好的代码结构是什么?

coder 2024-05-28 原文

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

3年前关闭。




Improve this question




目前正在使用 C# 开发 3D 媒体引擎,我遇到了一个小难题。我已经弄清楚了我的渲染循环,我得到了一个很棒的插件架构和内容管理系统,甚至一个 Material 管道都已经计划好了。然后引擎计划使用 DirectX 和 OpenGL(通过“渲染器”插件),以及两个 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 插件(渲染器)中,我可以只创建一个实用程序类,它可以为每个结构类型创建语义,然后缓存数据,这样就不必为每个顶点重新创建声明。

我什至可以向 ELEmentUsage 添加一个 NONE 枚举值,以便自定义值可以用于任何含义……但它们只能在 OpenGL 中工作,因为 DirectX 要求您标记每个顶点……除非有我想要的东西丢失的。

我的问题:

有没有更好的方法来解决这个问题(除了使用属性之外)?
有没有办法避免在 DirectX 中使用 VertexDeclarations?
关于“我的”问题,您有什么不明白的地方吗?

编辑:

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

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

接下来,我可以将 IElement 数组保存在一个包含 AddElement(IElement)、GetElement(string name)、GetElement(int index)、Insert、Replace 等方法的 Vertex 结构中。我将实现 DirectX 已知的所有元素,以便渲染器插件可以解析一个顶点结构来创建一个顶点声明数组。

问题是我不确定数组 '[]' 是否可以用作顶点元素数据。比如,数组包含哪些其他字节(如果有)会阻碍我将 Vertex 结构(包含 IElement 数组)直接传递给 DirectX,然后传递给 GPU?

以这种方式实现它对于我需要的东西来说绝对是完美的。另一个问题是 IElement(元素)的继承类型可以是一个类,还是元素值必须是值类型?

最佳答案

我已经很长时间没有做过任何 directx 或 opengl,所以请采纳我的建议,但我记得不久前做了这样的事情。

我想我做了这样的事情:

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 可让您一次性更改单个元素或上传和替换整个顶点缓冲区。

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

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

关于c# - api-independent 顶点处理的好的代码结构是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2189494/

有关c# - api-independent 顶点处理的好的代码结构是什么?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  7. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  8. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  9. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  10. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

随机推荐