3D Engineering

...Лучшее из общего.

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Экономичная и экологическая оценка танкера двойного действия


Нажмите что бы увеличить

OKHOTSK SEA & SEA ICE, MOMBETSU, JAPAN, 24-28.2.2002

Подробнее...
 

3D МОДЕЛИРОВАНИЕ ЧЕЛОВЕЧЕСКОГО ТЕЛА И АНИМАЦИЯ

 

Глава 3: Анатомия человека

Леонардо да Винчи сказал, "Высшая неудача - это когда теория опережает выполнение." Хотя эта книга стремится быть практическим руководством, есть некоторые предположения о человеческой анатомии, которые должны быть обсуждены в более аналитической манере. Хотя в этой главе и рассматривается анатомия, она не претендует быть полным исследованием по этой теме. Целые книги написаны об этом предмете. Они должны служить более подходящими руководствами для серьезного студента отделения гуманитарных наук, желающего глубокого изучать анатомию.

Подробнее...
 

Peter Ratner 3-D HUMAN MODELING AND ANIMATION 2nd Edition 3D МОДЕЛИРОВАНИЕ ЧЕЛОВЕЧЕСКОГО ТЕЛА И АНИМАЦИЯ

 

Глава 1: Основы техники моделирования

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

Подробнее...
 

3D МОДЕЛИРОВАНИЕ ЧЕЛОВЕЧЕСКОГО ТЕЛА И АНИМАЦИЯ

 

Глава 2: Техника моделирования среднего уровня

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

Подробнее...
 

PДДSTESEADMETE- JA VAHENDITEGA SEOTUD LEPPEMДRGID


mida kasutatakse kooskхlas Rahvusvahelise konventsiooni

inimelude ohutusest merel (SOLAS 1974/1978) reegliga III/9.2.3

Подробнее...
 


Страница 1 из 31

Архив статей

 Янв   Февраль 2012   Мар

ВПВСЧПС
   1  2  3  4
  5  6  7  8  91011
12131415161718
19202122232425
26272829 
Julianna Walker Willis Technology

Случайная новость

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

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

далее