2010-02-03 8 views
12

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

+2

Я рекомендую посмотреть, как XNA это делает. – Foole

+0

У меня есть, что-то похожее на directX ... нет разницы на самом деле. Как только я это выясню для нашего рендеринга DirectX, Xna будет так же просто. Я снова посмотрю на все, что я пропустил, спасибо :). –

+0

Посмотрел на Xna, и он похож на DirectX :(.. поэтому никакой помощи нет. –

ответ

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

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

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

+0

Это было слишком долго, я знаю, но ваш ответ правильный, и ваш шаблон можно легко настроить, чтобы он соответствовал моему ... что его необходимо больше xD. В любом случае, спасибо. –

+0

Добро пожаловать =) – jonnii

1

Вы можете посмотреть, как OGRE обрабатывает это. В частности, The render system documentation о VertexElement, а также vertex buffer classes. OGRE - это C++, но я уверен, что вы сможете легко преобразовать шаблоны проектирования в C#.

Смежные вопросы