Quantcast
Channel: Форум программистов и сисадминов Киберфорум
Viewing all articles
Browse latest Browse all 524215

Lazarus OpenGL - вращение камеры - Lazarus

$
0
0
Получил боле-менее стабильное вращение без ошибок и лишних усложнений программы.
Еле-еле мне удалось обнаружить суть проблемы, проведя небольшое исследование.
Сгенерировал такой код (многие ругают меня, что у меня много предупреждений от компилятора - но так и работы я за краткие промежутки времени делаю больше, и если что-то не используется вдруг, то значит это применялось в опробировании вариантов исполнения), после чего вращение камеры стало вполне предсказуемым, а надобность в отслеживании OpenGLControl1MouseUp отпала
Кликните здесь для просмотра всего текста
:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  OpenGLContext, GL, GLU;

type

  { TForm1 }

  TForm1 = class(TForm)
    Memo1: TMemo;

    OpenGLControl1: TOpenGLControl;
    procedure FormCreate(Sender: TObject);
    procedure OpenGLControl1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure OpenGLControl1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure OpenGLControl1Paint(Sender: TObject);
    procedure OpenGLControl1Resize(Sender: TObject);
    procedure InitOpenGL;
  private
    Vectors: array[0..49, 0..49] of TPoint; // Массив векторов
    GridValues: array[0..50, 0..50] of Byte; // Массив значений ячеек сетки (0-255)
    AngleX, AngleY: Single;
    LastX, LastY: Integer;
    MouseDownFlag: Boolean;

    procedure LogMessage(const Msg: string); // Процедура для добавления сообщений в TMemo
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.LogMessage(const Msg: string);
begin
  Memo1.Lines.Add(Msg);
end;

//procedure TForm1.InitOpenGL;
//begin

//end;

procedure TForm1.InitOpenGL();
begin
  OpenGLControl1.MakeCurrent;

  // Включение теста глубины
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);

  // Включение сглаживания линий
  glEnable(GL_LINE_SMOOTH);
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

//  LogMessage('InitOpenGL: OpenGL settings initialized');

  OpenGLControl1.SwapBuffers;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i,j:integer;
begin

  OpenGLControl1.Width := 1000;
  OpenGLControl1.Height := 800;

  // Инициализация генератора случайных чисел
  Randomize;

  // Инициализация векторов (пример данных)
  for i := 0 to 49 do
    for j := 0 to 49 do
      Vectors[i][j] := Point(Random(10) - 5, Random(10) - 5); // Пример случайных векторов

  // Инициализация значений ячеек сетки (пример данных)
  for i := 0 to 50 do
    for j := 0 to 50 do
      GridValues[i][j] := Random(256); // Случайные значения от 0 до 255

  AngleX := 0.0;
  AngleY := 0.0;

//  LogMessage('FormCreate: Initialization completed');
  InitOpenGL;
end;



procedure TForm1.OpenGLControl1Paint(Sender: TObject);
var
  i, j,i1,j1: Integer;
  x,y,z, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4: Single;
  grayValue, sizeFactor, alpha: Byte;
begin
 // LogMessage('OpenGLControl1Paint: Rendering started');

  OpenGLControl1.MakeCurrent;

  // Очистка буферов цвета и глубины
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  // Сброс матрицы проекции
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;

  // Установка перспективной проекции
  gluPerspective(45.0, OpenGLControl1.Width / OpenGLControl1.Height, 0.1, 100.0);

  // Сброс матрицы модели-вида
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  // Перемещение камеры вперед
  gluLookAt(3.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  // Поворот камеры
  glRotatef(AngleY,  1, 0, 0);
  glRotatef(AngleX, 0.0, 0.0, 1.0);

  // Включение смешивания для прозрачности
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  // Отрисовка квадратов в градациях серого с учетом размера и прозрачности
  glBegin(GL_QUADS);
  for i := 0 to 49 do
    for j := 0 to 49 do
    begin
      grayValue := GridValues[i][j];

      // Вычисление фактора размера (чем больше значение, тем меньше квадрат)
      sizeFactor := 10 - (grayValue div 25); // Нормализация значения от 1 до 10

            // Вычисляем координаты центра ячейки
      x := -2.5 + (i * 0.1) + 0.05;
      y := -2.5 + (j * 0.1) + 0.05;
      z := 0.0;

      x1 := x-(sizeFactor / 200);
      y1 := y-(sizeFactor / 200);
      z1 := 0.0;

      x2 := x1 + (sizeFactor/100);
      y2 := y1;
      z2 := 0.0;

      x3 := x2;
      y3 := y1 + (sizeFactor/100);
      z3 := 0.0;

      x4 := x1;
      y4 := y3;
      z4 := 0.0;

      // Вычисление прозрачности (чем больше значение, тем ярче квадрат)
      alpha := grayValue; // Значение от 0 до 255

      glColor4f(grayValue / 255.0, grayValue / 255.0, grayValue / 255.0, alpha / 255.0); // Градации серого с прозрачностью

      glVertex3f(x1, y1, z1);
      glVertex3f(x2, y2, z2);
      glVertex3f(x3, y3, z3);
      glVertex3f(x4, y4, z4);
    end;
  glEnd;

  // Выключение смешивания
  glDisable(GL_BLEND);


  // Отрисовка векторов
  glColor3f(1.0, 0.0, 0.0); // Красный цвет для векторов
  glBegin(GL_LINES);
  for i1 := 1 to 49 do
    for j1 := 1 to 49 do
    begin
      x1 := -2.5 + i1 * 0.1;
      y1 := -2.5 + j1 * 0.1;
      z1 := 0.0;

      x2 := x1 + Vectors[i1][j1].X * 0.01; // Нормализация векторов
      y2 := y1 + Vectors[i1][j1].Y * 0.01;
      z2 := 0.0;

      glVertex3f(x1, y1, z1);
      glVertex3f(x2, y2, z2);
    end;
  glEnd;

//  LogMessage('OpenGLControl1Paint: Rendering completed');

  OpenGLControl1.SwapBuffers;
end;


procedure TForm1.OpenGLControl1Resize(Sender: TObject);
var
  AspectRatio: Single;
begin
  if OpenGLControl1.Height = 0 then Exit; // Защита от деления на ноль

  OpenGLControl1.MakeCurrent;

  // Установка области просмотра
  glViewport(0, 0, OpenGLControl1.Width, OpenGLControl1.Height);

  // Сброс матрицы проекции
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;

  // Вычисление соотношения сторон
  AspectRatio := OpenGLControl1.Width / OpenGLControl1.Height;

  // Установка перспективной проекции
  gluPerspective(45.0, AspectRatio, 0.1, 100.0);

 // LogMessage('OpenGLControl1Resize: Projection set');

  OpenGLControl1.SwapBuffers;
end;


procedure TForm1.OpenGLControl1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
  begin
//    MouseDownFlag := True;
    LastX := X;
    LastY := Y;
  end;
end;


//procedure TForm1.OpenGLControl1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
//begin
//  if Button = mbLeft then
//    MouseDownFlag := False;
//end;

procedure TForm1.OpenGLControl1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  DeltaX, DeltaY: Integer;
begin
  if ssLeft in Shift then
  begin
    DeltaX := X - LastX;
    DeltaY := Y - LastY;

    // Обновление углов вращения камеры
    AngleX := AngleX + DeltaY * 0.5; // Вращение по оси X
    AngleY := AngleY + DeltaX * 0.5; // Вращение по оси Y

    LastX := X;
    LastY := Y;

    // Перерисовка экрана
    OpenGLControl1.Refresh;

//    LogMessage(Format('AngleX: %.2f, AngleY: %.2f', [AngleX, AngleY]));
  end;
end;




end.


Но, выяснилась одна деталь. Сейчас сначала расшифрую эту строку например
:

glRotatef(AngleX, 0.0, 0.0, 1.0);
поворот камеры.
AngleX -величина угла, на который производится поворот. И далее, через запятые, видимо коэффициенты, или что-то, по осям X, Y, Z.
Так вот, приведённая выше строка осуществляет поворот по оси Z от перемещения курсора мыши по оси X.
Но в данном случае интересует ось X и вот эта строка
:

  glRotatef(AngleY,  1, 0, 0);
вполне логично, что раз вертикальным движением вращается вокруг оси Z, то горизонтальным сделал ось X, и вот тут самое интересное - что она кривая в отличии от оси Y, вы это увидете изменив строку так
:

  glRotatef(AngleY,  0, 1, 0);
.
Точнее сказать у библиотеки совсем свои представления, в которых ось X для данной функции - диагональная, а ось Y - прямая, и это ещё помимо того, что сами оси просто переносятся из сцены на само окно, что можно понять повернув плоскость на 90 градусов вокруг оси Z, и вы обнаружите что осью Y вдруг стала перпендикуларная ось - меняется местами с X. Сам механизм работы поворота с матрицею - нигде не описывается, а по ссылкам разумеется можно прочитать что угодно, вплоть до того, что в OpenGL вообще камеры не существует. Ну может быть, но тем не менее что получается: ось Z - абсолютная, ось Y - переносная, а ось X - косая. Такой вывод можно сделать если поэкспериментировать с вращением и вот этими строками
:

  glRotatef(AngleY,  1, 0, 0);
  glRotatef(AngleX, 0.0, 0.0, 1.0);

.
Помогите пожалуйста разобраться в этой ситуации.

Добавлено через 20 минут
Кажется я понял, это возможно происходит потому, что при задании параметров перспективы установлен угол 45 градусов. Но сегодня у меня нет уже времени разбираться - разберусь завтра. Если кто знает точно - прошу подсказать.

Viewing all articles
Browse latest Browse all 524215

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>