DGL
https://delphigl.com/forum/

Bezier Curve - how to reference all points in the curve?
https://delphigl.com/forum/viewtopic.php?f=19&t=6831
Seite 1 von 1

Autor:  dpm_dpmartin [ So Aug 19, 2007 13:44 ]
Betreff des Beitrags:  Bezier Curve - how to reference all points in the curve?

Hello,

I had the idea that certain UI components of my project could 'fly away' when I decided to move to another screen. Sure, I could just send them along a straight +X or +Y line until they disappeared from the screen, but I thought that it would be very nice looking to have them follow a flight plan that was described by a curve - maybe even a random curve - but a curve anyway.

So, I've started educating myself about OpenGL and calculating and drawing Bezier curves. Here is the entirety of my code - it is pretty straightforward and will run easily (just a TForm, with a client-aligned TPanel and a TTimer). This code calculates a curve via four control points and is able to display it on the screen - as well as displaying each point on the curve and the control points connected via a thin red line.

What I'm curious about is the code at lines 137 and 148 - the lines that use glEvalCoord1f to apparently draw out a GL_POINT (or a part of a LINE_LOOP) by referencing some values it seems to have pre-calculated with the call to glMap1f earlier - or is calculating on the fly.

While calculating my curve, I would prefer to be able pre-calculate and store the X, Y and Z of each point on the curve in an array - so I can look them up later - glEvalCoord1f is obviously pulling out the correct details - but 1) I don't really know where it is getting them from and 2) I don't know if I can access them in code so I can use glVertex3f to display things.

Is there a way of 1) setting up my control points, 2) setting a number of segments (level of detail), 3) calculating the curve according to the control points and number of segments (level of detail) I want and 4) storing the values of each point on the curve in X, Y and Z format in an array, so that I can then 5) reference them so my moving objects can follow some kind of flight plan?

glEvalCoord1f is great in that it obviously returns or uses some form of X, Y and Z values for the LINE_LOOP and GL_POINTs loop it is being used in - but it is not a function, so I don't know how to get my X, Y and Z values from it... does that make sense?

Code:
  1. unit Main;
  2.  
  3. interface
  4.  
  5. uses
  6.   OpenGL, Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, ExtCtrls;
  7.  
  8. const
  9.   LevelOfDetail = 20;
  10.   NumberOfControlPoints = 4;
  11.  
  12. type
  13.   TPoint = record
  14.     X, Y, Z : GLFloat;
  15.   end;
  16.  
  17.   TfrmMain = class(TForm)
  18.     Timer1 : TTimer;
  19.     pOGL : TPanel;
  20.     procedure FormCreate (Sender : TObject);
  21.     procedure Timer1Timer (Sender : TObject);
  22.   private
  23.     procedure Draw;
  24.   public
  25.   end;
  26.  
  27. var
  28.   frmMain : TfrmMain;
  29.   ControlPoints : array[0..NumberOfControlPoints - 1] of TPoint;
  30.   Colours : array[0..LevelOfDetail] of array[0..2] of GLFloat;
  31.   Rotation : GLFloat = 0;
  32.  
  33.  
  34. implementation
  35.  
  36.  
  37. {$R *.DFM}
  38.  
  39.  
  40. procedure SetupPixelFormat ( DC : HDC
  41.                            );
  42. const
  43.    PFD : TPIXELFORMATDESCRIPTOR = (
  44.          nSize : SizeOf (TPIXELFORMATDESCRIPTOR); nVersion : 1;
  45.          dwFlags : PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER;
  46.          iPixelType : PFD_TYPE_RGBA;
  47.          cColorBits : 24; cRedBits : 0; cRedShift : 0; cGreenBits : 0; cGreenShift : 0;
  48.          cBlueBits : 0; cBlueShift : 0; cAlphaBits : 0; cAlphaShift : 0; cAccumBits : 0;
  49.          cAccumRedBits : 0; cAccumGreenBits : 0; cAccumBlueBits : 0; cAccumAlphaBits : 0;
  50.          cDepthBits : 16; cStencilBits : 0; cAuxBuffers : 0; iLayerType : PFD_MAIN_PLANE;
  51.          bReserved : 0; dwLayerMask : 0; dwVisibleMask : 0; dwDamageMask : 0);
  52. var
  53.   PixelFormat : Integer;
  54. begin
  55.    PixelFormat := ChoosePixelFormat (DC,@PFD);
  56.    if (PixelFormat = 0) then
  57.    begin
  58.      Exit;
  59.    end;
  60.  
  61.    if (SetPixelFormat (DC,PixelFormat,@PFD) <> True) then
  62.    begin
  63.      Exit;
  64.    end;
  65. end;
  66.  
  67.  
  68. procedure TfrmMain.FormCreate ( Sender : TObject
  69.                               );
  70. var
  71.   DC : HDC;
  72.   RC : HGLRC;
  73.   Loop : Integer;
  74. begin
  75.   DC := GetDC (pOGL.Handle);
  76.   SetupPixelFormat (DC);
  77.   RC := wglCreateContext (DC);
  78.   wglMakeCurrent (DC,RC);
  79.  
  80.   { Set up the control points for the Bezier curve... }
  81.   ControlPoints[0].X := -4;
  82.   ControlPoints[0].Y := -4;
  83.   ControlPoints[0].Z := -2;
  84.  
  85.   ControlPoints[1].X := -2;
  86.   ControlPoints[1].Y := 6;
  87.   ControlPoints[1].Z := 0;
  88.  
  89.   ControlPoints[2].X := 0;
  90.   ControlPoints[2].Y := -2;
  91.   ControlPoints[2].Z := 0;
  92.  
  93.   ControlPoints[3].X := 4;
  94.   ControlPoints[3].Y := 4;
  95.   ControlPoints[3].Z := -3;
  96.  
  97.   Randomize;
  98.   { Calculate colours for each segment of the created curve. }
  99.   for Loop := 0 to LevelOfDetail do
  100.   begin
  101.     Colours[Loop][0] := Random (100) / 100;
  102.     Colours[Loop][1] := Random (100) / 100;
  103.     Colours[Loop][2] := Random (100) / 100;
  104.   end;
  105.   glClearColor (0,0,0,1);
  106.  
  107.   glMap1f (GL_MAP1_VERTEX_3,0,1,3,4,@ControlPoints[0]);
  108.   glEnable (GL_MAP1_VERTEX_3);
  109.   glShadeModel (GL_FLAT);
  110.  
  111.   glMatrixMode (GL_PROJECTION);
  112.   glLoadIdentity;
  113.   gluPerspective (45,frmMain.Width / frmMain.Height,1,100);
  114.   glMatrixMode (GL_MODELVIEW);
  115. end;
  116.  
  117.  
  118. procedure TfrmMain.Draw;
  119. var
  120.   Loop : Integer;
  121. begin
  122.   glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  123.   glLoadIdentity;
  124.   glTranslatef (0,0,-15);
  125.  
  126.   glRotatef (Sin (GetTickCount / 500) * 60,1,0,0);
  127.   glRotatef (Sin (GetTickCount / 600) * 30,0,1,0);
  128.   glRotatef (Sin (GetTickCount / 2000) * 140,0,0,1);
  129.  
  130.   { Draw the actual segements of the Bezier curve. }
  131.   glLineWidth (4);
  132.   glBegin (GL_LINE_STRIP);
  133.     for Loop := 0 to LevelOfDetail do
  134.     begin
  135.       glColor3f (Colours[Loop][0],Colours[Loop][1],Colours[Loop][2]);
  136.       { How do I really know what X, Y and Z this is? }
  137.       glEvalCoord1f (Loop / LevelOfDetail);
  138.     end;
  139.   glEnd;
  140.  
  141.   { Draw each point along the Bezier curve... }
  142.   glColor3f (1,1,0);
  143.   glPointSize (5);
  144.   glBegin (GL_POINTS);
  145.     for Loop := 0 to LevelOfDetail do
  146.     begin
  147.       { Again - how can my X, Y and Z be obtained? }
  148.       glEvalCoord1f (Loop / LevelOfDetail);
  149.     end;
  150.   glEnd;
  151.  
  152.   { Draw the control points of the Bezier curve... }
  153.   glColor3f (1,0,0);
  154.   glLineWidth (1);
  155.   glBegin (GL_LINE_STRIP);
  156.     for Loop := 0 to 3 do
  157.     begin
  158.       { Obviously I know what my X, Y and Z are for these... }
  159.       glVertex3f (ControlPoints[Loop].X,ControlPoints[Loop].Y,ControlPoints[Loop].Z);
  160.     end;
  161.   glEnd;
  162.  
  163.   SwapBuffers (wglGetCurrentDC);
  164. end;
  165.  
  166.  
  167. procedure TfrmMain.Timer1Timer ( Sender : TObject
  168.                                );
  169. begin
  170.   Draw;
  171. end;
  172.  
  173.  
  174. end.

Autor:  i0n0s [ So Aug 19, 2007 14:26 ]
Betreff des Beitrags: 

Casteljau:
b_k^n (x) := x_k, k = 0,..., n;
b_k^(j+1) (x) := u_o(x|I) b_k^j (x) + u_1(x|I) b_(k+1)^j (x), k = 0,..., n - j - 1;

where u_0 and u_1 are "baryzentrische Koordinaten" which meens:
u_0(x|I) := (t_1 - x) / (t_1 - t_0)
and
u_1(x|I) := (x - t_0) / (t_1 - t_0)
where t_0 and t_1 are the points at the border of the interval I.

b_0^n(x) is the value of the bezier curve at point x.

Autor:  dpm_dpmartin [ So Aug 19, 2007 14:27 ]
Betreff des Beitrags:  Success!

S'OK... got it. Not exactly got it figured out - but got it working anyway with:

Code:
  1. function TfrmMain.GetPointOnCurve ( ControlPoint1, ControlPoint2, ControlPoint3, ControlPoint4 : TPoint;
  2.                                     CurvePoint : GLFloat
  3.                                   ) : TPoint;
  4. var
  5.   V1, V2, V3 : GLFloat;
  6.   Returning : TPoint;
  7. begin
  8.   V1 := 1 - CurvePoint;
  9.   V2 := V1 * V1 * V1;
  10.   V3 := CurvePoint * CurvePoint * CurvePoint;
  11.  
  12.   Returning.X := V2 * ControlPoint1.X + 3 * CurvePoint * V1 * V1 * ControlPoint2.X + 3 * CurvePoint * CurvePoint * V1 * ControlPoint3.X + V3 * ControlPoint4.X;
  13.   Returning.Y := V2 * ControlPoint1.Y + 3 * CurvePoint * V1 * V1 * ControlPoint2.Y + 3 * CurvePoint * CurvePoint * V1 * ControlPoint3.Y + V3 * ControlPoint4.Y;
  14.   Returning.Z := V2 * ControlPoint1.Z + 3 * CurvePoint * V1 * V1 * ControlPoint2.Z + 3 * CurvePoint * CurvePoint * V1 * ControlPoint3.Z + V3 * ControlPoint4.Z;
  15.  
  16.   GetPointOnCurve := Returning;
  17. end;
  18.  

...and:

Code:
  1.   glColor3f (1,1,0);
  2.   glPointSize (5);
  3.   glBegin (GL_POINTS);
  4.     T := 0;
  5.     for Loop := 0 to LevelOfDetail do
  6.     begin
  7.       ThisPoint := GetPointOnCurve (ControlPoints[0],ControlPoints[1],ControlPoints[2],ControlPoints[3],T);
  8.       glVertex3f (ThisPoint.X,ThisPoint.Y,ThisPoint.Z);
  9.       T := T + 1 / LevelOfDetail;
  10.     end;
  11.   glEnd;
  12.  
  13.  

Do I fully understand it? No. Do I understand that it does what I want? Yes. Am I happy with it? Yes.

Seite 1 von 1 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/