В настоящее время работает над движком 3D-носителей с использованием C#, и я столкнулся с небольшой загадкой. У меня есть изощренная петля, выяснилось, у меня отличная плагиновая архитектура и система управления контентом и даже материальный трубопровод, который все запланировано. Затем двигатель планируется использовать DirectX и OpenGL (через плагины «renderer»), а также программируемую трубопроводную линию API.Что такое хорошая структура кода для 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 (элементы) быть классом, или значения элементов должны быть типами значений?
Я рекомендую посмотреть, как XNA это делает. – Foole
У меня есть, что-то похожее на directX ... нет разницы на самом деле. Как только я это выясню для нашего рендеринга DirectX, Xna будет так же просто. Я снова посмотрю на все, что я пропустил, спасибо :). –
Посмотрел на Xna, и он похож на DirectX :(.. поэтому никакой помощи нет. –