OpenGL быстро мерцает вопросами - и теперь не показывает изображение


У меня возникли некоторые проблемы с OpenGL. Во-первых, у меня есть пользовательский элемент управления, который я создаю, инкапсулируя OpenGL. У меня есть проблема, когда он быстро мигает, как будто он "мигает". Контроль был слишком большим и сложным, чтобы разместить его здесь, поэтому я сделал новое небольшое демонстрационное приложение, чтобы продемонстрировать и воссоздать тот же сценарий.

Проблема теперь: я не получаю никакого изображения. Все было бы прекрасно в моем пользовательском контроле, но так как я скопировал код и раздел его в небольшой демо-версии приложение, оно не будет показывать изображение. Итак, здесь у меня есть две проблемы: мерцание (или мигание), и теперь изображение даже не отображается. Мерцание не происходило в прошлом, но после некоторой серьезной ревизии кода оно начало мерцать. Это было слишком большое изменение кода, чтобы объяснить, что именно было изменено, почти все.

Фон показывает, поэтому я знаю, что он что-то рисует (он цветной). Он должен рисовать только один куб для демонстрационных целей, но я ничего не вижу. Я должен был ... сократите это число примерно с 1000 строк кода до 300.

Это не то, что вы обычно называете мерцанием, на самом деле это скорее мигание или мигание, представьте, что мигает автомобильная мигалка. Это определенно связано с таймером, потому что чем выше интервал, который я ставлю на таймер, тем медленнее он мигает.

Почему я ничего не вижу? И если это зафиксировано, почему оно так сильно мерцает?

Вот код одной формы, без DFM необходимо:

unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, Winapi.OpenGL,
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    FDrawing: Bool;
    FDC: HDC;
    FRC: HGLRC;
    FDL: glUint;
    FTimer: TTimer;
    procedure Draw;
    procedure SetDC(const Value: HDC);
    procedure SetRC(const Value: HGLRC);
    procedure SetDL(const Value: glUint);
  public
    property DC: HDC read FDC write SetDC;
    property RC: HGLRC read FRC write SetRC;
    property DL: glUint read FDL write SetDL;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  PixelFormat: glUint;
  pfd: TPIXELFORMATDESCRIPTOR;
begin
  FDrawing := False;
  FDC := GetDC(Handle);
  with pfd do begin
    nSize := SizeOf(TPIXELFORMATDESCRIPTOR);
    nVersion := 1; // The version of this data structure
    dwFlags := PFD_DRAW_TO_WINDOW // Buffer supports drawing to window
      or PFD_SUPPORT_OPENGL // Buffer supports OpenGL drawing
      or PFD_DOUBLEBUFFER; // Supports double buffering
    iPixelType := PFD_TYPE_RGBA; // RGBA color format
    cColorBits := 32; // OpenGL color depth
    cRedBits := 0; // Number of red bitplanes
    cRedShift := 0; // Shift count for red bitplanes
    cGreenBits := 0; // Number of green bitplanes
    cGreenShift := 0; // Shift count for green bitplanes
    cBlueBits := 0; // Number of blue bitplanes
    cBlueShift := 0; // Shift count for blue bitplanes
    cAlphaBits := 0; // Not supported
    cAlphaShift := 0; // Not supported
    cAccumBits := 0; // No accumulation buffer
    cAccumRedBits := 0; // Number of red bits in a-buffer
    cAccumGreenBits := 0; // Number of green bits in a-buffer
    cAccumBlueBits := 0; // Number of blue bits in a-buffer
    cAccumAlphaBits := 0; // Number of alpha bits in a-buffer
    cDepthBits := 16; // Specifies the depth of the depth buffer
    cStencilBits := 0; // Turn off stencil buffer
    cAuxBuffers := 0; // Not supported
    iLayerType := PFD_MAIN_PLANE; // Ignored
    bReserved := 0; // Number of overlay and underlay planes
    dwLayerMask := 0; // Ignored
    dwVisibleMask := 0; // Transparent color of underlay plane
    dwDamageMask := 0; // Ignored
  end;
  PixelFormat := ChoosePixelFormat(FDC, @pfd);
  SetPixelFormat(FDC, PixelFormat, @pfd);
  FRC := wglCreateContext(FDC);
  wglMakeCurrent(FDC, FRC);
  FormResize(nil);
  wglMakeCurrent(FDC, FRC);
  glClearColor(0.8, 0.8, 0.9, 0.0);
  glShadeModel(GL_FLAT);
  glClearDepth(1.0);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  glEnable(GL_ALPHA_TEST);
  glAlphaFunc(GL_GREATER, 0.4);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_BLEND);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  glEnable(GL_TEXTURE_2D);
  glNewList(FDL, GL_COMPILE);
    glBegin(GL_QUADS);
      // Front Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, 1.0);
      // Back Face
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      // Top Face
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      // Bottom Face
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      // Left Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(1.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(1.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
    glEnd();
  glEndList();
  FTimer:= TTimer.Create(nil);
  FTimer.OnTimer:= Timer1Timer;
  FTimer.Interval:= 100;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FTimer.Free;
  if (not wglMakeCurrent(FDC, 0)) then
    MessageBox(0, 'Release of DC and RC failed!', 'Error', MB_OK or MB_ICONERROR);
  if (not wglDeleteContext(FRC)) then begin
    MessageBox(0, 'Release of rendering context failed!', 'Error', MB_OK or MB_ICONERROR);
    FRC := 0;
  end;
  if ((FDC > 0) and (ReleaseDC(Handle, FDC) = 0)) then begin
    MessageBox(0, 'Release of device context failed!', 'Error', MB_OK or MB_ICONERROR);
    FDC := 0;
  end;
end;

procedure TForm1.Draw;
var
  I: Integer;
begin
  if not FDrawing then begin
    FDrawing := TRUE;
    try
      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
      glEnable(GL_NORMALIZE);
      glShadeModel(GL_FLAT);
      glCullFace(GL_BACK);
      glLoadIdentity;
      glPushMatrix();
      glCallList(DL);
      glPopMatrix();
      SwapBuffers(wglGetCurrentDC);
    finally
      FDrawing := False;
    end;
  end;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  glViewport(0, 0, Width, Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, Width / Height, 0.1, 500.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
end;

procedure TForm1.SetDC(const Value: HDC);
begin
  FDC := Value;
end;

procedure TForm1.SetDL(const Value: glUint);
begin
  FDL := Value;
end;

procedure TForm1.SetRC(const Value: HGLRC);
begin
  FRC := Value;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Draw;
end;

end.
Теперь приведенный выше код довольно сильно отличается от того, как работает мой исходный код. Исходная процедура Draw выполняет итерацию по списку объектов, каждый из которых содержит свою собственную процедуру Draw. Таким образом, процедура рисования элемента управления подготавливает общую сцену, а затем рисует каждый "элемент" один за другим, как это:
procedure TGLImage.Draw;
var
  X: Integer;
begin
  if not FDrawing then begin
    FDrawing := TRUE;
    try
      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
      glEnable(GL_NORMALIZE);
      glShadeModel(GL_FLAT);
      glCullFace(GL_BACK);
      glLoadIdentity();

      glRotatef(FElapsedTime / 70, 0, 0, 1);
      glRotatef(90, 0, 1, 0);
      glTranslatef(-FElapsedTime / 400, 0, 0);

      if FInitialized then begin
        for X := 0 to FItems.Count - 1 do begin
          FItems[X].Draw;
        end;
      end;

      SwapBuffers(wglGetCurrentDC);
    finally
      FDrawing := False;
    end;
  end;
end;
И вот один из элементов, который он рисует...
constructor TGLBeam.Create(AOwner: TGLItems);
begin
  inherited;
  glNewList(DL, GL_COMPILE);
    glBegin(GL_QUADS);
      // Front Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, 1.0);
      // Back Face
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      // Top Face
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      // Bottom Face
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      // Left Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(1.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(1.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
    glEnd();
  glEndList();
end;

procedure TGLBeam.Draw;
var
  I: Integer;
begin
  glRotatef(Directions.X, 1.0, 0.0, 0.0);
  glRotatef(Directions.Y, 0.0, 1.0, 0.0);
  glRotatef(Directions.Z, 0.0, 0.0, 1.0);
  for I := 1 to 10 do begin
    //Main Center
    glPushMatrix();
    glTranslatef(I * 4 + Owner.Owner.ClockTime * 4, 0, 0);
    glCallList(DL);
    glPopMatrix();
    //Above
    glPushMatrix();
    glTranslatef(I * 4 + Owner.Owner.ClockTime * 4, 6, 0);
    glCallList(DL);
    glPopMatrix();
  end;
end;
2 3

2 ответа:

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_NORMALIZE);
glShadeModel(GL_FLAT);
glCullFace(GL_BACK);
glLoadIdentity;
glPushMatrix();
glCallList(DL);
glPopMatrix();
SwapBuffers(wglGetCurrentDC);

Во-первых, добавьте () к вашему вызову, чтобы glLoadIdentity

Вы загружаете матрицу идентичности, затем толкаете ее, затем рендерите и вытаскиваете ее, фактически не делая никаких преобразований.

Либо удалите 3 строки

glLoadIdentity;
glPushMatrix();

glPopMatrix();

Или Переместите glPushMatrix() в строку перед glLoadIdentity()

Я бы также предложил отключить затенение и отбраковку, чтобы убедиться, что они не мешают. Квадроциклы объявляются в немного неправильном порядке с отбраковкой задней поверхности на просто отбраковывает их даже если вы не хотите, чтобы их отбирали спереди.

Проблема с мерцанием была обнаружена, и это была очень большая ошибка, которую я не ожидаю, что вы поймете, не имея всего проекта. Проблема заключалась в том, что я создавал два из этих элементов управления, и они мешали / боролись друг с другом. На самом деле, поскольку OpenGL работает по потоку (или в рамках одного "контекста"), наличие двух различных элементов управления, которые пытаются сделать свой собственный рисунок, будет мешать, вызывая то же самое происходят на обоих элементах управления одновременно. Так что мигание было от того, что каждый элемент управления пытался по очереди делать рисунок. Мой новый вопрос, который я задал, связанный с помещением этого рисунка в нить, прекрасно вылечит эту проблему. Это была глупая ошибка, и я сожалею, что потратил чье-то время.