[ AmberSkyNet VR ]- В этом большом ящике - питание, а в меньшем - мир! В точности такусенький, как я обещал милостивому королю, - анизотропный, с особыми точками, в которых можно переключать бег времени, а доступ к этим точкам равный и всеобщий. Измыслили мы, государь, и несколько персон, которые в будущем помогут нам в опробовании следующих вселенных... Думаю, пора начинать творить цифровые миры. Сейчас-то у нас всё в прикладной программе обрабатывается - создание сцены, заполнение её элементами, движение и отрисовка - всё "вручную". Оно, конечно, не так уж и плохо - можно написать свою игру руками, используя из движка только события и функции отрисовки, но можно и упростить процесс для тех, кто не очень хочет разбираться с загрузкой материалов и моделей из файлов, а также с программированием динамического заполнения сцены этими моделями. IWorld и его реализация CWorldSimpleНапишем для начала интерфейсный класс мира с функциями заполнения элементами и отрисовки. А потом - плагин простейшего мира SimpleWorld, который будет просто отрисовывать всё, что в него напихали, без фильтрации по пирамиде видимости, оптимизации по BSP, Octree, итп. Для начала... class IWorld: public BaseObject { public: IWorld(IEngine *_Engine):BaseObject(_Engine){}; virtual ~IWorld(){} virtual bool Draw()=0; virtual bool Update(float tms)=0; virtual INode *getNode( UINT id )=0; //получить ноду с номером id virtual bool delNode( UINT id )=0; //уничтожаем ноду с номером id в мире virtual UINT addNode( INode* node )=0;//добавляем в мир внешнюю ноду, на выходе получаем её id в мире virtual UINT createNode( const std::string& InitString )=0;// создаём элемент сцены virtual INode *findNode( const std::string& InitString )=0; //найти ноду с именем Name; не у всех нод есть имена }; Функция сreateNode позволяет создать узел сцены по входной информации. Можно, например, написать класс некоей RPG-игры, в котором имеется заранее заданый набор NPC-персонажей. При помощи функции CreateNode( "Goblin,10,5" ) мы установим в ячейку с координатами 10,5 NPC типа Goblin. Функция addNode позволяет добавить в мир узел сцены, созданный извне. Мы сохраняем возможность заполнения мира "руками", из внешней программы. Функция delNode удаляет из мира узел с номером id и все его дочерние узлы. Функции getNode и findNode позволяют нам получить указатель на узел по его номеру и имени. Не все ноды могут иметь имя ( оно устанавливается в ноде вызовом функции node->SetParam("Name", node_name); ) Реализация класса CWorldSimple сохраняет ноды в двух списках - std::vector для всех нод
и std::map для нод, имеющих имя. INodeКак видно выше, в нашем классе мира используется интерфейсный класс INode - класс узла сцены. Привёдем заголовочный файл, показывающий этот интерфейс: class INode: public BaseObject { public: INode(IEngine *_Engine):BaseObject(_Engine){load_all=false;}; virtual ~INode(){} virtual bool Draw()=0;//узел отрисовывает себя в сцене virtual bool Update(float tms)=0;//узел изменяется по времени на tms virtual bool LoadResource()=0; //узел пытается загрузить необходимые для себя ресурсы.. false - если все ресурсы для ноды удалось загрузить virtual UINT getID(){return id;} // возвращение уникального для мира ID ноды virtual UINT addNode(INode* node)=0;// добавить дочерний узел virtual UINT delNode(UINT num)=0;// отсоединить дочерний узел, но из мира он не удалится! virtual INode *getParentNode(){return ParentNode};//получить родительский узел virtual NodeList_typ& getNodeList()=0;//получить список дочерних нод // функции установки и чтения значений вместо самих параметров в public-секции // т.к. внутри реализации класса INode они могут хранится совсем не в виде CVector // (а например в виде матрицы преобразований) virtual void setSize(const CVector& Size)=0;//размеры элемента virtual void setCenterPoint(const CVector& CenterPoint)=0;//точка центра (повороты, отрисовка, итп) virtual void setPos(const CVector& Pos)=0;//Позиция virtual void setRot(const CVector& Rot)=0;//Угол поворота //аналогично, для чтения virtual CVector& getSize()=0; virtual CVector& getCenterPoint()=0; virtual CVector& getPos()=0; virtual CVector& getRot()=0; protected: INode *ParentNode;//ссылка на родительскую INode bool load_all;// все ли ресурсы для данного объекта загружены }; Класс составлялся с учётом того, чтобы с одной стороны обеспечить достаточно удобную автономную работу из прикладной программы, а с другой стороны - такую же удобную работу под управлением менеджера мира. Класс CNode реализует основную функциональность по добавлению, удалению и отрисовке дочерних узлов сцены, по установке координат и углов узла итп. Сам по себе он ничего не отрисовывает на экране, но может служить хранилищем группы узлов сцены. От него же будет удобно наследовать реализацию других классов узлов сцены, например, сейчас от него наследуется класс CNode3ds, функционал которого сосредоточен только на отрисовке 3ds-моделей. Немного о менеджере ресурсовВ предыдущей реинкарнации AmberSkyNetVR менеджера ресурсов как такового не было, поэтому приходилось идти на некоторые ухищрения чтобы нужные объекты по два раза не создавались или загружались. В этой версии будет всё немного по-другому - если узлу сцены понадобится какой-то ресурс, то он сначала поищет его в кэше ресурсов, и если не обнаружит такого, то создаст его. В менеджере ресурсов у меня хранятся собственно, не ресурсы, загруженные с диска, а некие объекты. Таким образом, например, класс CNode3ds может запомнить в кэше экземпляр класса модели Model3ds с загруженной в него моделью. Интерфейс менеджера ресурсов выглядит примерно так: class IResourceSystem{ public: IResourceSystem(){} ~IResourceSystem(){} // устанавливаем новый ресурс virtual bool SetResource(const std::string& Type, const std::string& Name, BYTE* Resource, UINT Res_size )=0; // берём ресурс virtual BYTE *GetResource(const std::string& Type, const std::string& Name)=0; // избавляемся от ресурса virtual bool ReleaseResource(const std::string& Type, const std::string& Name)=0; // устанавливаем новый объект virtual bool SetObject(const std::string& Type, const std::string& Name, IasnObject *resObject)=0; // берём ресурс virtual IasnObject *GetObject(const std::string& Type, const std::string& Name)=0; // избавляемся от ресурса virtual bool ReleaseObject(const std::string& Type, const std::string& Name)=0; }; Указатель на менеджер ресурсов хранится в глобальных указателях движка и может быть
получен вот так: CNode3ds и CModel3dsКласс CNode3ds реализует отрисовку моделей формата 3ds. Он создаёт в системе ресурсов экземпляр файла CModel3ds, который используя библиотеку l3ds ( copyright (c) 2001-2002 Lev Povalahev ) конвертит 3ds-модель в набор мешей и материалов и сохраняет их у себя. Зачем нужен класс CModel3ds и почему бы не хранить меши и материалы в самом классе?
Ну, например, у нас на сцене десять объектов имеют одну и ту же 3ds-модель.
Нам достаточно один раз создать класс CModel3ds с набором мешей и материалов этой модели
и загрузить его в кэш, а девять раз получить указатель на него из кэша. Имя модели, котору надо загрузить класс CNode3ds хранит в своей локальной переменной под именем "MeshName". Класс отслеживает её динамическое изменение, чтобы отрисовывать именно ту модель, имя которой хранится в этой переменной. Встречаются 3ds модели, в которой материалов нет. В этом случае можно задать материал принудительно, установив локальной переменной с именем "MeshMaterial" имя материала. AmberSkyNetVR.dllОчень удобно компилировать движок отдельными плагинам, когда отлаживаешь какой-нибудь участок кода - тратится меньше времени, чем перекомпилировать полностью все классы. Но вот когда пишешь прикладную программу, которая этот самый движок использует - тут лучше чтобы всё находилось в одной dll - как-то некрасиво выглядит кучка этих самых asnEngine.dll, asnNode3ds.dll, итп. в дистрибутиве. Поэтому принял решение сделать возможность компиляции всего движка в одну dll. На функциональность это никак не повлияло, а одна dll занимает меньше места и выглядит более солидно =) Возможность компиляции плагинов как отдельных dll так же осталась... Изменения в исходникахМмм.. Сложно так все упомнить.. include/: добавлен интерфейс IResourceSystem.h src/asnMain/: небольшая демка с моделями 3ds, позаимствованными из проекта S.C.O.U.R.G.E... src/asnAll/: добавлена папка с интерфейсом, позволяющим загружать все известные объекты движка из одного плагина (AmberSkyNetVR.dll) а не с набора разных dll. Для удобства использования. src/asnCommon/: добавлен класс CNode - основа для прочих узлов сцены. src/asnEngine/: добавлен менеджер ресурсов. src/asnWorld/: новый плагин - плагин реализации простейшего менеджера мира CSimpleWorld. src/asnNode3ds/: новый плагин - первый плагин узла сцены, рисующий 3ds модели. Исходники этого шага выложены в SVN. Скачать их можно набрав команду: svn co https://svn.sourceforge.net/svnroot/ambernet/tags/AmberSkyNet-0.8 ambernet_0.8 |