Для эффективной и максимально быстрой работы с вершинами и треугольниками, операции над ними можно производить непосредственно в памяти из внешних библиотек, не прибегая к встроенным командам блица. В качестве примера напишем функцию для преобразования всех вершин выбранного сурфейса в глобальную систему координат произвольной Entity, в качастве среды разработки возьмём MSVC++ 6.0. Для начала нам нужно получить адрес сурфейса(сетки), где хранятся Vertex Buffer и Index Buffer(треугольники). SurfHandle = GetSurface(model, 1 ) ;хендл(адрес) сурфейса. (прим. Структуру сурфейса можно посмотреть здесь: http://blitz.pp.ru/forum/showthread.php?s=&threadid=203 ) Vertex Buffer лежит по смещению (SurfHandle + 28байт), Index Buffer - (SurfHandle + 44байта). Для простоты работы с вершинами можно создать специальную структуру, с помощью которой мы будем обращаться к параметрам вершины: typedef struct _BBVERTEX { float x,y,z; float nx,ny,nz; char a,r,g,b; float u0,v0; float u1,v1; char i1,i2,i3,i4; float w1,w2,w3,w4; } BBVERTEX, *LPBBVERTEX; Точно также можно сделать и для треугольников: typedef struct _BBTRIANGE { unsigned short a,b,c; } BBTRIANGE, *LPBBTRIANGE; (прим. Треугольник - это последовательность 3-х индексов в IndexBuffer соответственно) Для получения положения Entity (поворот, размер, позиция), воспользуемся её матрицей трансформации. Глобальная матрица хранится по смещению (SurfHandle + 216байт), таже матрица, но с учётом Tween(если используется), хранится по адресу (SurfHandle + 516байт). (прим. В спецификации DirectX используются матрицы размерностью 4х4, но для пространственных преобразований достаточно матрицы 3х4, она и хранится в структуре Entity в блице) Получение матрицы: float EMatrix11= *(Entity+44); float EMatrix12= *(Entity+45); float EMatrix13= *(Entity+46); float EMatrix21= *(Entity+47); float EMatrix22= *(Entity+48); float EMatrix23= *(Entity+49); float EMatrix31= *(Entity+50); float EMatrix32= *(Entity+51); float EMatrix33= *(Entity+52); float EMatrix41= *(Entity+53); float EMatrix42= *(Entity+54); float EMatrix43= *(Entity+55); (прим. В С++ значение смещения для указателей учитывается в соответствии с их типом, например, если используется тип Float(4байта), то смещение на 40 байт будет указано как +10) Для преобразования координат вершины, нужно перемножить их на матрицу: //координаты исходной сетки. x=SrcVertexBuffer[vertex].x; y=SrcVertexBuffer[vertex].y; z=SrcVertexBuffer[vertex].z; //преобразованные координаты. DestVertexBuffer [vertex].x = EMatrix11*x + EMatrix21*y + EMatrix31*z + EMatrix41; DestVertexBuffer [vertex].y = EMatrix12*x + EMatrix22*y + EMatrix32*z + EMatrix42; DestVertexBuffer [vertex].z = EMatrix13*x + EMatrix23*y + EMatrix33*z + EMatrix43; Количество вершин можно получить так: int VertexCount = ( *(surfaceSrc+8) - *(surfaceSrc+7) )/64; (прим. 64 - количество байт на одну вершину) Цикл перебора вершин будет выглядеть так: for (int vertex = 0; vertex { x=SrcVertexBuffer[vertex].x; y=SrcVertexBuffer[vertex].y; z=SrcVertexBuffer[vertex].z; DestVertexBuffer [vertex].x = EMatrix11*x + EMatrix21*y + EMatrix31*z + EMatrix41; DestVertexBuffer [vertex].y = EMatrix12*x + EMatrix22*y + EMatrix32*z + EMatrix42; DestVertexBuffer [vertex].z = EMatrix13*x + EMatrix23*y + EMatrix33*z + EMatrix43; } Таким образом Мы можем вертеть сетку в соответствии с позицией любой Entity (Прим. При изменении координат вершин мы изменяем размер всей сетки, но блиц проверяет её видимость по старому размеру, поэтому корректнее также изменять и параметры ограничивающего бокса(Bounding Box) - см. структуру меша) Полный код функции: BBDECL void TransformSurfaceToMatrix( unsigned int *surfaceSrc, unsigned int *surfaceDest, float *Entity ) { LPBBVERTEX SrcVertexBuffer, DestVertexBuffer ; float x,y,z; float EMatrix11= *(Entity+44); float EMatrix12= *(Entity+45); float EMatrix13= *(Entity+46); float EMatrix21= *(Entity+47); float EMatrix22= *(Entity+48); float EMatrix23= *(Entity+49); float EMatrix31= *(Entity+50); float EMatrix32= *(Entity+51); float EMatrix33= *(Entity+52); float EMatrix41= *(Entity+53); float EMatrix42= *(Entity+54); float EMatrix43= *(Entity+55); SrcVertexBuffer = (struct _BBVERTEX *)*(surfaceSrc +7); //Адрес начала вершинного буфера исходной сетки DestVertexBuffer = (struct _BBVERTEX *)*(surfaceDest+7); //Адрес начала вершинного буфера трансформируемой сетки *(surfaceDest+16)=0; //Обнуление этого флага означает изменение вертекс буфера, после чего он будет передан видеокарте int VertexCount = ( *(surfaceSrc+8) - *(surfaceSrc+7) )/64; //Количество вершин в сетке for (int vertex = 0; vertex { x=SrcVertexBuffer[vertex].x; y=SrcVertexBuffer[vertex].y; z=SrcVertexBuffer[vertex].z; // Здесь мы производим перемножение координат вершины исходной сетки на матрицу и запись результата в изменяемую сетку DestVertexBuffer [vertex].x = EMatrix11*x + EMatrix12*y + EMatrix13*z + EMatrix41; DestVertexBuffer [vertex].y = EMatrix21*x + EMatrix22*y + EMatrix23*z + EMatrix42; DestVertexBuffer [vertex].z = EMatrix31*x + EMatrix32*y + EMatrix33*z + EMatrix43; } } Пример использования в Blitz3D: Graphics3D 640,480,32,2 SetBuffer BackBuffer() camera=CreateCamera() PositionEntity camera,0,10,-30 light=CreateLight(1) RotateEntity light,50,80,0 Entity1=CreateCube(); PositionEntity Entity1,15,10,0 ScaleEntity Entity1,5,5,5 SurfaceSrc = GetSurface(Entity1, 1) Vcount = CountVertices(SurfaceSrc) Entity2=CopyMesh(Entity1) EntityColor Entity2,255,0,0 PositionEntity Entity2,-30,0,0 SurfaceDest = GetSurface(Entity2, 1) While Not KeyHit(1) TurnEntity Entity1, 1, 1, 0 RenderWorld() If KeyDown(57) Text 5,5, "Don't ransformate" Else Text 5,5, "Transformating SurfaceSrc(Red color)" TransformSurfaceToMatrix SurfaceSrc, SurfaceDest, Entity1 EndIf Flip 1 Wend End Пример к статье можно найти здесь: http://andreyman.ucoz.ru/VertexSample.rar
|