3D Rotating Cube lazarus / 39-Graphics ---------------------------------------------------------------------- Gigatron · 2025-04-07 13:03 Hi, Here is a simple BGRA wireframe 3d rotating cube, you can play with this to improve it; All rotation forumula are from WWW . Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes;  const  CubeSize = 600; type  TVec3 = record    x, y, z: Single;  end;    { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private   public   end; var  Form1: TForm1;  AngleX, AngleY, AngleZ: Single;  CubePoints: array[0..7] of TVec3 = (    (x:-1; y:-1; z:-1), (x:1;  y:-1; z:-1),    (x:1; y:1; z:-1),   (x:-1; y:1;  z:-1),    (x:-1; y:-1; z:1),  (x:1;  y:-1; z:1),    (x:1; y:1; z:1),    (x:-1; y:1;  z:1)  ); implementation {$R *.lfm} procedure DrawCube(Bitmap: TBGRABitmap; AngleX, AngleY, AngleZ: Single);const  Edges: array[0..11, 0..1] of Integer = (    (0,1), (1,2), (2,3), (3,0),    (4,5), (5,6), (6,7), (7,4),    (0,4), (1,5), (2,6), (3,7)  );var  i: Integer;  Rotated: array[0..7] of TVec3;  Projected: array[0..7] of TPoint;  cx, cy: Integer;  x1, y1, z1: Single;  p1, p2: TPoint;begin  cx := Bitmap.Width div 2;  cy := Bitmap.Height div 2;   for i := 0 to 7 do  begin    x1 := CubePoints[i].x;    y1 := CubePoints[i].y;    z1 := CubePoints[i].z;     // Rotation X    Rotated[i].y := y1 * cos(AngleX) - z1 * sin(AngleX);    Rotated[i].z := y1 * sin(AngleX) + z1 * cos(AngleX);  y1 := Rotated[i].y;    z1 := Rotated[i].z;     // Rotation Y    Rotated[i].x := x1 * cos(AngleY) + z1 * sin(AngleY);    Rotated[i].z := -x1 * sin(AngleY) + z1 * cos(AngleY);    x1 := Rotated[i].x;    z1 := Rotated[i].z;     // Rotation Z    Rotated[i].x := x1 * cos(AngleZ) - y1 * sin(AngleZ);    Rotated[i].y := x1 * sin(AngleZ) + y1 * cos(AngleZ);     // Projection    Projected[i].X := Round(cx + (Rotated[i].x * CubeSize) / (Rotated[i].z + 5));    Projected[i].Y := Round(cy + (Rotated[i].y * CubeSize) / (Rotated[i].z + 5));  end;   for i := 0 to 11 do  begin    p1 := Projected[Edges[i][0]];    p2 := Projected[Edges[i][1]];   // Bitmap.DrawLineAntialias(p1.X, p1.Y, p2.X, p2.Y, BGRA(255, 255, 255), 6);    Bitmap.DrawLine(p1.X, p1.Y, p2.X, p2.Y, BGRA(255, 255, 255),false);    Bitmap.DrawLine(4+p2.X, 4+p2.Y, p1.X+4, p1.Y+4, BGRA(255, 0, 0),false);  end;end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Timer1.Enabled := True;  Timer1.Interval := 15*6; // Amiga500 68000 vector rotation speed in 1986 !end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);begin  DrawCube(Bitmap, AngleX, AngleY, AngleZ);end; procedure TForm1.Timer1Timer(Sender: TObject);begin  AngleX += 0.020;  AngleY += 0.030;  AngleZ += 0.010;  BGRAVirtualScreen1.RedrawBitmap;end; end. ---------------------------------------------------------------------- TBMan · 2025-04-07 16:22 I'm not a math wiz so before I start tinkering with your code, are the angles in radians? ---------------------------------------------------------------------- Handoko · 2025-04-07 16:40 Quote from: TBMan on April 07, 2025, 06:22:00 pmI'm not a math wiz so before I start tinkering with your code, are the angles in radians? Radians. The DrawCube procedure uses sin and cos functions, and their parameters are in radians: https://www.freepascal.org/docs-html/rtl/system/sin.html ---------------------------------------------------------------------- TBMan · 2025-04-07 19:13 Quote from: Handoko on April 07, 2025, 06:40:15 pmQuote from: TBMan on April 07, 2025, 06:22:00 pmI'm not a math wiz so before I start tinkering with your code, are the angles in radians? Radians. The DrawCube procedure uses sin and cos functions, and their parameters are in radians: https://www.freepascal.org/docs-html/rtl/system/sin.html I knew that. LOL. ---------------------------------------------------------------------- Gigatron · 2025-04-07 19:16 Quote from: Handoko on April 07, 2025, 06:40:15 pmQuote from: TBMan on April 07, 2025, 06:22:00 pmI'm not a math wiz so before I start tinkering with your code, are the angles in radians? Radians. The DrawCube procedure uses sin and cos functions, and their parameters are in radians: https://www.freepascal.org/docs-html/rtl/system/sin.html Thank you @Handoko for the answer; ---------------------------------------------------------------------- d2010 · 2025-04-10 01:23 Quote from: TBMan on April 07, 2025, 06:22:00 pmI'm not a math wiz so before I start tinkering with your code, are the angles in radians? Here is My-Demo. ---------------------------------------------------------------------- TBMan · 2025-04-10 02:11 Here's my spin on this (pun intended) with ptcgraph. Check the initgraph to make sure its compatible with your PC. 2 video pages are being used. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program cube1;uses windows, ptcgraph,ptccrt,math;const  CubeSize = 600; type  TVec3 = record    x, y, z: Single;  end;   tpoint = record    x,y:single;  end;   VideoPages = (Page0, Page1); var gdriver,gmode:smallint; Page: VideoPages = Page0; AngleX, AngleY, AngleZ: Single;  CubePoints: array[0..7] of TVec3 = (    (x:-1; y:-1; z:-1), (x:1;  y:-1; z:-1),    (x:1; y:1; z:-1),   (x:-1; y:1;  z:-1),    (x:-1; y:-1; z:1),  (x:1;  y:-1; z:1),    (x:1; y:1; z:1),    (x:-1; y:1;  z:1)  );  procedure Nextactivepage;  begin    if page = page0 then page := page1    else      page := page0;      SetactivePage(Ord(Page));  end; procedure NextVisualPage;  begin    SetVisualpage(Ord(Page));  end; procedure frametick(frames:integer);var  scount,ecount:qword;begin   scount := GetTickCount64;  repeat    ecount := GetTickCount64;  until ecount > (scount+(64*15)/frames);end;   procedure DrawCube(AngleX, AngleY, AngleZ: Single);const  Edges: array[0..11, 0..1] of Integer = (    (0,1), (1,2), (2,3), (3,0),    (4,5), (5,6), (6,7), (7,4),    (0,4), (1,5), (2,6), (3,7)  );var  i: Integer;  Rotated: array[0..7] of TVec3;  Projected: array[0..7] of TPoint;  cx, cy: Integer;  x1, y1, z1: Single;  p1, p2: TPoint;begin  cx := 210;  cy := 210;   for i := 0 to 7 do  begin    x1 := CubePoints[i].x;    y1 := CubePoints[i].y;    z1 := CubePoints[i].z;     // Rotation X    Rotated[i].y := y1 * cos(AngleX) - z1 * sin(AngleX);    Rotated[i].z := y1 * sin(AngleX) + z1 * cos(AngleX);    y1 := Rotated[i].y;    z1 := Rotated[i].z;     // Rotation Y    Rotated[i].x := x1 * cos(AngleY) + z1 * sin(AngleY);    Rotated[i].z := -x1 * sin(AngleY) + z1 * cos(AngleY);    x1 := Rotated[i].x;    z1 := Rotated[i].z;     // Rotation Z    Rotated[i].x := x1 * cos(AngleZ) - y1 * sin(AngleZ);    Rotated[i].y := x1 * sin(AngleZ) + y1 * cos(AngleZ);     // Projection    Projected[i].X := Round(cx + (Rotated[i].x * CubeSize) / (Rotated[i].z + 5));    Projected[i].Y := Round(cy + (Rotated[i].y * CubeSize) / (Rotated[i].z + 5));  end;   for i := 0 to 11 do  begin    p1 := Projected[Edges[i][0]];    p2 := Projected[Edges[i][1]];     Line(round(p1.X),round( p1.Y), round(p2.X), round(p2.Y));//    Line(round(p2.X)+4, round(p2.Y)+4, round(p1.X)+4,round( p1.Y)+4);  end;end; var  j:integer;  s:single;   Ydegrees,  xdegrees,zdegrees:integer;begin gdriver := vesa; Gmode := installusermode(800, 600, 256, 2, 8000, 6000); WindowTitle := '3d Cube'; initgraph(gdriver, gmode, ''); setviewport(100,50,600,500,true);  xdegrees := 90;  zdegrees := 100;  ydegrees := 45; repeat    nextactivepage;    clearviewport;    DrawCube(angleX, AngleY, angleZ);    nextvisualpage;    inc(zdegrees);    if zdegrees >360 then zdegrees := 1;    inc(xdegrees);    if xdegrees > 360 then xdegrees := 1;    dec(ydegrees);    if ydegrees <0 then ydegrees := 359;    angleX := degTorad(xdegrees);    angleZ := degToRad(Zdegrees);    angley := degtorad(ydegrees);    frametick(960);until keypressed; end. ---------------------------------------------------------------------- Gigatron · 2025-04-10 14:27 @d2010 ; @TBMan Nice and perfect job ; ---------------------------------------------------------------------- TBMan · 2025-04-10 16:35 Quote from: Gigatron on April 10, 2025, 04:27:03 pm@d2010 ; @TBMan Nice and perfect job ; Thanks. The odds of me learning the ins and outs of 3d programming are slim to none due to a no trig or calculus background, but I'd like to learn what to do to construct 3 objects manually as you did in your code. Do you have any recommendations short of college courses?  It looks like the Edges array is the vertices(distances/steps from the centerx and centery?) and the CubePoints seem to be some sort of 2d to 3d translator table. ---------------------------------------------------------------------- Gigatron · 2025-04-10 17:03 Hi; CubePoints defines the 8 corners (vertices) of a cube centered around (0,0,0). Each point is 3D (x, y, z) and goes from -1 to 1. Simple rotation formulas on each axis (X, Y, Z). You can find the formula on www like me This website help you : https://www.instructables.com/Rotating-Cube- Using-JavaScript/ After rotation perspective projection of  each 3D point into 2D using this line: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // Projection    Projected[i].X := Round(cx + (Rotated[i].x * CubeSize) / (Rotated[i].z + 5));    Projected[i].Y := Round(cy + (Rotated[i].y * CubeSize) / (Rotated[i].z + 5)); The (z + 5)  (to avoid dividing by zero). End part is  drawing the edges of the cube using the Edges array, which just connects the right points. I learn everything I can by reading documents on the www. It takes a lot of time, no TV but learning and making mistakes!! Mistakes are the key to programming The mathematical formulas for projection and rotations are available on the net. Hope this will help; Regards Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes, LCLType;  const  CubeSize = 600; type  TVec3 = record    x, y, z: Single;  end;    { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);    procedure Timer1Timer(Sender: TObject);  private   public   end; var  Form1: TForm1;  AngleX, AngleY, AngleZ: Single;  CubePoints: array[0..7] of TVec3 = (    (x:-1; y:-1; z:-1), (x:1;  y:-1; z:-1),  (x:1; y:1; z:-1),   (x:-1; y:1;  z:-1),    (x:-1; y:-1; z:1),  (x:1;  y:-1; z:1),    (x:1; y:1; z:1),    (x:-1; y:1;  z:1)  ); implementation {$R *.lfm} procedure DrawCube(Bitmap: TBGRABitmap; AngleX, AngleY, AngleZ: Single);const  Edges: array[0..11, 0..1] of Integer = (    (0,1), (1,2), (2,3), (3,0),    (4,5), (5,6), (6,7), (7,4),    (0,4), (1,5), (2,6), (3,7)  );var  i: Integer;  Rotated: array[0..7] of TVec3;  Projected: array[0..7] of TPoint;  cx, cy: Integer;  x1, y1, z1: Single;  p1, p2: TPoint; begin  cx := Bitmap.Width div 2;  cy := Bitmap.Height div 2;   for i := 0 to 7 do  begin    x1 := CubePoints[i].x;    y1 := CubePoints[i].y;    z1 := CubePoints[i].z;     // Rotation X    Rotated[i].y := y1 * cos(AngleX) - z1 * sin(AngleX);    Rotated[i].z := y1 * sin(AngleX) + z1 * cos(AngleX);    y1 := Rotated[i].y;    z1 := Rotated[i].z;     // Rotation Y       Rotated[i].x := x1 * cos(AngleY) + z1 * sin(AngleY);    Rotated[i].z := -x1 * sin(AngleY) + z1 * cos(AngleY);    x1 := Rotated[i].x;    z1 := Rotated[i].z;     // Rotation Z    Rotated[i].x := x1 * cos(AngleZ) - y1 * sin(AngleZ);    Rotated[i].y := x1 * sin(AngleZ) + y1 * cos(AngleZ);     // Projection    Projected[i].X := Round(cx + (Rotated[i].x * CubeSize) / (Rotated[i].z + 5));    Projected[i].Y := Round(cy + (Rotated[i].y * CubeSize) / (Rotated[i].z + 5));  end;   for i := 0 to 11 do  begin    p1 := Projected[Edges[i][0]];    p2 := Projected[Edges[i][1]];   // Bitmap.DrawLineAntialias(p1.X, p1.Y, p2.X, p2.Y, BGRA(255, 255, 255), 6);    Bitmap.DrawLine(p1.X, p1.Y, p2.X, p2.Y, BGRA(255, 255, 255),false);    Bitmap.DrawLine(4+p2.X, 4+p2.Y, p1.X+4, p1.Y+4, BGRA(255, 0, 0),false);  end;end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Timer1.Enabled := True;  Timer1.Interval := 15*2; // Amiga500 68000 vector rotation speed in 1986 !end; procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState  );begin  case Key of    VK_LEFT:  AngleY -= 0.03;    VK_RIGHT: AngleY += 0.03;    VK_UP:    AngleX -= 0.03;    VK_DOWN:  AngleX += 0.03;  end;  BGRAVirtualScreen1.RedrawBitmap; end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);begin  DrawCube(Bitmap, AngleX, AngleY, AngleZ);end; procedure TForm1.Timer1Timer(Sender: TObject);begin  //AngleX += 0.020;  //AngleY += 0.030;  AngleZ += 0.030;  BGRAVirtualScreen1.RedrawBitmap;end; end. ---------------------------------------------------------------------- TBMan · 2025-04-10 17:23 Thank you.