3d движок
Зачем?
Наверно каждый программист
хотел написать, что-то по настоящему мощное,
чем можно было удивить. Казалось бы все уже
написано: Quake, CS и пр. Зачем? Но настоящего
программиста, как ребенка разбирающего
игрушку, интересует: что внутри. Как
работает Quake и CS? Какие математические
формулы используются для перевода из
мировых координат в экранные? На этот
вопрос я постараюсь дать ответ. В качестве
языка программирования будет
использоваться Borland Pascal 7.0. В процессе
разработки я буду давать максимально
подробные комментарии.
Как?
Не буду особо докучать теорией.
Скажу лишь только, что трехмерное
пространство проецируется на экран с
помощью тригонометрии. Каждый семиклассник
знает что такое векторы и проекции.
Программа.
Для скорости вычисления мы сразу
создадим массив для хранения синусов и
косинусов для углов от 0 до 359 градусов. В
программе используется разрешение 640*350 т.к.
этот видеорежим содержит 2 видеостраницы.
maxx и maxy отвечают за правую нижнюю точку.
tsin и tcos массив, содержащий sin и cos. perspective переменная
отвечающая за использование перспективы,
а e - коэффициент перспективы (как далеко
объект от нас). rotate(Ax,Ay,Az:Integer; var p: Point3d);
поворачивает точку вокруг осей Ax, Ay, Az. transform(pt3d:Point3d; var x2d,y2d:Integer);
переводит из 3d в 2d. line3d(point1,point2:Point3d; color:byte);
построение линии из 2х точек с заданным
цветом. После запуска программы: q и a поворачивают
вокруг оси X, w и s поворачивают вокруг оси Y, e
и d поворачивают вокруг оси Z. ESC - выход.
Между {-----------------} находиться прорисовка
куба со стороной 200. Можно организовать
считывание линий из файла. Можно
организовать построение трехмерного
графика, сферы и пр. Можно в программе
использовать мышь - что еще лучше!!! Скоро в
разделе Pascal появится моя работа и с мышкой и
со всеми прибамбасами, просто нужно все
собрать и зазиповать. Там есть программа по
построению графиков, есть файлы со сферой и
кубом и с поверхностями. Я уверен, что этот
небольшой пример будет началом создания
игры. Если у вас что-нибудь получиться -
пишите alexartwww@yandex.ru!
Также нужно создать алгоритм по отрезанию
невидимых линий!
Скачать
программу
Скачать программу для Windows написанную на
Delphi.
Текст программы:
{$G+}
uses crt,graph;
type
point3d = Record
x,y,z:Integer;
end;
var
tcos,tsin:array[0..359] of
Extended;
int:Integer;
perspective:Boolean;
e:Integer;
maxx,maxy,ox,oy,oz:Integer;
gd,gm,m:Integer;
key:Char;
p1,p2:point3d;
const
gr = pi/180;
procedure transform(pt3d:Point3d; var x2d,y2d:Integer);
var
Thit:Real;
begin
if perspective then
begin
Thit:=1/(1-pt3d.x/e);
x2d:= trunc(maxx/2+pt3d.y*thit);
y2d:= trunc(maxy/2-pt3d.z*thit);
end
else
begin
x2d:=trunc(maxx/2+round(pt3d.y));
y2d:=trunc(maxy/2-round(pt3d.z));
end;
end;
procedure rotate(Ax,Ay,Az:Integer; var p: Point3d);
var
s1,s2,s3,c1,c2,c3:Extended;
Puit:Point3d;
begin
s1:=tsin[trunc(ax)];
c1:=tcos[trunc(ax)];
s2:=tsin[trunc(ay)];
c2:=tcos[trunc(ay)];
s3:=tsin[trunc(az)];
c3:=tcos[trunc(az)];
puit.x:=trunc(p.x*(c2*c3)+p.y*(c2*s3)-p.z*s2);
puit.y:=trunc(p.x*(s1*s2*c3-c1*s3)+p.y*(s1*s2*s3+c1*c3)+p.z*(s1*c2));
puit.z:=trunc(p.x*(c1*s2*c3+s1*s3)+p.y*(c1*s2*s3-s1*c3)+p.z*(c1*c2));
p:=puit;
end;
procedure linec(x1,y1,x2,y2:Integer; color:byte);
begin
setcolor(color);line(x1,y1,x2,y2);
end;
procedure line3d(point1,point2:Point3d; color:byte);
var
x1,x2,y1,y2:Integer;
begin
transform(point1,x1,y1);
transform(point2,x2,y2);
if ((x1 > 0) and (x1 < maxx)) or ((y1 > 0) and (y1 < maxy)) then
linec(x1,y1,x2,y2,color);
end;
Begin
perspective:=true;
e:=300;
for int := 0 to 359 do
begin
tsin[int]:=sin(int*gr);
tcos[int]:=cos(int*gr);
end;
gd:=9;gm:=1;
InitGraph(gd,gm,'');
maxx:=640;
maxy:=350;
m:=0;
repeat
key:=#0;
if keypressed then key:=readkey;
if key = #113 then ox:=ox-1;
if key = #97 then ox:=ox+1;
if key = #119 then oy:=oy-1;
if key = #115 then oy:=oy+1;
if key = #101 then oz:=oz-1;
if key = #100 then oz:=oz+1;
if ox > 359 then ox:=ox-359;
if ox < 0 then ox:=359-(0-ox);
if oy > 359 then oy:=oy-359;
if oy < 0 then oy:=359-(0-oy);
if oz > 359 then oz:=oz-359;
if oz < 0 then oz:=359-(0-oz);
m:=1-m;
setactivepage(m);
cleardevice;
{-----------------------}
p1.x:=-100;
p1.y:=-100;
p1.z:=100;
p2.x:=100;
p2.y:=-100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=100;
p1.y:=-100;
p1.z:=100;
p2.x:=100;
p2.y:=100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=100;
p1.y:=100;
p1.z:=100;
p2.x:=-100;
p2.y:=100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=-100;
p1.y:=100;
p1.z:=100;
p2.x:=-100;
p2.y:=-100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=-100;
p1.y:=-100;
p1.z:=-100;
p2.x:=100;
p2.y:=-100;
p2.z:=-100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=100;
p1.y:=-100;
p1.z:=-100;
p2.x:=100;
p2.y:=100;
p2.z:=-100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=100;
p1.y:=100;
p1.z:=-100;
p2.x:=-100;
p2.y:=100;
p2.z:=-100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=-100;
p1.y:=100;
p1.z:=-100;
p2.x:=-100;
p2.y:=-100;
p2.z:=-100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=100;
p1.y:=100;
p1.z:=-100;
p2.x:=100;
p2.y:=100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=-100;
p1.y:=100;
p1.z:=-100;
p2.x:=-100;
p2.y:=100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=100;
p1.y:=-100;
p1.z:=-100;
p2.x:=100;
p2.y:=-100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
p1.x:=-100;
p1.y:=-100;
p1.z:=-100;
p2.x:=-100;
p2.y:=-100;
p2.z:=100;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,15);
{OX}
p1.x:=150;
p1.y:=0;
p1.z:=0;
p2.x:=0;
p2.y:=0;
p2.z:=0;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,14);
{OY}
p1.x:=0;
p1.y:=150;
p1.z:=0;
p2.x:=0;
p2.y:=0;
p2.z:=0;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,14);
{OZ}
p1.x:=0;
p1.y:=0;
p1.z:=150;
p2.x:=0;
p2.y:=0;
p2.z:=0;
rotate(ox,oy,oz,p1);
rotate(ox,oy,oz,p2);
line3d(p1,p2,14);
{-----------------------}
setvisualpage(m);
until (key = #27);
closegraph;
end.
|
|