Цитата(Чупакабро @ 27.9.2007, 16:09) | Значит так, выкладываю код. Нужно создать форму с таймером и весь код модуля unit1 заменить на нижеследующий. Сейчас нет времени писать подробные комментарии, это я наверное на выходных сделаю, но про некоторые особенности напишу сейчас. Прграмма рисует вращающийся куб, режим закраски можно менять клавишей "пробел". Прграмма поддерживает отрисовку и анимацию произвольных полигональных объектов стандартными средствами Delphi (без использования DirectX и OpenGL). Можно изменять позицию объектов и камеры. Не успел реализовать отсечение невидимых треугольников, z-buffer, направленные источники света. Возможно добавлю позднее. Программа получилась большая, т.к. претендует на универсальность, а не только на отрисовку конкретно вращающегося куба.
Собственно код:
Код | unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Math, ExtCtrls; //uses math
type
TMatrix=record _11,_12,_13,_14,_21,_22,_23,_24,_31,_32,_33,_34,_41,_42,_43,_44:single; end; T3Matrix=record _11,_12,_13,_21,_22,_23,_31,_32,_33:single end;
TPoint3d=record x,y,z:single; end;
TTriangle=array[1..3] of TPoint3d;
TMesh=class triangles:array of TTriangle; cx,cy,cz:single; procedure rotate(rx,ry,rz:single); procedure move(dx,dy,dz:single); end;
TForm1 = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); private { Private declarations } public { Public declarations } HW:single; fov:single; pview:tpoint3d; pviewto:tpoint3d; fillmode:byte;//0-solid,1-wireframe,2-point cullmode:byte;//0-iao iona?aiey,1-?eno?ony ii ?n,2-?eno?ony i?ioea ?n backBitmap:tbitmap; clbckgr:tcolor; curcl:tcolor; curbrcl:tcolor; function projection(tr3d:TTriangle; clwidth,clheight:integer):TTriangle; procedure setrotatexmatrix(var m:TMatrix; angle:single); procedure setrotateymatrix(var m:TMatrix; angle:single); procedure setrotatezmatrix(var m:TMatrix; angle:single); procedure settranslatematrix(var m:TMatrix; x,y,z:single); procedure render; procedure drawtriangle(t:TTriangle); procedure addcube; end;
var Form1: TForm1; cube:tmesh;
implementation
{$R *.dfm} function GetVecLength(x,y,z:single):single; begin GetVecLength:=sqrt(sqr(x)+sqr(y)+sqr(z)); end;
function norm(p1,p2,p3:TPoint3d):TPoint3d; var v1,v2:tpoint3d; begin v1.x:=p2.x-p1.x; v1.y:=p2.y-p1.y; v1.z:=p2.z-p1.z; v2.x:=p3.x-p1.x; v2.y:=p3.y-p1.y; v2.z:=p3.z-p1.z; norm.x:=v1.y*v2.z-v1.z*v2.y; norm.y:=-v1.x*v2.z+v1.z*v2.x; norm.z:=v1.x*v2.y-v1.y*v2.x; end;
{function det(_11,_12,_13,_21,_22,_23,_31,_32,_33:single):single; begin det:=_11*(_22*_33-_32*_23)-_12*(_21*_33-_31*_23)+_13*(_21*_32-_31*_22); end;}
function matrixmul(m1,m2:TMatrix):TMatrix; begin matrixmul._11:=m1._11*m2._11+m1._12*m2._21+m1._13*m2._31+m1._14*m2._41; matrixmul._12:=m1._11*m2._12+m1._12*m2._22+m1._13*m2._32+m1._14*m2._42; matrixmul._13:=m1._11*m2._13+m1._12*m2._23+m1._13*m2._33+m1._14*m2._43; matrixmul._14:=m1._11*m2._14+m1._12*m2._24+m1._13*m2._34+m1._14*m2._44;
matrixmul._21:=m1._21*m2._11+m1._22*m2._21+m1._23*m2._31+m1._24*m2._41; matrixmul._22:=m1._21*m2._12+m1._22*m2._22+m1._23*m2._32+m1._24*m2._42; matrixmul._23:=m1._21*m2._13+m1._22*m2._23+m1._23*m2._33+m1._24*m2._43; matrixmul._24:=m1._21*m2._14+m1._22*m2._24+m1._23*m2._34+m1._24*m2._44;
matrixmul._31:=m1._31*m2._11+m1._32*m2._21+m1._33*m2._31+m1._34*m2._41; matrixmul._32:=m1._31*m2._12+m1._32*m2._22+m1._33*m2._32+m1._34*m2._42; matrixmul._33:=m1._31*m2._13+m1._32*m2._23+m1._33*m2._33+m1._34*m2._43; matrixmul._34:=m1._31*m2._14+m1._32*m2._24+m1._33*m2._34+m1._34*m2._44;
matrixmul._41:=m1._41*m2._11+m1._42*m2._21+m1._43*m2._31+m1._44*m2._41; matrixmul._42:=m1._41*m2._12+m1._42*m2._22+m1._43*m2._32+m1._44*m2._42; matrixmul._43:=m1._41*m2._13+m1._42*m2._23+m1._43*m2._33+m1._44*m2._43; matrixmul._44:=m1._41*m2._14+m1._42*m2._24+m1._43*m2._34+m1._44*m2._44; end;
procedure TMesh.rotate(rx,ry,rz:single); var i,j:integer; rvec:tpoint3d; length:single; ax,ay,az:single; dc,dx,dy,dz:T3Matrix; dx1,dy1,dz1:single; begin for i:=0 to high(triangles) do begin for j:=1 to 3 do begin
rvec.x:=(triangles[i][j].x-cx); rvec.y:=(triangles[i][j].y-cy); rvec.z:=(triangles[i][j].z-cz);
if rx<>0 then begin length:=GetVecLength(0,triangles[i][j].y-cy,triangles[i][j].z-cz); if length<>0 then begin if rvec.y>=0 then begin dx1:=arccos((rvec.z)/length) ; end else begin dx1:=-arccos((rvec.z)/length) ; end; end else begin dx1:=0; end; triangles[i][j].y:=cy+length*sin(rx+dx1); triangles[i][j].z:=cz+length*cos(rx+dx1); rvec.x:=(triangles[i][j].x-cx); rvec.y:=(triangles[i][j].y-cy); rvec.z:=(triangles[i][j].z-cz); end;
if ry<>0 then begin length:=GetVecLength(triangles[i][j].x-cx,0,triangles[i][j].z-cz); if length<>0 then begin if rvec.z>=0 then begin dy1:=arccos(rvec.x/length) ; end else begin dy1:=-arccos(rvec.x/length) ; end; end else begin dy1:=0; end; triangles[i][j].x:=cx+length*cos(ry+dy1); triangles[i][j].z:=cz+length*sin(ry+dy1); rvec.x:=(triangles[i][j].x-cx); rvec.y:=(triangles[i][j].y-cy); rvec.z:=(triangles[i][j].z-cz); end;
if rz<>0 then begin length:=GetVecLength(triangles[i][j].x-cx,triangles[i][j].y-cy,0); if length<>0 then begin if rvec.x>=0 then begin dz1:=arccos((rvec.y)/length) ; end else begin dz1:=-arccos((rvec.y)/length) ; end; end else begin dz1:=0; end; triangles[i][j].x:=cx+length*sin(rz+dz1); triangles[i][j].y:=cy+length*cos(rz+dz1); end;
end; end; end;
procedure TMesh.move(dx,dy,dz:single); var i,j:integer;
begin for i:=0 to high(triangles) do begin for j:=1 to 3 do begin triangles[i][j].x:=triangles[i][j].x+dx; triangles[i][j].y:=triangles[i][j].y+dy; triangles[i][j].z:=triangles[i][j].z+dz; end; end; end;
function TForm1.projection(tr3d:TTriangle; clwidth,clheight:integer):TTriangle; var i:integer; xc,yc,zc,xc1,yc1,zc1,lc,l:single;//aaeoi? eaia?u crx,cry,crz:single; mtx,mty,mtz,mts,beeline:tmatrix; vect:tpoint3d; x,y,z:single; halfWidth,halfHeight:integer; tx,ty:single; begin halfwidth:=clwidth div 2; halfheight:=clheight div 2; lc:=GetVeclength(pviewto.x-pview.x,pviewto.y-pview.y,pviewto.z-pview.z); if lc=0 then exit; xc:=(pviewto.x-pview.x)/lc; yc:=(pviewto.y-pview.y)/lc; zc:=(pviewto.z-pview.z)/lc;
l:=GetVeclength(0,pviewto.y-pview.y,pviewto.z-pview.z); if l<>0 then begin yc1:=(pviewto.y-pview.y)/l; zc1:=(pviewto.z-pview.z)/l; if zc1<=0 then crx:=-arcsin(yc1) else crx:=arcsin(yc1); end else crx:=0;
l:=GetVeclength(pviewto.x-pview.x,0,pviewto.z-pview.z); if l<>0 then begin xc1:=(pviewto.x-pview.x)/l; zc1:=(pviewto.z-pview.z)/l; if xc1>=0 then cry:=arccos(zc1) else cry:=-arccos(zc1); end else cry:=0;
{l:=GetVeclength(pviewto.x-pview.x,pviewto.y-pview.y,0); if l<>0 then begin xc1:=(pviewto.x-pview.x)/l; yc1:=(pviewto.y-pview.y)/l; if yc1>=0 then crz:=arccos(xc1) else crz:=-arccos(xc1); end else crz:=0; }
setrotatexmatrix(mtx,-crx); setrotateymatrix(mty,-cry); {setrotatezmatrix(mtz,-crz); } mts:=matrixmul(mtx,mty); {mts:=matrixmul(mts,mtz);} settranslatematrix(beeline,-pview.x,-pview.y,-pview.z); mts:=matrixmul(beeline,mts);
for i:=1 to 3 do begin x:=tr3d[i].x; y:=tr3d[i].y; z:=tr3d[i].z{-pview.z}; vect.x:=x*mts._11+y*mts._21+z*mts._31+mts._41; vect.y:=x*mts._12+y*mts._22+z*mts._32-mts._42; vect.z:=x*mts._13+y*mts._23+z*mts._33+mts._43; x:=vect.x; y:=vect.y; z:=vect.z; x:=x/(2*(z+0.5/tan(fov/2))*tan(fov/2)); y:=y/(2*(z+0.5/tan(fov/2))*tan(fov/2)); projection[i].x:=x*clwidth*hw+halfWidth; projection[i].y:=y*clheight+halfHeight; end; end;
procedure tform1.setrotatexmatrix(var m:TMatrix; angle:single); begin m._11:=1; m._12:=0; m._13:=0; m._14:=0; m._21:=0; m._22:=cos(angle); m._23:=sin(angle); m._24:=0; m._31:=0; m._32:=-sin(angle); m._33:=cos(angle); m._34:=0; m._41:=0; m._42:=0; m._43:=0; m._44:=1; end;
procedure tform1.setrotateymatrix(var m:TMatrix; angle:single); begin m._11:=cos(angle); m._12:=0; m._13:=-sin(angle); m._14:=0; m._21:=0; m._22:=1; m._23:=0; m._24:=0; m._31:=sin(angle); m._32:=0; m._33:=cos(angle); m._34:=0; m._41:=0; m._42:=0; m._43:=0; m._44:=1; end;
procedure tform1.setrotatezmatrix(var m:TMatrix; angle:single); begin m._11:=cos(angle); m._12:=sin(angle); m._13:=0; m._14:=0; m._21:=-sin(angle); m._22:=cos(angle); m._23:=0; m._24:=0; m._31:=0; m._32:=0; m._33:=1; m._34:=0; m._41:=0; m._42:=0; m._43:=0; m._44:=1; end;
procedure tform1.settranslatematrix(var m:TMatrix; x,y,z:single); begin m._11:=1; m._12:=0; m._13:=0; m._14:=0; m._21:=0; m._22:=1; m._23:=0; m._24:=0; m._31:=0; m._32:=0; m._33:=1; m._34:=0; m._41:=x; m._42:=y; m._43:=z; m._44:=1; end;
procedure tform1.addcube; begin cube:=tmesh.Create; cube.cx:=0; cube.cy:=0; cube.cz:=0; setlength(cube.triangles,12);
cube.triangles[0][1].x:=-0.5; cube.triangles[0][1].y:=-0.5; cube.triangles[0][1].z:=0.5; cube.triangles[0][2].x:=-0.5; cube.triangles[0][2].y:=0.5; cube.triangles[0][2].z:=0.5; cube.triangles[0][3].x:=0.5; cube.triangles[0][3].y:=0.5; cube.triangles[0][3].z:=0.5;
cube.triangles[1][1].x:=-0.5; cube.triangles[1][1].y:=-0.5; cube.triangles[1][1].z:=0.5; cube.triangles[1][2].x:=0.5; cube.triangles[1][2].y:=0.5; cube.triangles[1][2].z:=0.5; cube.triangles[1][3].x:=0.5; cube.triangles[1][3].y:=-0.5; cube.triangles[1][3].z:=0.5;
cube.triangles[2][1].x:=0.5; cube.triangles[2][1].y:=-0.5; cube.triangles[2][1].z:=-0.5; cube.triangles[2][2].x:=0.5; cube.triangles[2][2].y:=0.5; cube.triangles[2][2].z:=-0.5; cube.triangles[2][3].x:=-0.5; cube.triangles[2][3].y:=0.5; cube.triangles[2][3].z:=-0.5;
cube.triangles[3][1].x:=0.5; cube.triangles[3][1].y:=-0.5; cube.triangles[3][1].z:=-0.5; cube.triangles[3][2].x:=-0.5; cube.triangles[3][2].y:=0.5; cube.triangles[3][2].z:=-0.5; cube.triangles[3][3].x:=-0.5; cube.triangles[3][3].y:=-0.5; cube.triangles[3][3].z:=-0.5;
cube.triangles[4][1].x:=0.5; cube.triangles[4][1].y:=-0.5; cube.triangles[4][1].z:=-0.5; cube.triangles[4][2].x:=0.5; cube.triangles[4][2].y:=0.5; cube.triangles[4][2].z:=-0.5; cube.triangles[4][3].x:=0.5; cube.triangles[4][3].y:=0.5; cube.triangles[4][3].z:=0.5;
cube.triangles[5][1].x:=0.5; cube.triangles[5][1].y:=-0.5; cube.triangles[5][1].z:=-0.5; cube.triangles[5][2].x:=0.5; cube.triangles[5][2].y:=0.5; cube.triangles[5][2].z:=0.5; cube.triangles[5][3].x:=0.5; cube.triangles[5][3].y:=-0.5; cube.triangles[5][3].z:=0.5;
cube.triangles[6][1].x:=-0.5; cube.triangles[6][1].y:=-0.5; cube.triangles[6][1].z:=0.5; cube.triangles[6][2].x:=-0.5; cube.triangles[6][2].y:=0.5; cube.triangles[6][2].z:=0.5; cube.triangles[6][3].x:=-0.5; cube.triangles[6][3].y:=0.5; cube.triangles[6][3].z:=-0.5;
cube.triangles[7][1].x:=-0.5; cube.triangles[7][1].y:=-0.5; cube.triangles[7][1].z:=0.5; cube.triangles[7][2].x:=-0.5; cube.triangles[7][2].y:=0.5; cube.triangles[7][2].z:=-0.5; cube.triangles[7][3].x:=-0.5; cube.triangles[7][3].y:=-0.5; cube.triangles[7][3].z:=-0.5;
cube.triangles[8][1].x:=-0.5; cube.triangles[8][1].y:=0.5; cube.triangles[8][1].z:=-0.5; cube.triangles[8][2].x:=-0.5; cube.triangles[8][2].y:=0.5; cube.triangles[8][2].z:=0.5; cube.triangles[8][3].x:=0.5; cube.triangles[8][3].y:=0.5; cube.triangles[8][3].z:=0.5;
cube.triangles[9][1].x:=-0.5; cube.triangles[9][1].y:=0.5; cube.triangles[9][1].z:=-0.5; cube.triangles[9][2].x:=0.5; cube.triangles[9][2].y:=0.5; cube.triangles[9][2].z:=0.5; cube.triangles[9][3].x:=0.5; cube.triangles[9][3].y:=0.5; cube.triangles[9][3].z:=-0.5;
cube.triangles[10][1].x:=0.5; cube.triangles[10][1].y:=-0.5; cube.triangles[10][1].z:=-0.5; cube.triangles[10][2].x:=0.5; cube.triangles[10][2].y:=-0.5; cube.triangles[10][2].z:=0.5; cube.triangles[10][3].x:=-0.5; cube.triangles[10][3].y:=-0.5; cube.triangles[10][3].z:=0.5;
cube.triangles[11][1].x:=0.5; cube.triangles[11][1].y:=-0.5; cube.triangles[11][1].z:=-0.5; cube.triangles[11][2].x:=-0.5; cube.triangles[11][2].y:=-0.5; cube.triangles[11][2].z:=0.5; cube.triangles[11][3].x:=-0.5; cube.triangles[11][3].y:=-0.5; cube.triangles[11][3].z:=-0.5; end;
procedure tform1.drawtriangle(t:TTriangle); var v1,v2:tpoint3d; pp:array of tpoint; begin v1.x:=pviewto.x-pview.x; v1.y:=pviewto.y-pview.y; v1.z:=pviewto.z-pview.z; v2:=norm(t[1],t[2],t[3]); case cullmode of 0:begin end; 1:begin if v1.x*v2.x+v1.y*v2.y+v1.z*v2.z<0 then begin exit; end; end; 2:begin end; end; case fillmode of 0:begin t:=projection(t,form1.ClientWidth,form1.ClientHeight); setlength(pp,3); pp[0].X:=round(t[1].x); pp[0].Y:=round(t[1].y); pp[1].X:=round(t[2].x); pp[1].Y:=round(t[2].y); pp[2].X:=round(t[3].x); pp[2].Y:=round(t[3].y); backbitmap.Canvas.Brush.Color:=curbrcl; backbitmap.Canvas.pen.color:=curbrcl; backbitmap.Canvas.Polygon(pp); {backbitmap.Canvas.MoveTo(round(t[1].x),round(t[1].y)); backbitmap.Canvas.LineTo(round(t[2].x),round(t[2].y)); backbitmap.Canvas.LineTo(round(t[3].x),round(t[3].y)); backbitmap.Canvas.LineTo(round(t[1].x),round(t[1].y)); } end; 1:begin t:=projection(t,form1.ClientWidth,form1.ClientHeight); backbitmap.Canvas.pen.color:=curcl; backbitmap.Canvas.MoveTo(round(t[1].x),round(t[1].y)); backbitmap.Canvas.LineTo(round(t[2].x),round(t[2].y)); backbitmap.Canvas.LineTo(round(t[3].x),round(t[3].y)); backbitmap.Canvas.LineTo(round(t[1].x),round(t[1].y)); end; 2:begin end; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin backbitmap:=tbitmap.Create; backbitmap.Width:=screen.Width; backbitmap.Height:=screen.height; fillmode:=1; curbrcl:=clyellow; cullmode:=0; curcl:=clgray; pview.x:=0; pview.y:=0.5; pview.z:=4; pviewto.x:=0; pviewto.y:=0; pviewto.z:=0; addcube; fov:=1; hw:=clientheight/clientwidth; end;
procedure TForm1.Timer1Timer(Sender: TObject); begin render; cube.rotate(0,0.1,0); end;
procedure tform1.render; var rect:trect; i:integer; begin hw:=clientheight/clientwidth; setrect(rect,0,0,clientwidth,clientheight); backbitmap.Canvas.Brush.Color:=clbckgr; backbitmap.Canvas.FillRect(rect); if cube<>nil then begin for i:=0 to high(cube.triangles) do begin drawtriangle(cube.triangles[i]); end; end; form1.Canvas.CopyRect(rect,backbitmap.Canvas,rect); end;
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin if key=' ' then begin if fillmode=0 then fillmode:=1 else fillmode:=0; end; end;
end.
|
ЗЫ Практической ценности пример ИМХО не представляет, лучше изучать dx или opengl. ЗЗЫ Создание вращающегося куба и написание серьезного 3d приложения (игры) это две ОГРОМНЫЕ разницы. ЗЗЗЫ А может это вам в школе по предмету "Информатика" задали? Тогда нечего и огород городить. Там все гораздо проще. |
Здраствуйте. Поидеи все вроде номально. НО вот пробелемма что код нехочет работать с Делфи 7. Пробемма соостоит в том что происхотит перегрузка памети т.е. код выходит за пределы выделенной помети. Пока не могу понять где. Увожаемая "Чупокабра" немогли бы подсказать где может произойти перегрузка. |