Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Программирование игр, графики и искусственного интеллекта > создание куба вращающегося


Автор: AVRUDOI 22.9.2007, 12:58
Здраствуйте. Есть желание написать программу вращающегося куба по оси Y. Сам немогу. Нехвотает знаний если у каго есть желание помочь? Хочу написать на Делфи 7.

Автор: Чупакабро 24.9.2007, 15:21
А кубег какой должен быть: проволочный, со сплошной закраской, с текстурой?
И как вы его хотите рисовать: с помощью методов tcanvas или Directx или OpenGL?

Автор: AVRUDOI 27.9.2007, 12:08
Скорея всего с помощью методов tconves. Мне больше по душе этот метод. Он позволяет прочуствовать на линиях и точка красоту 3D. А потом хоть квейк пиши.smile текстура ненужна пока. Просто куб с ребрами.

Автор: Чупакабро 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 приложения (игры) это две ОГРОМНЫЕ разницы.
ЗЗЗЫ А может это вам в школе по предмету "Информатика" задали?smile Тогда нечего и огород городить. Там все гораздо проще.

Автор: Rickert 28.9.2007, 07:41
Канвас красивее OGL & D3D  smile 
Мда...
И вообще, тема должна быть в Дельфи, в таком случае.
[...уходит ворча...]

Автор: fse 28.9.2007, 12:21
Всем привет!
AVRUDOI, похвально стремление докопаться до сути 3д, правда на канвасе мало кто что рисует трёхмерного;)
Предложу и свой вариант кода.
Чупакабро написал, видимо, рабочий код, но для новичка в этом деле сложный. По крайней мере разбираться можно долгоsmile


Код

type
  TPoint3D = record
    X, Y, Z: Float;
    {$IFDEF USEPOINTDATA}
    Data: TUserData;
    {$ENDIF}
  end;

  TAngles = TPoint3D;
...

//Процедура поворота точки на 3 угла относительно начала координат в последовательности поворотов OX>OY>OZ:
function PointRotate(Angles: TAngles; Pt: TPoint3D): TPoint3D; overload;
begin
  Result:=PointRotateOX(Angles.X, Pt);
  Result:=PointRotateOY(Angles.Y, Result);
  Result:=PointRotateOZ(Angles.Z, Result);
end;

//Отдельные повороты:

function PointRotateOX(Angle: Float; Pt: TPoint3D): TPoint3D;
begin
  Angle:=DegToRad(Angle);
  Result.X:=Pt.X;
  Result.Y:=Pt.Y*Cos(Angle)-Pt.Z*Sin(Angle);
  Result.Z:=Pt.Y*Sin(Angle)+Pt.Z*Cos(Angle);
end;

function PointRotateOY(Angle: Float; Pt: TPoint3D): TPoint3D;
begin
  Angle:=DegToRad(Angle);
  Result.X:=Pt.X*Cos(Angle)+Pt.Z*Sin(Angle);
  Result.Z:=Pt.Z*Cos(Angle)-Pt.X*Sin(Angle);
  Result.Y:=Pt.Y;
end;

function PointRotateOZ(Angle: Float; Pt: TPoint3D): TPoint3D;
begin
  Angle:=DegToRad(Angle);
  Result.X:=Pt.X*Cos(Angle)-Pt.Y*Sin(Angle);
  Result.Y:=Pt.X*Sin(Angle)+Pt.Y*Cos(Angle);
  Result.Z:=Pt.Z;
end;


Вся дальнейшая работа сводится к повороту на нужные углы соответствующих вершин куба. И рисовать грани между соответствующими в кубе точками.

Могу посоветовать:

Если пересчитывается много точек, то создай таблицу sin(ox, oy, oz) и cos(ox, oy, oz), а не вычисляй их постоянно.

А реально, эти формулы получаются как раз из перемножения матриц поворота на вектор, то, что сделано у Чупакабро.
Это касательно поворотов.
Перспективу можно строить при помощи косоугольных систем координат.
Если с заливкой рисовать, то после поворотов всех точек нужно делать тест глубины (грубо говоря, сортировка точек по удалённости от проекционной плоскости).

Советую почитать:
Аналитическая геометрия (вышка)
Компьютерная графика (статьи в инете)

Удачи;)

Автор: Чупакабро 28.9.2007, 18:19
Цитата(fse @  28.9.2007,  12:21 Найти цитируемый пост)
Чупакабро написал, видимо, рабочий код, но для новичка в этом деле сложный

А вы пробовали запускать? (заискивающе улыбается)
Цитата(fse @  28.9.2007,  12:21 Найти цитируемый пост)
рабочий код, но для новичка в этом деле сложный. По крайней мере разбираться можно долго

Дык я скоро комментарии подготовлю. Хотя ведь и не факт, что человеку реально нужно разобраться.
Я сам-то там половину методом научного тыка написал, например, нужно ли перемножать матрицу сдвига на матрицу поворота или в обратном порядке, чтобы получить нормальную картинку.
Ну а вообще вращающийся куб иногда рисуют даже в школе на информатике, хотя к 3d это имеет весьма отдаленное отношение.
Зато код получается простой, это да.
Да, кстати... fse, у вас получается, что куб вращается вокруг начала координат. В принципе, автору темы наверно это и нужно, но если реализовывать поворот вокруг произвольной оси, то код усложняется. То же самое с перспективой. Это как раз-таки задачка посложнее, чем само по себе вращение куба. А если сюда же добавить эмуляцию пиксельных шейдеров... smile

Цитата(Rickert @  28.9.2007,  07:41 Найти цитируемый пост)
И вообще, тема должна быть в Дельфи, в таком случае.

Нет нет. Все правильно это именно программирование графики, а перевести все это на C, например, дело недолгое, т.к. здесь одна математика.

Автор: fse 29.9.2007, 12:12
Чупакабро, оно так всё, если делать по науке - то конечно, матрицы. Хотя на уровне формул тоже нужно понимать.
Цитата

если реализовывать поворот вокруг произвольной оси, то код усложняется

Не согласен, вот как будет выглядеть процедура поворота...

Как было

Код

function PointRotate(Angles: TAngles; Pt: TPoint3D): TPoint3D; overload;
begin
  Result:=PointRotateOX(Angles.X, Pt);
  Result:=PointRotateOY(Angles.Y, Result);
  Result:=PointRotateOZ(Angles.Z, Result);
end;


Как стало

Код

function PointRotate(Angles: TAngles; Pt: TPoint3D; RotCenter: TPoint3D): TPoint3D; overload;
begin
  Pt.X := Pt.X - RotCenter.X;
  Pt.Y := Pt.Y - RotCenter.Y;
  Pt.Z := Pt.Z - RotCenter.Z;

  Result:=PointRotateOX(Angles.X, Pt);
  Result:=PointRotateOY(Angles.Y, Result);
  Result:=PointRotateOZ(Angles.Z, Result);

  Result.X := Result.X + RotCenter.X;
  Result.Y := Result.Y + RotCenter.Y;
  Result.Z := Result.Z + RotCenter.Z;
end;


Т.е. мы просто перевели точку к другому началу координат простым перемещением, повернули точку вокруг нового начала координат, потом переместили обратно!smile

На самом деле, в тех задачах, что сейчас у меня, удобно работать именно не с матрицами, а с формулами, поэтому я пишу именно так.
При этом, вместо матрицы смещения используется просто суммирование координат. Масштабирование: умножение координат на коэффициенты.
При таком подходе существенно возрастает скорость, т.к. мы отходим от не столь быстрой операции умножения матриц.

Цитата

То же самое с перспективой


Опять же, спорный вопрос ;)

Перспектива - это просто перенос вектора в косоугольную систему координат.
Если есть оси ox, oy, oz (единичные вектора) в новой косоугольной СК; x, y, z - координаты вектора; их нужно перевести в эту новую СК. При этом нужно просто найти проекции вектора каждую ось новой СК. Эти проекции численно будут являться координатами в перспективе. Находится тремя операциями скалярного произведения, что весьма быстроsmile

Вот, это касательно математики. Хотя, отлично понимаю, иногда этим нечего забивать голову, можно оперировать просто шаблонными матрицами.
Это выгодно может быть по производительности только в случае, когда над точкой производятся очень сложные модификации. Вроде большой серии поворотов, перемещений, масштабирования и т.д. При этом, можно не умножать вектор на каждую матрицу, а просчитать сначала матрицу всех произведений матриц модификации. А потом умножать каждую точку на кэшированную матрицу.

"добавить эмуляцию пиксельных шейдеров" - ууух, я и словей таких не знаю smile

Цитата

перемножать матрицу сдвига на матрицу поворота или в обратном порядке


Хм, а это всё зависет от нужного нам результата ;)

Автор: Чупакабро 29.9.2007, 15:29
Цитата(fse @  29.9.2007,  12:12 Найти цитируемый пост)
Т.е. мы просто перевели точку к другому началу координат простым перемещением, повернули точку вокруг нового начала координат, потом переместили обратно!

Дык. Это я и имел в виду под усложнением кода) У вас получилось на 6 строчек больше smile

Цитата(fse @  29.9.2007,  12:12 Найти цитируемый пост)
"добавить эмуляцию пиксельных шейдеров" - ууух, я и словей таких не знаю 

Ну, может я не так выразился. Имелось в виду выполнение операций над пикселями (как растерезация, так и всякие эффекты) центральным процессором, а не GPU.

Автор: AVRUDOI 18.10.2007, 14:54
Цитата(Чупакабро @ 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 приложения (игры) это две ОГРОМНЫЕ разницы.
ЗЗЗЫ А может это вам в школе по предмету "Информатика" задали?smile Тогда нечего и огород городить. Там все гораздо проще.

Здраствуйте. Поидеи все вроде номально. НО вот пробелемма что код нехочет работать с Делфи 7. Пробемма соостоит в том что происхотит  перегрузка памети т.е. код выходит за пределы выделенной помети. Пока не могу понять где. Увожаемая "Чупокабра" немогли бы подсказать где может произойти перегрузка. smile 

Автор: Чупакабро 21.10.2008, 19:47
Цитата(AVRUDOI @  18.10.2007,  14:54 Найти цитируемый пост)
Увожаемая "Чупокабра

Сильно сказано!
Не понял: что значит "код твыходит за пределы выделенной памяти"?
А в других версиях Delphi работает?
У меня в седьмой все нормально...

Автор: fse 21.10.2008, 22:36
Всем привет!

Чупакабро, код запустил, симпотично smile)
Правда сложные многоугольники без теста глубины чудить будут ужасно. Я когда-то даже поддержал в проекте GDI-3Д своего загрузку моделей из максовских файлов и произвольное освещение. Как положено, цвет считался по проекции на вектор нормали полигона! Без теста глубины получилось плачевно smile)) А тест глубины - довольно сложный алгоритм, так что DOOM4 не получился smile

А у AVRUDOI пологаю что знаю в чём проблема!
По шагам, что делать в D7:
- Создаёшь новый проект
- Копипастишь напрямую
- Ctrl-F9
Она спросит "удалить ли описанный Timer1", говоришь да
Помещаешь его на форму
Создаёшь из среды для таймера OnTimer
Для формы OnCreate и OnKeyPress.

И тогда всё заработает. Иначе программа обращается к объектам backbitmap и cube, которые не создаются, т.к. не вызывается OnCreate. И тогда аксес невалялся  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)