Список работ

Разработка базы данных для представления анимированной модели 3d–объекта

Курсовая работа

Иванова А. М., A-13-03, alibi_@mail.ru

Содержание

Введение

Курсовая работа является частью проекта по разработке графического редактора анимированной 3d-сцены.
Цель курсовой работы – разработать базу данных (БД) для представления информации об анимированном объекте.

Постановка задачи

Решаются следующие задачи:

Описание предметной области

Предметная область – это анимированная полигональная модель 3d-объекта. Анимация представляется в виде последовательности кадров.
Один кадр отображает состояние модели объекта в некоторый момент времени.
Каждому полигону может быть назначена текстура.
Полигон задается координатами своих вершин.
Для каждой вершины необходимо хранить следующие данные:

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

Наличие в модели групп позволяет выполнять и прочие групповые операции, например аффинные преобразования полигонов группы. В настоящей реализации такие операции не рассматриваются.
Распределение полигонов по группам выполняется в следующем порядке: отображестся имеющаяся в БД модель объекта; выбираются подходящие полигоны, из которых формируется группа. Заметим, что при выборе полигона, входящего в группу, выбираются все полигоны группы. Описанный механизм реализован с использованием графической библиотеки OpenGL.

Получаем следующее (без учета групп полигонов) представление анимированной модели в одной ненормализованной таблице:

№ кадра№ полигона№ вершины{x, y, z}{xn, yn, zn}{u, v}Текстура
111    
112    
113    
123    
127    
122    
121    
211    
212    

Использование данной ненормализованной таблицы неприемлемо из-за наличия избыточности и вредных эксплуатационных издержек. Например, при изменении координат вершины 1 придется изменять значения нескольких полей таблицы (аномалия редактирования).

Проектирование базы данных

Выделим и опишем с указанием типа данных следующие сущности:
КАДР – хранит координаты вершины и координаты нормали этой вершины.

№ кадра, integer№ вершины, integerx, floaty, floatz, floatxn, floatyn, floatzn, float

ГРУППА – включает некоторое подмножество полигонов модели. В текущей разработке группе (всем ее полигонам) можно единовременно назначить текстуру.

№ группы, integerИмя текстуры, varchar(20)

ТЕКСТУРА – хранит путь и имя файла текстуры; путь задается относительно расположения БД.

Имя текстуры, varchar(20)Путь к текстуре, varchar(100)

ВЕРШИНА – хранит флаг активности вершины (активность вершин будет использована в программе для выделения объекта).

№ вершины, integerФлаг активности, char(1)

ПОЛИГОН – хранит для каждого полигона номер группы, которой полигон принадлежит. Содержит также флаг активности полигона.

№ группы, integer№ полигона, integerФлаг активности, char(1)

ПОЛИГОН и ВЕРШИНЫ – указывает, какие вершины образуют полигон, и UV-координаты вершины в текущем полигоне.

№ полигона, integer№ вершины, integeru, floatv, float

Реализация базы данных

Выбор инструментов проектирования

Графический редактор разрабатывается в среде Borland C++ Builder 6 с использованием OpenGL.
В качестве СУБД употребляется Interbase 7.1.

Создание базы данных

База данных, ее таблицы и индексы автоматически создаются в Interbase в результате употребления следующего кода.

create table texture
(
  name varchar(20) not null, art varchar(100) not null,
  primary key(name)
);
create table grope
(
  cod integer not null, texture varchar(20) not null,
  primary key(cod),
  foreign key(texture) references texture(name) on update cascade
);
create table point
(
  nom integer not null, act char(1) default 'f', primary key(nom)
);
create table poligon
(
  nom integer not null, nom_grope integer not null, act char(1) default 'f',
  primary key(nom),
  foreign key(nom_grope) references grope(cod) on update cascade
);
create table kadr
(
  nom integer not null, nom_point integer not null,
  x float not null, y float not null, z float not null,  
  xn float not null, yn float not null, zn float not null,
  primary key(nom, nom_point),
  foreign key(nom_point) references point(nom) on delete cascade
);
create table poligon_point
(
  nom integer not null,
  nom_point integer not null,
  u float not null,
  v float not null,
  primary key(nom, nom_point)
);

При работе с БД будут полезны следующие индексы:

CREATE INDEX "I_POLIGON_POINT_NOM" ON "POLIGON_POINT"("NOM");
CREATE INDEX "I_POLIGON_NOM_GROPE" ON "POLIGON"("NOM_GROPE");
CREATE INDEX "I_POLIGON_NOM" ON "POLIGON"("NOM");
CREATE INDEX "I_KADR_NOM_POINT" ON "KADR"("NOM_POINT");
CREATE INDEX "I_KADR_NOM" ON "KADR"("NOM");

Хранимые процедуры и триггеры

За создание хранимых процедур и триггеров отвечает следующий код.

Процедура select_point обеспечивает выбор (выделение) вершин полигонов в кадре n, охваченных прямоугольником, заданным точками {x1, y1, z1} и {x2, y2, z2}.

SET TERM !! ;
CREATE PROCEDURE select_point(n int, x1 float, y1 float, z1 float, x2 float, y2 float, z2 float)
AS
  declare variable xx float;
  declare variable yy float;
  declare variable zz float;
  declare variable ind int;
BEGIN
  ind = 0;
  FOR SELECT x, y, z FROM kadr WHERE nom = :n INTO :xx,yy,zz
  DO BEGIN
   ind = ind + 1;
   IF (x1 < xx AND xx < x2 AND y1 < yy AND yy < y2 AND z1 < zz AND zz < z2)
   THEN UPDATE point SET act = 't' WHERE point.nom = :ind;
  END
END !!
SET TERM ; !!

Процедура выделения полигонов по выбранным вершинам. Полигон выделяется, если выбрана хотя бы одна его вершина.

SET TERM !! ;
CREATE PROCEDURE select_poligon
AS
BEGIN
  UPDATE poligon SET act = 't'
  WHERE nom IN
   (SELECT poligon_point.nom FROM poligon_point, point
    WHERE poligon_point.nom_point = point.nom AND point.act = 't');
END !!
SET TERM ; !!

Процедура, обеспечивающая создание группы из выделенных полигонов; str – название текстуры.

SET TERM !! ;
CREATE PROCEDURE create_grope(str varchar(20))
AS
  declare variable i integer;
BEGIN
  SELECT count(*) FROM grope INTO:i;
  i = i + 1;
  INSERT INTO grope VALUES(:i, :str);
  UPDATE poligon SET nom_grope = :i WHERE act = 't';
END !!
SET TERM ; !!

Удаление группы контролируется двумя триггерами. Первый срабатывает до удаления группы. Если удаляется группа с номером, большим 1, то полигоны автоматически записываются в группу 1. Группа 1 всегда имеется в модели объекта.

SET TERM !! ;
CREATE TRIGGER delete_grope FOR grope
BEFORE DELETE
AS
BEGIN
  IF (old.cod <> 1)
  THEN BEGIN
   UPDATE poligon SET act = 'f';
   UPDATE poligon SET act = 't' WHERE nom_grope = old.cod;
   UPDATE poligon SET nom_grope = 1 WHERE act = 't';
   UPDATE poligon SET act = 'f'
  END
END !!
SET TERM ; !!

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

SET TERM !! ;
CREATE TRIGGER delete_grope_not_1 FOR grope
AFTER DELETE
AS
declare variable ind int;
BEGIN
  IF (old.cod = 1)
  THEN INSERT INTO grope VALUES(1, 'zero');
  ELSE BEGIN
   FOR SELECT cod FROM grope WHERE cod > old.cod INTO :ind
    DO
     UPDATE grope SET cod = :ind - 1 WHERE cod = :ind;
   END
END !!
SET TERM ; !!

Очистка текстуры контролируется двумя триггерами. Первый запускается до очистки; он обеспечивает замену существующей текстуры на текстуру ZERO.

SET TERM !! ;
CREATE TRIGGER delete_texture FOR texture
BEFORE DELETE
AS
BEGIN
  IF (old.name <> 'zero') THEN UPDATE grope SET texture = 'zero' where texture = old.name;
END !!
SET TERM ; !!

Второй триггер запускается после очистки текстуры. Если удалена текстура ZERO, то она будет триггером восстановлена.

SET TERM !! ;
CREATE TRIGGER delete_texture_not_zero FOR texture
AFTER DELETE
AS
BEGIN
  IF (old.name = 'zero') THEN INSERT INTO texture VALUES('zero', 'textura\zero.bmp');
END !!
SET TERM ; !!

Экспорт данных из Maya и их вставка в базу данных

Плагин mexport

Для наполнения БД используются созданные в Maya полигональные модели 3d-объектов. В качестве тестовой выбрана модель кисти руки (рис. 1).

Отображение модели кисти руки

Рис. 1. Кисть руки

В БД загружаются данные о Maya-модели, предварительно выгруженные в текстовый файл следующего формата:

<количество вершин в объекте>
x y z u v xn yn zn      
...
<количество полигонов>
<количество вершин в полигоне> <номера вершин, принадлежащих полигону>
...

Так, при выгрузке созданного в Maya куба формируется файл со следующими данными:

8
-0.500000 -0.500000 0.500000 0.000000 4.000000 -0.577350 -0.577350 0.577350
0.500000 -0.500000 0.500000 1.000000 0.000000 0.577350 -0.577350 0.577350
-0.500000 0.500000 0.500000 0.000000 1.000000 -0.577350 0.577350 0.577350
0.500000 0.500000 0.500000 1.000000 1.000000 0.577350 0.577350 0.577350
-0.500000 0.500000 -0.500000 -1.000000 1.000000 -0.577350 0.577350 -0.577350
0.500000 0.500000 -0.500000 1.000000 2.000000 0.577350 0.577350 -0.577350
-0.500000 -0.500000 -0.500000 -1.000000 0.000000 -0.577350 -0.577350 -0.577350
0.500000 -0.500000 -0.500000 1.000000 3.000000 0.577350 -0.577350 -0.577350
6
4 0 1 3 2
4 2 3 5 4
4 4 5 7 6
4 6 7 1 0
4 1 7 5 3
4 6 0 2 4

Экспорт данных из Maya обеспечивает нижеприведенный плагин:

code:
#pragma comment(lib, "foundation.lib")
#pragma comment(lib, "openmaya.lib")
#include <math.h>
#include <maya/MPxCommand.h>
#include <maya/MGlobal.h>
#include <maya/MFnPlugin.h>
#include <maya/MObject.h>
#include <maya/MStatus.h>
#include <maya/MArgList.h>
#include <maya/MDagPath.h>
#include <maya/MSelectionList.h>
#include <maya/MItMeshVertex.h>
#include <maya/MItMeshPolygon.h>
class point
{
  public:
   point(){x = 0; y = 0; z = 0; u = 0; z = 0; xn = 0; yn = 0; zn = 0;}
   float x, y, z;
   float u, v;
   float xn, yn, zn;
   bool test(point t)
   {
    return (t.x == x) && (t.y == y) && (t.z == z);
   }
};
class AModelExport : public MPxCommand
{
  public:
   virtual MStatus doIt(const MArgList& arg);
   static void *creator();
};
MStatus AModelExport::doIt(const MArgList& arg)
{
  int i, j;
  FILE* file = NULL;
  float fuv[2]={0.0f, 0.0f};
  MDagPath node;  // Узел объекта в иерархии
  MObject obj;  // Объект
  MSelectionList list;  // Список выделенных объектов
  MFnDagNode nodefn; // Функции для работы с узлом объекта
  printf("=============================\n");
  printf("Begin mexport...\n");
  if (MGlobal::getActiveSelectionList(list) != MS::kSuccess)
  {
   printf("Error: Can't get selection list\n");
   return MS::kFailure;
  }
  if (list.length() == 0)
    printf("No choosed object\n");
  else
  {
   if (list.length() > 1) printf("This Plug-In works only with one object! Any other will be ignored\n");
   list.getDagPath(0, node, obj);
   nodefn.setObject(node);
   printf("Object '%s' Is Founded\n", nodefn.name().asChar());
  }
  MStatus * ReturnStatus = NULL;
  MItMeshVertex www(node, obj);
  MVector vn;
  bool created = 0;
  MString name = nodefn.name() + ".mdl";
  file = NULL;
  file = fopen("C:\\mexport_obj.txt", "w");  // Открываем файл для выгрузки данных
  fprintf(file, "%d\n", www.count());
  point VV[3000];
  for (i = 0; i < www.count(); i++)
  {
   www.getUV(fuv);
   VV[i].x = www.position(MSpace::kWorld).x;
   VV[i].y = www.position(MSpace::kWorld).y;
   VV[i].z = www.position(MSpace::kWorld).z;
   VV[i].u = fuv[0];
   VV[i].v = fuv[1];
   VV[i].xn = vn.x;
   VV[i].yn = vn.y;
   VV[i].zn = vn.z;  
   www.getNormal(vn, MSpace::kWorld);
   fprintf(file, "%f %f %f %f %f %f %f %f", www.position(MSpace::kWorld).x,
    www.position(MSpace::kWorld).y, www.position(MSpace::kWorld).z,
    fuv[0], fuv[1], vn.x, vn.y, vn.z);
   fprintf(file, "\n");
   www.next();
  }
  // Теперь полигоны
  point PP;
  MItMeshPolygon  poly(node, obj);
  printf("Polygons Count = %d\n", poly.count());
  fprintf(file, "%d\n", poly.count());
  for (i = 0; i < poly.count(); i++)
  {
   fprintf(file, "%d", poly.polygonVertexCount());
   for (j = 0; j < poly.polygonVertexCount(); j++)
   {
    if (poly.getUV(j, fuv) == MS::kFailure)
    {
     printf("Can't Get UV Coordinates For %d Vertex Of %d Polygon", j, i);
     return MS::kFailure;
    }
    PP.x = poly.point(j, MSpace::kWorld).x;
    PP.y = poly.point(j, MSpace::kWorld).y;
    PP.z = poly.point(j, MSpace::kWorld).z;
    for(int i = 0; i < www.count(); i++)
     if(VV[i].test(PP))
     {
      fprintf(file, " %d", i);
      i = www.count();
     }
   }
  }
  fprintf(file, "\n");
  poly.next();
}
printf("End mexport...\n");
printf("=============================\n\n");
fclose(file);
return MS::kSuccess;
}
void *AModelExport::creator()
{
  return new AModelExport;
}
MStatus initializePlugin(MObject obj)
{
  MFnPlugin plugin(obj, "...I...", "1.0");
  MStatus stat;
  stat = plugin.registerCommand("mexport", AModelExport::creator);
  // Аварийное завершение registerCommand в случае неудачи
  if(!stat) stat.perror("registerCommand failed");
  return stat;
}
MStatus uninitializePlugin(MObject obj)
{
  MFnPlugin plugin(obj);
  MStatus stat;
  stat = plugin.deregisterCommand("mexport");
  // Аварийное завершение deregisterCommand в случае неудачи
  if(!stat) stat.perror("deregisterCommand failed");
  return stat;
}

Выгрузка (экспорт) данных выполняется по команде mexport. Команда доступна в Maya после загрузки плагина. Выгружаемый объект должен быть выбран в Maya. Если выбрано несколько объектов, то будут выгружены сведения только об объекте, открывающем список выбранных в Maya объектов.

Вставка данных

Выгруженные из Maya данные переносятся в БД посредством нижеприводимого кода; в нем также имеются средства для создания групп полигонов и группового назначения текстуры (при загрузке все полигоны модели автоматически помещаютсяв в группу 1).

CODE:
class TKnot
{
  public:
   TVertex pozition;
   TVertex normal;
   float uv[2];
   TKnot* ret()
   {
    return this;
   }
};
class TGrope
{
  public:
   AnsiString texture;
   AnsiString texture_name;
   TGrope* ret()
   {
    return this;
   }
};
class SPoligon
{
  public:
   vector<TKnot*>point;
   TGrope* grope;
};
class TObj_poligons : public IObject
{
  public:
    TObj_poligons(AnsiString);
    ~TObj_poligons();
    void create(IObject*& aObj){};
    bool inputFile(FILE *);
    void outputFile(FILE *);
    void draw();
    void del();
    void allocate(const TVertex p1, const TVertex& p2);
    void free();
    // Выделяем путь к текстуре
    AnsiString textura();
    void add_texture(AnsiString, AnsiString);
    void update_texture(AnsiString, AnsiString);
    void delete_texture(AnsiString);
    void Create_grope(AnsiString);
    void delete_grope(int);
    TDataSource *DataSource1;
    TDataSource *DataSource5;
    TDataSource *DataSource_texture;
    TIBClientDataSet *IBClientDataSet_grope;
    TIBClientDataSet *IBClientDataSet_draw;
    TIBClientDataSet *IBClientDataSet_texture;
    TIBSQL *IBSQL1;
    AnsiString m_tras;
  protected:
   void conect();
    TIBDatabase *IBDatabase1;
    TIBTransaction *IBTransaction1;
    int m_kadr;  // Текущий номер кадра
    int m_n;  // Количество вершин
};
TObj_poligons::TObj_poligons(AnsiString str)
{
  m_tras = "";
  m_kadr = 0;
  m_n = 0;
  IBDatabase1 = new TIBDatabase(Application);
  IBTransaction1 = new TIBTransaction(Application);
  IBClientDataSet_grope = new TIBClientDataSet(Application);
  IBSQL1 = new TIBSQL(Application);
  DataSource1 = new TDataSource(Application);
  DataSource5 = new TDataSource(Application);
  IBClientDataSet_draw = new TIBClientDataSet(Application);
  DataSource_texture = new TDataSource(Application);
  IBClientDataSet_texture = new TIBClientDataSet(Application);
  IBTransaction1->DefaultDatabase = IBDatabase1;
  IBDatabase1->Params->Add("user_name=SYSDBA");
  IBDatabase1->Params->Add("password=masterkey");
  IBDatabase1->DefaultTransaction = IBTransaction1;
  IBDatabase1->DatabaseName = str;
  IBDatabase1->Connected = true;
  IBTransaction1->Active = true;
  IBSQL1->Database = IBDatabase1;
  IBSQL1->Transaction = IBTransaction1;
  IBClientDataSet_grope->DBConnection = IBDatabase1;
  IBClientDataSet_grope->DBTransaction = IBTransaction1;
  IBClientDataSet_grope->CommandText =
   "select COD, TEXTURE, ART from GROPE, TEXTURE where GROPE.TEXTURE = TEXTURE.NAME order by COD";
  IBClientDataSet_grope->Active = true;
  DataSource1->DataSet = IBClientDataSet_grope;
  IBClientDataSet_draw->DBConnection = IBDatabase1;
  IBClientDataSet_draw->DBTransaction = IBTransaction1;
  IBClientDataSet_draw->CommandText = "select NOM_GROPE, POLIGON.NOM, POLIGON_POINT.NOM_POINT, X, Y, Z, XN, YN, ZN, U, V from POLIGON, POLIGON_POINT, KADR where POLIGON_POINT.NOM = POLIGON.NOM and POLIGON_POINT.NOM_POINT = KADR.NOM_POINT order by 1";
  IBClientDataSet_draw->Active = true;
  DataSource5->DataSet = IBClientDataSet_draw;
  IBClientDataSet_texture->DBConnection = IBDatabase1;
  IBClientDataSet_texture->DBTransaction = IBTransaction1;
  IBClientDataSet_texture->CommandText = "select * from TEXTURE";
  IBClientDataSet_texture->Active = true;
  DataSource_texture->DataSet = IBClientDataSet_texture;
  conect();
}
TObj_poligons::~TObj_poligons()
{
  delete IBDatabase1;
  delete IBTransaction1;
  delete IBSQL1;
  delete IBClientDataSet_grope;
  delete IBClientDataSet_texture;
  delete IBClientDataSet_draw;
  delete DataSource1;
  delete DataSource5;
}
bool TObj_poligons::inputFile(FILE *file)
{
  FILE *fin;
  // Добавить try
  fin = fopen("c:\qqq.txt","w");
  TKnot p;
  int n = 0;
  fscanf(file,"%d \n",&n);
  for (int i = 1; i <= n; i++)
  {
    fscanf(file, "%f", &p.pozition.x);
    fscanf(file, "%f", &p.pozition.y);
    fscanf(file, "%f", &p.pozition.z);
    fscanf(file, "%f", &p.uv[0]);
    fscanf(file, "%f",.uv[1]);
    fscanf(file, "%f",.normal.x);
    fscanf(file, "%f", &p.normal.y);
    fscanf(file, "%f \n", &p.normal.z);
    fprintf(fin, "INSERT INTO kadr  VALUES(1, %d, %f, %f, %f,  %f, %f, %f); \n",
     i, p.pozition.x, p.pozition.y, p.pozition.z, p.normal.x, p.normal.y, p.normal.z);
  }
  for (int i = 1; i <= n; i++)
   fprintf(fin,"INSERT INTO point  VALUES(%d, 'f'); \n" ,i);
  fprintf(fin,"INSERT INTO grope VALUES(1,'zero'); \n");
  fprintf(fin,"INSERT INTO texture VALUES('zero','textura\\zero.bmp'); \n");
  int kp = 0;  // Количество вершин в полигоне
  int nom = 0;
  fscanf(file, "%d", &n);
  float temp = 3.1415926535 / 2;
  for (int i = 1; i <= n; i++)
  {
    fprintf(fin,"INSERT INTO poligon (nom, nom_grope) VALUES(%d,1); \n", i);
    fscanf(file,"\n %d",&kp);
    for (; kp != 0; kp--)
    {
     fscanf(file,"%d",&nom);
     fprintf(fin,"INSERT INTO poligon_point VALUES( %d, %d, %f, %f); \n",
      i, nom + 1, 0.5 * (1 + cos(i * temp)), 0.5 * (1 + sin(i * temp)));
    }
  }
  fclose(fin);
  return true;
}
void TObj_poligons::draw()
{
  int i, j, k;
  TKnot p;
  AnsiString str = "";
  IBClientDataSet_grope->First();
  IBClientDataSet_draw->First();
  int n = IBClientDataSet_grope->RecordCount;
  for(i = 0; i < n; i++)
  {
    // Установка текстуры или цвета
    str = m_tras + IBClientDataSet_grope->FieldByName("ART")->AsString;
    LoadGLTextures(str.c_str());
    while((i + 1 == IBClientDataSet_draw->FieldByName("NOM_GROPE")->AsInteger) && (!IBClientDataSet_draw->Eof))
    {
      j = IBClientDataSet_draw->FieldByName("NOM")->AsInteger;
      glBegin(GL_POLYGON);
        while((j == IBClientDataSet_draw->FieldByName("NOM")->AsInteger) && (!IBClientDataSet_draw->Eof))
        {
          p.uv[0] = IBClientDataSet_draw->FieldByName("U")->AsFloat;
          p.uv[1] = IBClientDataSet_draw->FieldByName("V")->AsFloat;
          p.pozition.x = IBClientDataSet_draw->FieldByName("X")->AsFloat;
          p.pozition.y = IBClientDataSet_draw->FieldByName("Y")->AsFloat;
          p.pozition.z = IBClientDataSet_draw->FieldByName("Z")->AsFloat;
          p.normal.x = IBClientDataSet_draw->FieldByName("XN")->AsFloat;
          p.normal.y = IBClientDataSet_draw->FieldByName("YN")->AsFloat;
          p.normal.z = IBClientDataSet_draw->FieldByName("ZN")->AsFloat;
          glTexCoord2f(p.uv[0], p.uv[1]);
          glNormal3f(p.normal.x, p.normal.y, p.normal.z);
          glVertex3f(p.pozition.x, p.pozition.y, p.pozition.z);
          IBClientDataSet_draw->Next();
        }
      glEnd();
    }
    IBClientDataSet_grope->Next();
  }
}
void TObj_poligons::allocate(const TVertex p1, const TVertex& p2)
{
  TReplaceFlags flags;
  m_kadr = 1;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("EXECUTE PROCEDURE select_point(");
  IBSQL1->SQL->Add(IntToStr(m_kadr) + ",");
  IBSQL1->SQL->Add(StringReplace(FloatToStr(p1.x), ", ", ".", flags) + ",");
  IBSQL1->SQL->Add(StringReplace(FloatToStr(p1.y), ", ", ".", flags) + ",");
  IBSQL1->SQL->Add(StringReplace(FloatToStr(p1.z), ", ", ".", flags) + ",");
  IBSQL1->SQL->Add(StringReplace(FloatToStr(p2.x), ", ", ".", flags) + ",");
  IBSQL1->SQL->Add(StringReplace(FloatToStr(p2.y), ", ", ".", flags) + ",");
  IBSQL1->SQL->Add(StringReplace(FloatToStr(p2.z), ", ", ".", flags) + ");");
  IBSQL1->ExecQuery();
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("EXECUTE PROCEDURE select_poligon;");
  IBSQL1->ExecQuery();
}
void TObj_poligons::free()
{
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("UPDATE ");
  IBSQL1->ExecQuery();
}
void TObj_poligons::conect()
{
  m_tras = IBDatabase1->DatabaseName;
  m_tras.SetLength(LastDelimiter("\\", m_tras));
}
AnsiString TObj_poligons::textura()
{
  return (m_tras + IBClientDataSet_texture->FieldByName("ART")->AsString);
}
void TObj_poligons::add_texture(AnsiString str, AnsiString str_name)
{
  IBClientDataSet_texture->Active = false;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("INSERT INTO texture VALUES('" + str_name + "','" + str + "');");
  IBSQL1->ExecQuery();
  IBClientDataSet_texture->Active = true;
}
void TObj_poligons::update_texture(AnsiString art_new, AnsiString name)
{
  IBClientDataSet_texture->Active = false;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("UPDATE texture SET art = '" + art_new + "' WHERE name = '" + name + "';");
  IBSQL1->ExecQuery();
  IBClientDataSet_texture->Active = true;
}
void TObj_poligons::delete_texture(AnsiString str)
{
  IBClientDataSet_texture->Active = false;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("DELETE FROM texture WHERE name = '" + str + "';");
  IBSQL1->ExecQuery();
  IBClientDataSet_texture->Active = true;
}
void TObj_poligons::Create_grope(AnsiString name)
{
  IBClientDataSet_draw->Active = false;
  IBClientDataSet_grope->Active = false;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("EXECUTE PROCEDURE create_grope('" + name + "');");
  IBSQL1->ExecQuery();
  IBClientDataSet_draw->Active = true;
  IBClientDataSet_grope->Active = true;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("UPDATE poligon SET act = 'f';");
  IBSQL1->ExecQuery();
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("UPDATE point SET act = 'f';");
  IBSQL1->ExecQuery();
}
void TObj_poligons::delete_grope(int n)
{
  IBClientDataSet_draw->Active = false;
  IBClientDataSet_grope->Active = false;
  IBSQL1->ParamCheck = false;
  IBSQL1->SQL->Clear();
  IBSQL1->SQL->Add("DELETE from grope where cod = "+ IntToStr(n) + ";");
  IBSQL1->ExecQuery();
  IBClientDataSet_draw->Active = true;
  IBClientDataSet_grope->Active = true;
}

Пример

Выгруженная из Maya полигональная модель кисти руки была затем загружена в созданную БД.
Проверка выполнена посредством визуализации хранимой в БД модели кисти средствами OpenGL (рис. 2).

Загрузка кисти руки из БД

Рис. 2. Воспроизведение хранимой в БД полигональной модели кисти

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

Групповое назначение текстуры

Рис. 3. Назначение текстуры группе полигонов

Источники

  1. Гоулд Дэвид А. Д. Полное руководство по программированию Maya. Подробное описание языка MEL и интерфейса C++ API. Перевод с англ. Петров А.В. М.: КУДИЦ-ОБРАЗ, 2004.
  2. Пахомов Б. И. Interbase и С++ Builder. СПб.: БХВ-Петербург, 2006.

Список работ

Рейтинг@Mail.ru