Программа реализует пример переключения камеры между объектами, привязка камеры к объекту.
Рисунок 1. Пример работы программы
Код проекта:
unit ogl_p17_u1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, dglOpenGL, ExtCtrls, Math, DGlut;
type
TForm1 = class(TForm)
tmr1: TTimer;
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure tmr1Timer(Sender: TObject);
private
{ Private declarations }
public
h_RC: HGLRC; // Контекст рендеринга
h_DC: HDC; // Контекст устройства
procedure AttachCameraToCube;
procedure AttachCameraToCube2;
procedure ReturnCameraToOrigPos;
procedure InitGL;
procedure DrawGLScene;
procedure UpdateCamera;
procedure HandleKeys;
procedure DrawCube;
procedure DrawCube2;
procedure DrawTrack;
procedure BuildFont;
procedure glPrint(text: string);
{ Public declarations }
end;
var
Form1: TForm1;
CubePos: array [0..2] of GLfloat = (0, 0, 0); // Позиция куба
Cube2Pos: array [0..2] of GLfloat = (0, 0, 0); // Позиция куба 2
Cube2PosCount: GLfloat = 1.0;
Cube2Rot: GLfloat = 0.0;
Cube2Speed: GLfloat = 1.0;
CubeRot: GLfloat = 0.0; // Угол вращения куба
CamPos: array [0..2] of GLfloat = (0, 5, 10); // Позиция камеры
CamPitch: GLfloat; // Углы поворота камеры
MoveSpeed: GLfloat = 0.1; // Скорость перемещения
CamPosFlag: GLbyte;
const
CAM_FREE = 0;
CAM_CUBE1 = 1;
CAM_CUBE2 = 2;
FONT_BASE = 1000;
implementation
{$R *.dfm}
procedure TForm1.BuildFont;
var
h_Font: HFONT;
begin
h_Font := CreateFont(
-16,
0,
0,
0,
FW_NORMAL,
0,
0,
0,
RUSSIAN_CHARSET,
OUT_TT_PRECIS,
CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY,
FF_DONTCARE or DEFAULT_PITCH,
'Arial'
);
SelectObject(h_DC, h_Font);
wglUseFontBitmaps(h_DC, 0, 256, FONT_BASE);
DeleteObject(h_Font);
end;
procedure TForm1.glPrint(text: string);
begin
glListBase(FONT_BASE);
glCallLists(Length(text), GL_UNSIGNED_BYTE, PAnsiChar(AnsiString(text)));
end;
procedure TForm1.AttachCameraToCube;
begin
CamPos[0] := CubePos[0] + 3;
CamPos[1] := CubePos[1] + 4;
CamPos[2] := CubePos[2] + 5;
end;
procedure TForm1.AttachCameraToCube2;
begin
CamPos[0] := Cube2Pos[0] + 3;
CamPos[1] := Cube2Pos[1] + 4;
CamPos[2] := Cube2Pos[2] + 5;
end;
procedure TForm1.ReturnCameraToOrigPos;
begin
CamPos[0] := 0;
CamPos[1] := 5;
CamPos[2] := 10;
end;
procedure TForm1.InitGL;
begin
InitOpenGL;
h_DC := GetDC(Handle);
h_RC := CreateRenderingContext(h_DC, [opDoubleBuffered], 32, 24, 8, 0, 0, 0);
ActivateRenderingContext(h_DC, h_RC);
if Assigned(wglSwapIntervalEXT) then
wglSwapIntervalEXT(1);
glClearColor(0.0, 0.0, 0.0, 1.0); // Чёрный фон
glEnable(GL_DEPTH_TEST); // Включение теста глубины
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(45.0, 640/480, 0.1, 100.0); // Настройка перспективы
glMatrixMode(GL_MODELVIEW);
BuildFont;
end;
procedure TForm1.UpdateCamera;
begin
glLoadIdentity;
case CamPosFlag of
CAM_FREE: // Исходная позиция
gluLookAt(CamPos[0], CamPos[1], CamPos[2], 0, 0, 0, 0, 1, 0);
CAM_CUBE1: // Следим за первым кубом
gluLookAt(CamPos[0], CamPos[1], CamPos[2], CubePos[0], CubePos[1], CubePos[2], 0, 1, 0);
CAM_CUBE2: // Следим за вторым кубом
gluLookAt(CamPos[0], CamPos[1], CamPos[2], Cube2Pos[0], Cube2Pos[1], Cube2Pos[2], 0, 1, 0);
end;
end;
procedure TForm1.HandleKeys;
var
Angle: GLfloat;
begin
if GetAsyncKeyState(VK_F1) < 0 then
begin
CamPosFlag := CAM_CUBE1;
AttachCameraToCube;
end;
if GetAsyncKeyState(VK_F2) < 0 then
begin
CamPosFlag := CAM_CUBE2;
AttachCameraToCube2;
end;
if GetAsyncKeyState(VK_F3) < 0 then
begin
CamPosFlag := CAM_FREE;
ReturnCameraToOrigPos;
end;
if GetAsyncKeyState(VK_UP) < 0 then
begin
CubePos[2] := CubePos[2] - MoveSpeed;
if CamPosFlag = CAM_CUBE1 then
AttachCameraToCube;
end;
if GetAsyncKeyState(VK_DOWN) < 0 then
begin
CubePos[2] := CubePos[2] + MoveSpeed;
if CamPosFlag = CAM_CUBE1 then
AttachCameraToCube;
end;
if GetAsyncKeyState(VK_LEFT) < 0 then
begin
CubePos[0] := CubePos[0] - MoveSpeed;
if CamPosFlag = CAM_CUBE1 then
AttachCameraToCube;
end;
if GetAsyncKeyState(VK_RIGHT) < 0 then
begin
CubePos[0] := CubePos[0] + MoveSpeed;
if CamPosFlag = CAM_CUBE1 then
AttachCameraToCube;
end;
CubeRot := CubeRot + 2.0; // Вращение
if CubeRot >= 360 then CubeRot := 0;
// Движение и вращение второго куба
Cube2PosCount := Cube2PosCount + Cube2Speed;
if Cube2PosCount >= 360 then Cube2PosCount := 0;
// Всегда обновляем позицию второго куба
Angle := DegToRad(Cube2PosCount);
Cube2Pos[0] := 5*Cos(Angle);
Cube2Pos[1] := 0.5;
Cube2Pos[2] := 5*Sin(Angle);
Cube2Rot := Cube2Rot + 3.0; // Независимое вращение
if Cube2Rot >= 360 then Cube2Rot := 0;
end;
procedure TForm1.DrawCube;
begin
glColor3f(0, 0, 1); // Синий цвет
glPushMatrix;
glTranslatef(CubePos[0], CubePos[1], CubePos[2]);
glRotatef(CubeRot, 0, 1, 0); // Вращение вокруг Y
glutSolidCube(1.0); // Используем GLUT для простоты
glPopMatrix;
end;
procedure TForm1.DrawCube2;
begin
glColor3f(1, 0, 1); // Фиолетовый цвет
glPushMatrix;
glTranslatef(Cube2Pos[0], Cube2Pos[1], Cube2Pos[2]);
glRotatef(Cube2Rot, 0, 1, 0);
glutSolidCube(1.0);
glPopMatrix;
end;
procedure TForm1.DrawTrack;
var
i: Integer;
begin
glColor3f(1, 1, 0); // Жёлтый цвет
glBegin(GL_LINE_STRIP);
for i := 0 to 360 do
glVertex3f(5*Cos(DegToRad(i)), 0, 5*Sin(DegToRad(i)));
glEnd;
end;
procedure TForm1.DrawGLScene;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity;
UpdateCamera;
HandleKeys;
DrawTrack;
DrawCube;
DrawCube2;
// Сохраняем текущую матрицу
glPushMatrix;
// Переключаемся в 2D режим для текста
glMatrixMode(GL_PROJECTION);
glPushMatrix;
glLoadIdentity;
gluOrtho2D(0, ClientWidth, ClientHeight, 0); // 2D проекция
glMatrixMode(GL_MODELVIEW);
glPushMatrix;
glLoadIdentity;
// Отключаем тест глубины для текста
glDisable(GL_DEPTH_TEST);
// Устанавливаем цвет текста
glColor3f(1.0, 1.0, 1.0); // Белый цвет
// Рисуем текст
glRasterPos2f(10, 20);
glPrint('F1 - Синий куб');
glRasterPos2f(10, 40);
glPrint('F2 - Розовый куб');
glRasterPos2f(10, 60);
glPrint('F3 - Вся сцена');
// Восстанавливаем настройки
glEnable(GL_DEPTH_TEST);
glPopMatrix; // MODELVIEW
glMatrixMode(GL_PROJECTION);
glPopMatrix; // PROJECTION
glMatrixMode(GL_MODELVIEW);
glPopMatrix; // исходная матрица
SwapBuffers(h_DC);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
wglMakeCurrent(0, 0);
wglDeleteContext(h_RC);
ReleaseDC(Handle, h_DC);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered := False;
InitGL;
KeyPreview := True;
Visible := True;
tmr1.Interval := 16;
CamPosFlag := 0;
Cube2PosCount := 0;
end;
procedure TForm1.FormResize(Sender: TObject);
begin
glViewport(0, 0, ClientWidth, ClientHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(45.0, ClientWidth/ClientHeight, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
end;
procedure TForm1.tmr1Timer(Sender: TObject);
begin
DrawGLScene;
end;
end.

Комментариев нет:
Отправить комментарий