2010-11-26 6 views
1

У меня есть дерево объектов, которые представляют собой 3D-модель (граф сцены). Узлы дерева имеют разные типы (реализованы как производные классы из общего базового класса). Например, есть узел, представляющий многоугольник, или узел, который применяет преобразование координат (поворот, перевод) к своим дочерним узлам. Также необходимо, чтобы сторонние поставщики должны были иметь возможность внедрять новые типы узлов и добавлять их плагином (я использую Qt как инфраструктуру графического интерфейса). Поэтому возможно, что в дереве могут быть узлы, из которых тип неизвестен при компиляции.реализация шаблона MVC на графике сцены C++

Теперь я хочу реализовать класс, который выступает в качестве представления для этого графика сцены. Для каждого типа узла дерева вид должен принимать соответствующие действия (рисовать многоугольник, преобразовывать и т. Д.). Моя идея - реализовать классы представления для каждого типа узлов и позволить классу класса верхнего уровня делегировать эти классы в зависимости от типа узла. (Сторонние поставщики смогут реализовать собственные классы делегатов представления)

Итак, мой вопрос: как я могу определить тип узла в исполнении и расширяемый?

Мои идеи до сих пор:

  1. Я мог бы добавить идентификатор типа для каждого класса узла. Это может быть просто целым числом (строки не подходят для повышения производительности). Проблема заключается в управлении идентификаторами типов для сторонних поставщиков. Как я могу убедиться, что один и тот же идентификатор не используется для разных типов узлов (например, разными поставщиками)?

  2. Я мог бы реализовать код чертежа или хотя бы вызов соответствующего объекта делегирования чертежа непосредственно в узле. Но мои объекты-узлы предпочтительно не должны знать что-то о своих объектах представления. Также невозможно дать каждому узлу объект выделенный объект представления (речь идет о десятках тысяч узлов).

Итак, каковы ваши идеи? Возможно, это совершенно другой способ справиться с этим? Помните: решение не должно требовать поиска хеш-таблиц или других алгоритмов с интенсивным вычислением, потому что мне нужно рисовать график в реальном времени.

Спасибо заранее, McNumber граф

ответ

2

Сцена обычно живет в View слое системы MVC. В конце концов, сцена вид подразумевает часть, которую вы видите. Как правило, после установки правильного контекста OpenGL (или любого другого чертежа api, используемого вами в качестве эквивалента), вы вызываете некоторый метод «render» в корневом узле графа сцены, а затем рекурсивно отображает всех своих потомков.

Графы сцены не часто представляют собой другие виды состояний. Например, в игре с физическим симулятором вы бы сохранили график сцены для выполнения рендеринга, но список физических объектов поддерживается отдельно физическим движком, и он следует за очень отдельной структурой. Физические двигатели работают лучше всего, если объекты, находящиеся вблизи друг от друга, также пересекаются локально. Рендеринг лучше всего работает, если объекты с аналогичными характеристиками рендеринга (сделанные из одних и тех же текстур) пройдены локально.

Таким образом, узел на графе сцены будет знать, как искать позицию экземпляра модели, которую он представляет, испускать это средство визуализации и затем испускать примитивы рисования для этого типа объекта.


с этим из пути, на самом деле реализации такой вещи, вероятно, означает думать о видах взаимодействия на глобальном уровне, корневой узел графа сцены должен реагировать. В типичном случае это, вероятно, означает рендеринг.

class SceneNode 
{ 
    public: 
    virtual void render() = 0; 
}; 

Самое очевидное, что нужно сделать узел с дочерними элементами, так что у нас есть дерево узлов.

class ListSceneNode : public SceneNode 
{ 
    private: 
    typedef std::vector<std::shared_ptr<SceneNode> > ChildList; 
    ChildList children; 

    public: 
    void render() { 
     for(ChildList::iterator i = children.begin() ; i != children.end(); ++i) 
     i->render(); 
    } 
}; 
+0

Спасибо за ответ! В какой-то игре это было бы вполне приемлемо. Но мне нужно разработать приложение 3D-CAD. Дерево используется для хранения всей информации о объектах в настоящее время отредактированной модели. Кроме того, одно и то же дерево используется для моделирования, тестов и т. Д. Наличие разных деревьев для этих задач было бы бессмысленным, потому что они были бы в основном одинаковыми. Я явно хочу отделить модель (возможно, лучшее слово, чем график сцены) и алгоритм рисования. – McNumber 2010-11-26 09:03:15

0

насчет разбив операцию просмотра в виде набора простых операций (перемещение в положение (х, у), нарисовать линию длиной N и так далее) в рамках рендер класса. Затем каждый модельный узел может иметь свою собственную операцию рендеринга, в которой он вызывает операции над объектом рендеринга, который имеет эти простые операции в своем интерфейсе.

Реализация класса рендеринга может реализовывать эти простые операции с точки зрения Qt-вызовов. Класс верхнего уровня View просто вызывает метод рендеринга на узлах (он также может передать соответствующий объект рендеринга в качестве аргумента, если вы не хотите, чтобы он был постоянным атрибутом класса node).

0

Неактивная нить на некоторое время, но мне интересно, достигли ли вы прогресса с тех пор и/или все еще работают в одном и том же поле.

У меня такая же проблема. Я разделяю существующую кодовую базу на все сгруппированные: Model (SceneGraph), GUI (win32) и рендеринг (OpenGL) в красивую структуру Model/View (без отдельного контроллера). Разделение Model/View для графического интерфейса работает, и теперь я работаю над рендерингом OpenGL. В качестве первого «простого» спроса на себя я начал ограничивать систему в том смысле, что включение слоя OpenGL в слой модели не допускается. Это сразу заставляет вас иметь отдельный OpenGL «RenderGraph» на стороне представления в дополнение к SceneGraph на стороне модели. Все возможные узлы в SceneGraph получают собственное представление представления (например, вы указываете). Я вроде как, потому что типичные данные рендеринга OpenGL (например, массивы вершин) остаются на стороне обзора. Можно было бы, например, представить рендер рендеринга, который не имеет смысла для этих данных, поэтому хорошо не включать его в модель (только такие вещи, как «радиус» или «позиция»).

Иерархия SceneGraph и Rendergraph в настоящее время является симулятивной, хотя я мог представить, что у вас будет другая структура, основанная на изменениях состояния (как упоминает TokenMacGuy). Когда SceneGraph изменяется (как запускается графическим интерфейсом и распространяется по модели), вы должны обрабатывать это уведомление об изменении локально в RenderGraph. Это включает в себя такие действия, как добавление/удаление/перемещение объектов. Это немного громоздко, но это управляемо.

Моя основная проблема на данный момент заключается в том, что связь между SceneGraph (Model) и «ViewGraph» (View/GUI) немного отличается от отношения между SceneGraph и RenderGraph (View/OpenGL). Хотя в первом случае вы можете иметь «горизонтальные» соединения между узлами модели и узлами просмотра, во втором случае изменение промежуточного узла часто заставляет повторную визуализацию всего RenderGraph от корневого узла вверх. Я не нашел элегантный способ включить это в мои рамки.

В качестве примера, скажем, у вас есть модель автомобиля на вашем SceneGraph. Где-то в листе у вас есть «диаметр клапана передней левой шины». Это будет представлено в текстовом контроле в ViewGraph, и когда пользователь изменит его, отредактируется соответствующий лист в SceneGraph. Нет проблем, это локальное изменение. Модель получает это изменение и отправляет уведомление RenderGraph для обновления рендеринга OpenGL. Узел в RenderGraph, получающий это уведомление, теперь не только должен повторно отображать себя, но и весь RenderGraph в целом должен быть перерисован.

С наилучшими пожеланиями, Daniel Dekkers

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