? С позиции пользователя код в частности должен решать две следующие задачи
English Russian
Live Здравствуйте, дорогие любители RENDER.RU. Вот спустя некоторое время решил написать собственный ...
Главная   Уроки   Библиотека   Документация   Знания

3D инженерия и 3D моделирование, человеческое тело в 3D 3D инженерия и 3D моделирование, человеческое тело в 3D

3D инженерия и 3D моделирование, человеческое тело в 3D 3D инженерия и 3D моделирование, человеческое тело в 3D

3D инженерия и 3D моделирование, человеческое тело в 3D 3D инженерия и 3D моделирование, человеческое тело в 3D

Новости

3D моделирование - воплощение любой фантазии
В настоящее время компьютерная графика проникла во все сферы человеческой деятел...
3D моделирование и визуализация
  Создавая какую-то фигуру или элемент трехмерной графики, перед самим дизайнеро...
Создание нерегулярных сложных объектов
Основной проблемой при создании таких объектов является постоянное видение объе...
Home Вы здесь:: 3D инженерия Уроки С позиции пользователя код в частности должен решать две следующие задачи
 

Модели

3D моделирование - воплощение любой фантазии
В настоящее время компьютерная графика проникла во все сферы человеческой деятельности. Черчение, рисование, моделирование и даже проектирование – все это сфера ...
3D моделирование и визуализация
  Создавая какую-то фигуру или элемент трехмерной графики, перед самим дизайнером стоит не только цель сделать его правдоподобным, но и по максимуму сделать его яр...
Создание нерегулярных сложных объектов
Основной проблемой при создании таких объектов является постоянное видение объекта. Используются и начальные наброски объекта, и его модель. Второе, безусловно, л...
Общие принципы создание 3D-моделей
Все объекты 3D-моделирования делятся по своей форме на простые и сложные. Простым объектом может быть электрическая лампочка, сложным объектом можно считать дерево...
Рельефное структурирование
Рельефное структурирование появилось после нормалмаппинга и представляет собой метод наложения структур, базирующихся на информации о глубине. Изначально метод ...
Нормалмаппинг
Нормалмаппинг - это усовершенствованная техника бампаппинга, ее расширенная версия. При этом методе наложения рельефности нормали изменяются на основе информаци...

Вход для авторов



 
   
С позиции пользователя код в частности должен решать две следующие задачи
09.01.2012 19:15

С позиции пользователя код, в частности, должен решать две следующие задачи:

  • создавать куб заданного размера после нажатия на кнопку Create;
  • обеспечивать ввод в сцену куба посредством мыши.

Сгенерированное помощником решение включает два cpp-файла с исходным кодом – это DllEntry.cpp и cube.cpp. Первый файл содержит код, обслуживающий dll-библиотеку. Это файл в нашем случае практически не требует изменений:

#include "cube.h"
extern ClassDesc2 *GetCubeDesc();
HINSTANCE hInstance;
// Функция DllMain вызывается Windows при загрузке DLL
// Также функция может вызываться во время таких операций,
// как воспроизведение изображения (Rendering)
BOOL WINAPI DllMain(HINSTANCE hinstDLL, ULONG fdwReason, LPVOID) {
if (fdwReason == DLL_PROCESS_ATTACH) {
  hInstance = hinstDLL;
  DisableThreadLibraryCalls(hInstance);
 }
 return TRUE;
}
// Возвращает строку с описанием DLL
__declspec( dllexport ) const TCHAR* LibDescription() {return GetString(IDS_LIBDESCRIPTION);}
// Возвращает число классов плагина
// В нашем случае DLL позволяет оперировать одним классом Cube
__declspec( dllexport ) int LibNumberClasses() {return 1;}
// Возвращает описание i-го класса плагина
__declspec( dllexport ) ClassDesc *LibClassDesc(int i) {
 switch(i) {
  case 0: return GetCubeDesc();
  default: return 0;
 }
}
__declspec( dllexport ) ULONG LibVersion() {return VERSION_3DSMAX;}
// Вызывается один раз при загрузке плагина в 3ds Max
// Если в качестве результата указать FALSE, то система не будет загружать плагин,
// а DLL будет интерпретироваться как свободная библиотека
__declspec( dllexport ) int LibInitialize(void) {return TRUE;}
// Вызывается один раз при выгрузке плагина из 3ds Max
// Возвращаемый результат приложением не используется
__declspec( dllexport ) int LibShutdown(void) {return TRUE;}
//
// Возвращает строку таблицы символов ресурса
TCHAR *GetString(int id) {
 static TCHAR buf[256];
 if (hInstance)
  return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
 return NULL;
}

Главная функция формирует DllMain hInstance – дескриптор экземпляра плагина, передаваемый файлу cube.cpp посредством заголовочного файла cube.h.
Имена declspec-функций файла отвечают имеющимся в def-файле определениям.
Функция GetString получает значение (Value) идентификатора ресурса и возвращает значение поля Caption таблицы символов (String Table) ресурса cube.rc проекта.
Код, обеспечивающий функционал плагина, размещен в файле cube.cpp.
Код перимущественно сформирован помощником и включает набор классов и функций (методов), необходимых для создания и управления процедурными объектами. При необходимости разработчик может добавить свои классы и методы, а также внести отвечающие цели проекта изменения в предоставленный помощником код.
Поскольку удален заголовочный файл 3dsmaxsdk_preinclude.h, то в файле cube.cpp не должны присутствовать #pragma message.
Код содержит определения следующих четырех классов:

  • cube;
  • cubeClassDesc;
  • cubeKBDlgProc;
  • cubeCreateCallBack.

На рис. 20 и 21 показаны иерархии классов, лежащих в основе классов cube и cubeClassDesc.

Рис. 20. Класс cube: иерархия родительских классов

Рис. 21. Класс cubeClassDesc: иерархия родительских классов

Класс cube обеспечивает создание и управление примитивом.
Класс cubeClassDesc обеспечивает регистрацию объекта в 3ds Max.
Класс cubeKBDlgProc отвечает за связь плагина с диалогом ручного создания куба: его функция DlgProc регистрирует нажатие на кнопку Create (IDC_CREATE) диалога и обеспечивает создание куба заданного размера с центром в начале мировой системы координат.
Класс cubeCreateCallBack отвечает за ввод в сцену примитива посредством мыши: его функция proc получает информацию о мышиных событиях – это сообщения 3ds Max с именами MOUSE_POINT, MOUSE_MOVE и MOUSE_ABORT и соответствующим образом реагирует на эти события. Метод SetObj класса ассоциирует созданную меш с кубом.
Обе функции (DlgProc и proc) употребляют метод BuildMesh класса cube, используя соответственно методы NonMouseCreate (класс IObjParam) и InvalidateUI (класс ParamBlockDesc2).
Прочие пояснения см. в комментариях к приводимому ниже коду. При этом прежде следует комментарий, а затем комментируемый код.

#include "cube.h"
#define cube_CLASS_ID Class_ID(0xd667c5aa, 0xb65e9ddb)
#define PBLOCK_REF 0
class cube : public SimpleObject2 {
 public:
  // Ссылка на интерфейс
  static IObjParam *ip;
  // Флаг ручного (по кнопке Create) ввода примитива
  static BOOL kbrdCreate;
  // Из класса BaseObject
  CreateMouseCallBack *GetCreateMouseCallBack();
  // Из класса Object
  BOOL HasUVW();
  void SetGenUVW(BOOL sw);
  int CanConvertToType(Class_ID obtype);
  Object *ConvertToType(TimeValue t, Class_ID obtype);
  void GetCollapseTypes(Tab &clist,Tab &nlist);
  // Из класса GeomObject
  int IntersectRay(TimeValue t, Ray &ray, float &at, Point3 &norm);
  // Возвращает структуру ObjectState
  ObjectState Eval(TimeValue t) {return ObjectState(this);};
  // Из класса Animatable
  void BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev);
  void EndEditParams(IObjParam *ip, ULONG flags, Animatable *next);
  // Из класса SimpleObject
  // Строит меш
  void BuildMesh(TimeValue t);
  // Проверяет корректность задания параметров объекта
  BOOL OKtoDisplay(TimeValue t);
  // Обновляет пользовательский интерфейс
  void InvalidateUI();
  // Загрузка и сохранение данных плагина
  IOResult Load(ILoad *iload);
  IOResult Save(ISave *isave);
  // Из класса Animatable
  Class_ID ClassID() {return cube_CLASS_ID;}
  SClass_ID SuperClassID() {return GEOMOBJECT_CLASS_ID;}
  void GetClassName(TSTR& s) {s = GetString(IDS_CLASS_NAME);}
  void DeleteThis() {delete this;}
  //
  RefTargetHandle Clone(RemapDir &remap);
  //
  // Получает из таблицы символов имя класса
  TCHAR *GetObjectName() {return GetString(IDS_CLASS_NAME);}
  // Число блоков параметров
  int NumParamBlocks() {return 1;}
  // Возвращает блок параметров по его номеру
  IParamBlock2 *GetParamBlock(int i) {return pblock2;}
  // Возвращает блок параметров по его идентификатору
  IParamBlock2 *GetParamBlockByID(BlockID id) {return (pblock2->ID() == id) ? pblock2 : NULL;}
  // Конструктор / Деструктор
  cube();
  ~cube();
};
class cubeClassDesc : public ClassDesc2 {
 public:
  int IsPublic() {return TRUE;}
  void *Create(BOOL) {return new cube();}
  const TCHAR *ClassName() {return GetString(IDS_CLASS_NAME);}
  SClass_ID SuperClassID() {return GEOMOBJECT_CLASS_ID;}
  Class_ID ClassID() {return cube_CLASS_ID;}
  const TCHAR *Category() {return GetString(IDS_CATEGORY);}
  const TCHAR *InternalName() {return _T("cube");}
  HINSTANCE HInstance() {return hInstance;}
};
static cubeClassDesc cubeDesc;
ClassDesc2 *GetCubeDesc() {return &cubeDesc;}
// Имена диалогов IDD_KBRD и IDD_PARAMS
enum {cube_kbrd, cube_params};
// Имена ассоцируемые с упраляющими элементами диалогов
// Элементы IDC_KBSZ, IDC_KBSZSPIN
enum {cube_kb_size};
// Элементы IDC_SZ, IDC_SZSPIN
enum {cube_size};
// Блок параметров диалога IDD_KBRD
static ParamBlockDesc2 cube_kbrd_blk (cube_kbrd, _T("cubeKbrd"), 0, &cubeDesc, P_CLASS_PARAMS + P_AUTO_UI,
 IDD_KBRD, IDS_KBRD, BEGIN_EDIT_CREATE, APPENDROLL_CLOSED, NULL,
 cube_kb_size, _T("kbSize"), TYPE_FLOAT, 0, IDS_CB_SIZE,
  p_default, 40.0, p_range, 0.0f, 100.0f,
  p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE, IDC_KBSZ, IDC_KBSZSPIN, 0.1f,
  end,
 end
);
// Блок параметров диалога IDD_PARAMS
static ParamBlockDesc2 cube_param_blk (cube_params, _T("params"), 0, &cubeDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, PBLOCK_REF,
 IDD_PARAMS, IDS_PARAMS, 0, 0, NULL,
  cube_size, _T("size"), TYPE_FLOAT, P_ANIMATABLE, IDS_CB_SIZE,
  p_default, 0.0f, p_range, 0.0f, 100.0f,
  p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE, IDC_SZ, IDC_SZSPIN, 0.1f,
  end,
 end
);
// Инициализация свойств ip и kbrdCreate класса cube
IObjParam *cube::ip = NULL;
BOOL cube::kbrdCreate = FALSE;
// Создаем диалог с P_AUTO_CONSTRUCT-блоком параметров
// Диалог IDD_KBRD будет создан при обращении cubeDesc.BeginEditParams
cube::cube() {cubeDesc.MakeAutoParamBlocks(this);}
cube::~cube() { }
IOResult cube::Load(ILoad *iload) {return IO_OK;}
IOResult cube::Save(ISave *isave) {return IO_OK;}
class cubeKBDlgProc : public ParamMap2UserDlgProc {
 public:
  cube *ob;
  cubeKBDlgProc(cube *cb) {ob = cb;}
  INT_PTR DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
  void DeleteThis() {delete this;}
};
// Обеспечивает создание куба после нажатия на кнопку Create диалога IDD_KBRD
INT_PTR cubeKBDlgProc::DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 if (msg != WM_COMMAND) return FALSE;
 if (LOWORD(wParam) != IDC_CREATE) return FALSE;
 float cbSize = cube_kbrd_blk.GetFloat(cube_kb_size);
 if (cbSize == 0.0) return TRUE;
 // Устанавливаем IDC_SZ = IDC_KBSZ
 if (ob->TestAFlag(A_OBJ_CREATING)) ob->pblock2->SetValue(cube_size, 0, cbSize);
 // Флаг ручного ввода
 ob->kbrdCreate = TRUE;
 // Формируем единичную матрицу
 Matrix3 tm(1);
 // Устанавливаем в матрице порцию Translate (перемещение) аффинных преобразований
 tm.SetTrans(Point3(0, 0, 0));
 ob->suspendSnap = FALSE;
 // Формируем куб
 ob->ip->NonMouseCreate(tm);
 return TRUE;
}
// Вызывается при создании очередного экземпляра куба (из класса Animatable)
void cube::BeginEditParams(IObjParam *ip,ULONG flags, Animatable *prev) {
 SimpleObject::BeginEditParams(ip, flags, prev);
 this->ip = ip;
 if (kbrdCreate) {
  // Если ранее был выполнен ручной ввод, то устанавливаем IDC_SZ = IDC_KBSZ
  pblock2->SetValue(cube_size, 0, cube_kbrd_blk.GetFloat(cube_kb_size));
  kbrdCreate = FALSE;
 }
 cubeDesc.BeginEditParams(ip, this, flags, prev);
 // Фиксируем пользовательскую процедуру,
 // ассоциированную с блоком параметров cube_kbrd_blk
 cube_kbrd_blk.SetUserDlgProc(new cubeKBDlgProc(this));
}
void cube::EndEditParams(IObjParam *ip, ULONG flags, Animatable *next) {
 SimpleObject::EndEditParams(ip, flags, next);
 cubeDesc.EndEditParams(ip, this, flags, next);
 // Плагин должен вызывать методы интерфейса ip только
 // между BeginEditParams и EndEditParams
 this->ip = NULL;
}
// Из класса Object
// Вернуть флаг наличия у объекта UVW-координат
BOOL cube::HasUVW() {return TRUE;}
// Можно модифицировать, исходя из целей проекта
void cube::SetGenUVW(BOOL sw) {if (sw == HasUVW()) return;}
// Класс обработки мышиных событий
class cubeCreateCallBack : public CreateMouseCallBack {
 cube *ob;  // Указатель на объект
 Point3 p0;  // Первая точка в мировой системе координат
 Point3 p1;  // Вторая точка в мировой системе координат
 public:
  int proc(ViewExp *vpt, int msg, int point, int flags, IPoint2 m, Matrix3 &mat);
  void SetObj(cube *cb) {ob = cb;}
};
int cubeCreateCallBack::proc(ViewExp *vpt, int msg, int point, int flags, IPoint2 m, Matrix3 &mat){
 if (msg == MOUSE_POINT || msg == MOUSE_MOVE) {
  switch(point) {
   case 0:
    ob->suspendSnap = TRUE;
    // m - позиция мыши в оконных координатах
    // p0 - позиция мыши в мировых координатах
    p0 = vpt->SnapPoint(m, m, NULL, SNAP_IN_PLANE);
    // Порция Translate (перемещение) аффинных преобразований позиции
    mat.SetTrans(p0);
    // Изменяем значение параметра cube_size диалога IDD_PARAMS
    ob->pblock2->SetValue(cube_size, ob->ip->GetTime(), 0.0f);
    break;
   case 1: {
    ob->suspendSnap = TRUE;
    // p1 - новая позиция мыши в мировых координатах
    p1 = vpt->SnapPoint(m, m, NULL, SNAP_IN_PLANE);
    // Управляем размером куба в зависимости от положения мыши
    ob->pblock2->SetValue(cube_size, ob->ip->GetTime(), 0.5f * Length(p1 - p0));
    // Создаем и отображаем меш в видовом порте
    cube_param_blk.InvalidateUI();
    break;
   }
   case 2:
    return CREATE_STOP;
  }
 }
 else
  if (msg == MOUSE_ABORT) return CREATE_ABORT;
 return TRUE;
}
static cubeCreateCallBack cubeCreateCB;
CreateMouseCallBack *cube::GetCreateMouseCallBack() {
 cubeCreateCB.SetObj(this);
 return &cubeCreateCB;
}
// Получает размер куба, строит его меш и формирует группы сглаживания
void cube::BuildMesh(TimeValue t) {
 float size, h;
 ivalid = FOREVER;
 pblock2->GetValue(cube_size, t, size, ivalid);
 h = 0.5 * size;
 // Число вершин и граней в меш
 mesh.setNumVerts(8);
 mesh.setNumFaces(12);
 // Координаты вершин
 mesh.setVert(0, Point3(-h, -h, -h));
 mesh.setVert(1, Point3(h, -h, -h));
 mesh.setVert(2, Point3(-h, h, -h));
 mesh.setVert(3, Point3(h, h, -h));
 mesh.setVert(4, Point3(-h, -h, h));
 mesh.setVert(5, Point3(h, -h, h));
 mesh.setVert(6, Point3(-h, h, h));
 mesh.setVert(7, Point3(h, h, h));
 // Состав граней
 mesh.faces[0].setVerts(0, 2, 3);
 mesh.faces[1].setVerts(3, 1, 0);
 mesh.faces[2].setVerts(4, 5, 7);
 mesh.faces[3].setVerts(7, 6, 4);
 mesh.faces[4].setVerts(0, 1, 5);
 mesh.faces[5].setVerts(5, 4, 0);
 mesh.faces[6].setVerts(1, 3, 7);
 mesh.faces[7].setVerts(7, 5, 1);
 mesh.faces[8].setVerts(3, 2, 6);
 mesh.faces[9].setVerts(6, 7, 3);
 mesh.faces[10].setVerts(2, 0, 4);
 mesh.faces[11].setVerts(4, 6, 2);
 // Группы сглаживания
 mesh.faces[0].setSmGroup(2);
 mesh.faces[1].setSmGroup(2);
 mesh.faces[2].setSmGroup(4);
 mesh.faces[3].setSmGroup(4);
 mesh.faces[4].setSmGroup(8);
 mesh.faces[5].setSmGroup(8);
 mesh.faces[6].setSmGroup(16);
 mesh.faces[7].setSmGroup(16);
 mesh.faces[8].setSmGroup(32);
 mesh.faces[9].setSmGroup(32);
 mesh.faces[10].setSmGroup(64);
 mesh.faces[11].setSmGroup(64);
 // Устанавливаем видимость внешних ребер граней (диагональные ребра не видны)
 for (int k = 0; k < 12; k++) {
  mesh.faces[k].setEdgeVisFlags(1, 1, 0);
  mesh.faces[k].setMatID(1);
 }
 // Назначаем UVW-координаты
 Matrix3 tm(1);
 tm.Scale(Point3(h, h, h));
 tm = Inverse(tm);
 mesh.ApplyUVWMap(MAP_BOX, 1.0f, 1.0f, 1.0f, 0, 0, 0, 0, tm);
 mesh.InvalidateTopologyCache();
}
// Добавлен код проверки корректности параметра size
BOOL cube::OKtoDisplay(TimeValue t) {
 float size;
 pblock2->GetValue(cube_size, t, size, FOREVER);
 return (size }
void cube::InvalidateUI() {cube_param_blk.InvalidateUI(pblock2->LastNotifyParamID());}
// Находит точку пересечения луча ray с поверхностью (см. класс Ray)
// и нормаль к поверхности в этой точке
int cube::IntersectRay(TimeValue t, Ray &ray, float &at, Point3 &norm) {
 return SimpleObject::IntersectRay(t, ray, at, norm);
}
// Методы, обеспечивающие преобразование и копирование объекта
Object* cube::ConvertToType(TimeValue t, Class_ID obtype) {
 return SimpleObject::ConvertToType(t, obtype);
}
int cube::CanConvertToType(Class_ID obtype) {
 if (obtype == defObjectClassID || obtype == triObjectClassID)
  return 1;
 else
  return SimpleObject::CanConvertToType(obtype);
}
void cube::GetCollapseTypes(Tab &clist, Tab &nlist) {
 Object::GetCollapseTypes(clist, nlist);
}
RefTargetHandle cube::Clone(RemapDir &remap) {
 cube *newob = new cube();
 newob->ReplaceReference(0, remap.CloneRef(pblock2));
 newob->ivalid.SetEmpty();
 BaseClone(this, newob, remap);
 return newob;
}

Приведенный код можно скопировать в созданный помощником проект Visual Studio. При этом следует копировать коды обоих файлов – и DllEntry.cpp, и cube.cpp.
После настроек свойств проекта и создания диалогов построенная на основе этого кода dll-библиотека должна обеспечивать описанный в уроке функционал.
Построение DLL осуществляется после нажатия на F7 (меню Build - Build Solution).

 
   
 
Ulti Clocks content

Новые поступления

Циклевка полов
Одним из самых лучших видов напольного покрытия можно назвать паркет. Состоящий из экологически чистой древесины, у него есть и масса других достоинств: практичн...
Значение 3D моделирования в нашей жизни
В наш век высоких технологий наука не стоит на месте. Большой популярностью сейчас пользуется 3D моделирование различных объектов. ...
Привет всем посетителям рендера! Я уже рассказывал о себе в прошлом making of
Привет всем посетителям рендера! Я уже рассказывал о себе в прошлом making of. С того времени коренных изменений в моей жизни не было, кроме 3D-Award на CGSociety за эту работу :-)....

Методы

3D моделирование в деятельности человека
Компьютеры, планшетные и настольные, равно как и компьютерные технологии прочно обосновались в нашей повседневной жизни. Очень часто их присутствия не замечают, однако компьютерные технологии широко применяются во в...
3D моделирование как способ визуализации в среде проектирования
В наше время компьютерная графика используется в качестве одной из методик проектирования в самых разных отраслях промышленности и предоставления услуг. В этом плане данный метод является очень удобным для визуализа...
История развития 3D моделирования и компьютерной графики
Компьютерная графика бывает двух типов — интерактивная и неинтерактивная графика. В последнем случае мы просто видим графический объект, например по телевизору или в компьютере, но не можем его изменить и манипулиров...
Введение в компьютерную графику и 3D моделирование
Сегодня существует очень мало аспектов нашей жизни, которые не зависели бы от компьютеров. Практически каждый день мы имеем дело с компьютерами — дома, на работе, когда снимаем деньги в банкомате, во время поездки в мет...
3D моделирование и программы для создания компьютерной графики
Для того чтобы создавать компьютерную графику, используется много разных программ. CAD: позволяет архитекторам и инженерам составлять проекты конструкций. Это акроним для автоматизированного проектирования. CAD предст...
 

Стоит попробовать

3D моделирование - воплощение любой фантазии
В настоящее время компьютерная графика проникла во все сферы человеческой деятельности. Черчение, рисование, моделирование и даже проектирование – все это сфера применения компьютерной графики. Голливудские фильмы ...

Документация

3DS Max: краткий обзор
У большинства современных дизайнеров слово «3D» ассоциируется с известной программой 3D Max, которая предназначена преимущественно для создания графических сцен и разработку качественной анимации. Не является удивите...
Top
Яндекс.Метрика
Travel Turne Tranzito
заказ контекстной рекламы