» Главная
eXcode.ru » Статьи » Delphi/Pascal » Мультимедиа
» Новости
» Опросы
» Файлы
» Журнал



Пользователей: 0
Гостей: 3





Вoксельная графика: От азов до движка




Насколько мы знаем, экран PC разбит на множество мельчайших точек, называемых пикселями. Но давайте взглянем в 3d пространство. Воксель – это своего рода 3d пиксель, т.е. точка в трехмерном пространстве. Из курса геометрии нам известно, что все тела состоят из точек поэтому воксельная графика ближе к реальности чем полигонарная.
Что представляет из себя воксель и воксельная графика для PC.
Как представить точку в языке Object Pascal? Надо учитывать все, что связано с частицами в нашем мире. Чтобы не описывать свойства каждой частицы, следует объединять частицы в материалы. Все материалы будут располагаться в массиве типа


TAMaterials

//А у каждой частицы будет просто номер материала – это намного уменьшит потребляемую память.

Delphi/Pascal код:

type TVoxel = record
MType : lognint; //Материал, из которого сделана частица
Ex : boolean; // Существует ли точка(для 3d матриц)
// Возможны еще свойства для частиц
end;
TMaterial = record // Описание типа материала
Name : string; // Название
Color : tcolor; // Цвет
Mirror : single; // Способность к ражению - между 0 и 1
Glass : single; // Коэффициент прозрачности - между 0 и 1
SType : byte; // 1-твердый, 2-жидкий, 3-газообразный
Lighting : integer; // Способность излучать свет (0=выкл)
LColor : tcolor; // Цвет излучаемого цвета
end;
// Коллекция материалов в одном массиве
TAMaterials = array of TMaterial;


Хранение и работа с вокселями.

Я знаю 2 способа хранения вокселей:
1) Статичная 3d матрица:
Отличается большим размером потребляемой памяти, но имеет более удобные способы доступа к вокселям для редактирования.
2) Динамичный массив вокселей:
Отличается гораздо меньшим объемом занимаемой памяти, но неудобен в прямом обращении к вокселям во многих операциях (кроме вращения).
У нас есть 2 способа хранения вокселей, у каждого есть свои достоинства и недостатки. Мы не будем игнорировать ни один из них, поэтому будем пользоваться обоими.


const
X_len=<<Длина сцены по оси X>>;
Y_len=<<Длина сцены по оси Y>>;
Z_len=<<Длина сцены по оси Z>>;
type
T3dMatrix = array[0..X_len,0..Y_len,0..Z-len] of TVoxel; // Трехмерная матрица вокселей
TArrayOfVoxels = array of record // Динамичный массив
x,y,z : integer; // Координаты
Voxel : TVoxel; // Воксель
end;


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


function Convert3dtoD(Mtx: T3dMatrix):TArrayOfVoxels;
var
aov: TArrayofVoxels;
x,y,z:integer;
begin
setlength(aov,0);
for x:=0 to X_len do
for y:=0 to Y_len do
for z:=0 to Z_len do
if (mtx[x,y,z].ex) then
begin
setlength(aov,length(aov)+1);
aov[length(aov)-1].Voxel:=mtx[x,y,z];
end;
result:=aov;
end;
function ConvertDto3d(da: TArrayOfVoxels):3dMatrix;
var mtx:T3dMatrix; i:integer;
begin
for i:=0 to length(da)-1 do
mtx[da.x,da.y,da.z]:=da.voxel;
result:=mtx;
end;


Этими способами конвертации нам придется воспользоваться в дальнейшем.
**Воксельная сцена как объект языка Object Pascal.
Чтобы удобнее было работать с воксельными сценами в Object Pascal можно создать свой объект.


type
T3dVoxel = class
private
{ Непубликуемые возможности }
public
{ Опубликованные возможности }
end;


Пока наш объект T3dVoxel – пустой. Теперь поработаем над его содержимым. Для начала создадим переменную, которая будет содержать в себе воксельную сцену.


public
scene: TArrayOfVoxels;


Графическое исполнение воксельной сцены.

Как нанести на полотно нашу воксельную сцену? Лучше на полотно мы будем наносить трехмерную матрицу. Для этого есть 2 способа.
1) Слоями: Этот способ самый легкий. Надо просто разбить 3d матрицу разбить на N 2d Матриц и наносить на полотно в обратной очередности.


procedure DrawVoxels_L(Voxels:3dMatrix; At: TCanvas);
var x,y,z:integer;
begin
for z:=Z_len downto 0 do
for x:=0 to X_len do
for y:=0 to Y_len do
if (voxels[x,y,z].ex) then
At.pixels[x,y]:=Materials[Voxels[x,y,z].MType].color;
end;


Как видно из этой процедуры, сложность данного алгоритма - N3, т.е. проверяется каждая точка воксельной сцены. И все это еще осложняется тем, что каждая точка должна прорисовываться на полотне даже если ее не видно.
2) “До первой точки” – это самый лучший способ для прорисовки воксельных сцен.


function DrawVoxels_T(voxels : T3dMatrix; At:Tcanvas);
Var x,y,z:integer; b:boolean;
Begin
for x:=0 to X_len do
for y:=0 to Y_len do
begin
b:=true;
z:=X_len;
while b do begin
if (Voxels[x,y,z].ex) then begin
At.canvas.pixels[x,y]:= Materials[Voxels[x,y,z].Mtype].color;
b:=false;
end;
if z=0 then b:=false;
dec(z);
end;


Поворот воксельной сцены на градус.

Теперь нужна функция для поворота вокселя вокруг осей x,y и z.


// Поворот вокруг оси Z
Function rotate_Z(da:TArrayOfVoxels;angle:real): TArrayOfVoxels;
Var I:integer; daw:TArrayOfVoxels; xo,yo : word;
r, a : single; s, c : extended;
Begin
angle:= angle /57; xo:=X_led div 2; yo:=Y_led div 2;
for i:=0 to length(da)-1 do
begin
setlength(daw, length(daw)+1);
r := sqrt(sqr(da[ i ].x - xo) + sqr(da[ i ].y - yo));
SinCos(angle + arctan2((da[ i ].y - yo), (da[ i ].x - xo)), s, c);
daw[ i ].x:=round(xo + r * c);
daw[ i ].y:=round(yo + r * s);
daw[ i ].z:=da[ i ].z;
daw[ i ].Voxel:=da[ i ].Voxel;
end;
result:=daw;
end;


Аналогично и для вокруг других осей.
Вот мы и получили полноценный объект языка Object Pascal, позволяющий нам использовать воксельную графику в своих приложениях! Хотя многие свойства(прозрачность, ...) еще не реализованы, но этот движок работает... Я думаю в дальнейшем можно будет придумать различные способы реализации и таких свойств! Спасибо за внимание!

Автор: bars
К началу статьи





Добавил: LedWormДата публикации: 2005-12-15 18:56:04
Рейтинг статьи:5.00 [Голосов 2]Кол-во просмотров: 8491

Комментарии читателей

Всего комментариев: 2

2009-08-04 14:58:45
Dr.Evil
+1 хотелось бы готовый пример для тестирования!!!!

2009-07-13 20:39:40
DungeonLords
А примеры можно разместить? И картинок бы в статью наставлять!
Ваше имя: *
Текст записи: *
Имя:

Пароль:



Регистрация

Вы жалеете, что Билли уходит на пенсию?
Гореть ему в АДУ!!!
41% (53)
Побыстрее бы ушел!
5% (6)
Уйдет он, придет другой!
28% (36)
А мне все равно, я Mac юзаю!
2% (3)
Жаль, дядю Билла :(
12% (15)
Может он передумает?!
13% (17)

Проголосовало: 130
Hе пей из чайника - чайником станешь...
Рейтинг: 8.3/10 (7)
Посмотреть все анекдоты