Добрый день.
Пишу двиг на опенгл (исходники прилагаются), лоадить модели получается, правда из объектного файла. Следующий шаг это текстурирование, в объектном файле есть координаты текстур (я их пока не использую), но подскажите как связать файл текстуры и набор вертексов? Буду признателен за пример. Или может посоветуете иным путем работать с моделями?
ЗЫ. сорсы - http://ice.sumy.ua/IEN.rar
Итак, смотрим:
class Engine {
public:
static void InitVariables(void);
static void GProcessSpecialKeys(int key, int x, int y);
static void Display(void);
static void InitEngine(int argc, char** argv);
static void AddObjectToScene(Model);
};Вместо использования набора статических функций, лучше используйте паттерн Singleton. То что есть сейчас - это во первых моветон в ООП-программировании, во вторых вы теряете одно из важных преимуществ - использование полиморфизма. Что если клиентское приложение захочет переопределить некоторые методы, породив свой класс от Engine?
class Engine {
public:
virtual ~Engine();
void InitVariables(void);
void GProcessSpecialKeys(int key, int x, int y);
void Display(void);
void InitEngine(int argc, char** argv);
void AddObjectToScene(Model);
static Engine& getInstance();
private:
Engine();
Engine(const Engine& src);
Engine& operator=(const Engine& src);
static Engine* s_pInstance;
};
Engine* Engine::s_pInstance = NULL;
Engine& Engine::getInstance()
{
if(NULL == s_pInstance)
{
s_pInstance = new Engine();
}
return *s_pInstance;
}Замечание номер дуа:
void Engine::Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef (Position.x, Position.y, Position.z);
glRotatef(Angle, Rotation.x, Rotation.y, Rotation.z);
for (unsigned int i=0;i < Scene.size ();i++)
{
for(int j=0;j<Scene[i].faceCount;j++)
{
glBegin (GL_TRIANGLES);
glNormal3f(Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[0]-1].x,
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[0]-1].y,
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[0]-1].z);
glVertex3f(Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[0]-1].x/Scene[i].scale,
Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[0]-1].y/Scene[i].scale,
Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[0]-1].z/Scene[i].scale);
glNormal3f(Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[1]-1].x,
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[1]-1].y,
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[1]-1].z);
glVertex3f(Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[1]-1].x/Scene[i].scale,
Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[1]-1].y/Scene[i].scale,
Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[1]-1].z/Scene[i].scale);
glNormal3f(Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[2]-1].x,
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[2]-1].y,
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[2]-1].z);
glVertex3f(Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[2]-1].x/Scene[i].scale,
Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[2]-1].y/Scene[i].scale,
Scene[i].ModelVertexs[Scene[i].ModelFaces[j].VertexCoord[2]-1].z/Scene[i].scale);
glEnd();
}
}
glutSwapBuffers();
}Этот метод выполняет слишком много работы, и часть её он должен делегировать другим классам. Например вы могли бы создать класс Model (вместо той примитивной структуры).
void Engine::Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef (Position.x, Position.y, Position.z);
glRotatef(Angle, Rotation.x, Rotation.y, Rotation.z);
//typedef vector<Model> ModelList;
for(ModelList::iterator it = Scene.begin(); it != Scene.end(); it++)
{
*it->drawModel();
}
glutSwapBuffers();
}Алсо, Scene - глобальная переменная?!! Сделайте её членом класса.
В общем хотя программного кода написано всего ничего, а грубых косяков хоть ложкой хлебай. Приведенные примеры - самые вопиющие косяки. Почитайте на досуге "Рефакторинг" Мартина Фаулера.
Не хочется говорить столько категорично, но имхо никакой паттерн тут не поможет, потому что все имплиментированные ф-ии относятся не к движку, а к клиентской аппликации, если не предметно, то как минимум символьно.
P.S. скачал архив (и просмотрел), не прочитав текста после слов "исходники прилагаются"... Что бы это могло значить =)
icepro
- пользуйся итераторами вместо std::vector::size()
- вынеси glBegin. glEnd за циклы.
- предпочитай glVertex3fv/glNormal3f вместо glVertex3f/glNormal3f ну, а далее как разберешься с OpenGL глубже, используй расширение GL_ARB_vertex_buffer_obhject.
>в объектном файле есть координаты текстур (я их пока не использую), но подскажите как связать файл текстуры и набор вертексов?
что-то я в тех файлах их не заметил.
а вообще для этого есть функции glTexCoord2fv/glTexCoord2f.
Сразу убивает, что фильтры в проекте на русском. Используйте английские слова, если хотите делать движок с открытыми кодами.
Второй вопрос, пришедший в голову: А в чём, собственно говоря, движок?
Третий вопрос: в чём разница данных структур, кроме названия?
struct Coordinate { float x,y,z; }; struct Vertex { float x,y,z; }; struct Normal { float x,y,z; };
Это по сути даже одна сущность, поскольку:
1. Точка в пространстве задаётся скорее не координатами, а радиус-вектором относительно начала координат
2. Вершина - это та же самая точка, которая также задаётся радиус-вектором
3. Нормаль - это в чистом виде вектор.
Т.е. вместо трёх структур используем одну.
Четвёртый вопрос - нужны операции над векторами:
1. Сложение и вычитание векторов
2. Скалярное произведение
3. Векторное произведение
4. Масштабирование
Последнее особенно необходимо, чтобы в коде не было таких монстров:
<вектор>.x/Scene[i].scale
Убивают монструозные выражения:
Scene[i].ModelNormals[Scene[i].ModelFaces[j].NormalCoord[0]-1]
Треугольник:
struct Triangle { int VertexCoord[3]; int NormalCoord[3]; };
А если индексы в массиве изменятся? Тогда надо будет бегать по треугольникам и менять индексы.
Вывод - рефакторинг необходим как воздух. А лучше всё написать заново.
Morgen_Dunkel
>А в чём, собственно говоря, движок?
+1.
Как говорил один мой знакомый, "телегу паровозом не называют". Изделие из двух классов и четырех структур вряд ли кому-то серьезно облегчит работу над игровым проектом. Проще свое написать.
icepro
Ты главное на них не обижайся :)
а то набежали советчики :)
сами бы лучше показали чтонить
Написала в прошлом году:
UML диаграмма самописной подсистемы GUI-интерфейса этого проекта, полученная путем reverse enginering:
icepro
К изучению:
http://www.gamedev.ru/code/terms/VertexBuffer
http://www.gamedev.ru/code/terms/IndexBuffer
К прочтению:
http://www.gamedev.ru/code/articles/?id=4142
Aglaranir
Я разве говорил где-то, что нельзя давать советы?
Я просто сказал чтоб человек не обижался.
Он же просто выложил свои наработки
P.S.: И ещё есть такое дело что всё можно делать и без ООП
cNoNim
>И ещё есть такое дело что всё можно делать и без ООП
Ну тут какбэ речь идет о самописном движке под OpenGL. И код "движка" выдержан с претензиями на ООП.
Просто я считаю, раз уж взялся использовать ООП, так надо делать это так, чтобы это приносило пользу - снижало сложность методов, повышало возможность повторного использования модулей.
Тема в архиве.