Подтвердить что ты не робот

Что такое хорошая структура кода для api-независимой обработки вершин?

В настоящее время работает над движком 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) я мог бы просто создать класс утилиты, который может создавать семантику для каждого типа структуры, а затем кэшировать данные, чтобы декларации не нужно воссоздавать для каждой вершины.

Я мог бы даже добавить значение NONE для перечисления в ELementUsage, чтобы пользовательские значения могли использоваться для того, что когда-либо имеет значение... но опять же они будут работать только в OpenGL, потому что DirectX требует, чтобы вы отмечали каждую вершину... если только нет что-то мне не хватает.

Мой вопрос (ы):

Есть ли лучший способ сделать это (помимо использования attirbutes)? Есть ли способ избежать использования VertexDeclarations в DirectX? Есть ли что-то, что вы не можете понять о "моем" вопросе?

EDIT:

Проблема с использованием атрибутов будет получать данные элемента из каждой вершины. Скажем, я хотел получить позиции каждой вершины в меш-буфере. Поскольку я пошел с атрибутами, я не могу просто сделать "vertex.Position", мне пришлось бы создать метод утилиты, который мог бы извлечь ссылку на поле из структуры вершин, например "Utility.GetElement(vertex, ElementUsage.POSITION)", Этот метод должен будет использовать отражение, чтобы сначала найти атрибут, а затем вернуть ссылку на значение поля. Установка значения не могла бы (я думаю) быть возможной?

Другой способ - создать интерфейс IElement и реализовать каждый элемент (Positon, Normal и т.д.). Интерфейс может иметь свойство Name, которое я могу возвращать непосредственно внутри структуры унаследованных элементов, например свойство PropertyElements Name просто вернет "Positon".

Затем я мог бы удерживать массив IElement внутри структуры Vertex, который содержит такие методы, как AddElement (IElement), GetElement (имя строки), GetElement (int index), Insert, Replace и т.д. Я бы использовал все элементы, известные DirectX так что плагин визуализации может анализировать структуру вершин, чтобы создать массив объявлений вершин.

Проблема в том, что я не уверен, что массив '[]' может использоваться как данные элемента вершин. Например, какие другие байты содержат массив (если есть), что помешало бы мне передать структуру Vertex (содержащий массив IElement) непосредственно в DirectX, а затем на GPU?

Реализация его таким образом была бы абсолютно идеальна для того, для чего мне это нужно. Другой вопрос заключается в том, может ли наследовательные типы IElement (элементы) быть классом или значения элементов должны быть типами значений?

4b9b3361

Ответ 1

Прошло много времени с тех пор, как я сделал какой-либо 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 позволит вам изменять отдельные элементы или загружать и заменять весь буфер вершин за один раз.

Самый большой недостаток заключается в том, что у вас нет одной структуры, которая представляет "столбец" в структуре вершин.

Я не знаю, действительно ли это то, что вы ищете. Почему такой дизайн не подходит?