![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Корректировка положения света и нормалей для правильного освещения вращающегося куба в DelphiDelphi , Графика и Игры , OpenGLdelphi and opengl: light is rotating with the cube Оригинальный заголовок:delphi and opengl: light is rotating with the cube Описание проблемы (вопрос):Вопрос был переведен, так что я не знаю, верно ли он орфографически. Я начал изучать OpenGL и столкнулся со следующей проблемой: когда я вращаю куб, свет также вращается. Я пытался изменить координаты света в каждом кадре, но это не помогло. Скажите, что пошло не так? Если нет проблем, было бы здорово получить исправленную версию. Код:unit MainUnit; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, dglOpenGL, dglut; type TFMainForm = class(TForm) procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); private procedure SetupGL; procedure uzglLightEnable; procedure IdleHandler(Sender: TObject; var Done: Boolean); public procedure Render; end; var FMainForm: TFMainForm; dc: hdc; hrc: hglrc; XRot, YRot, ZRot: Single; LightPos: TGLArrayf4; BlueArray: TGLArrayf4; GreenArray: TGLArrayf4; myTex: glUint; FrontNormal: TGLvectorf3 = (0, 0, 1); BackNormal: TGLvectorf3 = (0, 0, -1); LeftNormal: TGLvectorf3 = (-1, 0, 0); RightNormal: TGLvectorf3 = (1, 0, 0); UpNormal: TGLvectorf3 = (0, 1, 0); DownNormal: TGLvectorf3 = (0, -1, 0); FrontDownLeft: TGLvectorf3 = (-1, -1, -1); FrontDownRight: TGLvectorf3 = (1, -1, -1); FrontUpLeft: TGLvectorf3 = (-1, 1, -1); FrontUpRight: TGLvectorf3 = (1, 1, -1); BackDownLeft: TGLvectorf3 = (-1, -1, 1); BackDownRight: TGLvectorf3 = (1, -1, 1); BackUpLeft: TGLvectorf3 = (-1, 1, 1); BackUpRight: TGLvectorf3 = (1, 1, 1); const NearClipping = 0.1; FarClipping = 200; procedure uzglTriangle(x1, y1, z1, x2, y2, z2, x3, y3, z3: Single); procedure uzglCube; implementation {$R *.dfm} procedure uzglTriangle(x1, y1, z1, x2, y2, z2, x3, y3, z3: Single); begin glBegin(GL_TRIANGLES); glColor3f(0.3, 0, 0); glVertex3f(x1, y1, z1); glColor3f(0.25, 1, 0); glVertex3f(x2, y2, z2); glColor3f(0.7, 0, 1); glVertex3f(x3, y3, z3); glEnd; end; procedure uzglCube; begin glBegin(GL_QUADS); glNormal3fv(@FrontNormal); glVertex3fv(@FrontDownLeft); glVertex3fv(@FrontDownRight); glVertex3fv(@FrontUpRight); glVertex3fv(@FrontUpLeft); glEnd; glBegin(GL_QUADS); glNormal3fv(@LeftNormal); glVertex3fv(@FrontDownLeft); glVertex3fv(@FrontUpLeft); glVertex3fv(@BackUpLeft); glVertex3fv(@BackDownLeft); glEnd; glBegin(GL_QUADS); glNormal3fv(@RightNormal); glVertex3fv(@FrontDownRight); glVertex3fv(@FrontUpRight); glVertex3fv(@BackUpRight); glVertex3fv(@BackDownRight); glEnd; glBegin(GL_QUADS); glNormal3fv(@UpNormal); glVertex3fv(@FrontUpRight); glVertex3fv(@FrontUpLeft); glVertex3fv(@BackUpLeft); glVertex3fv(@BackUpRight); glEnd; glBegin(GL_QUADS); glNormal3fv(@DownNormal); glVertex3fv(@FrontDownRight); glVertex3fv(@FrontDownLeft); glVertex3fv(@BackDownLeft); glVertex3fv(@BackDownRight); glEnd; glBegin(GL_QUADS); glNormal3fv(@BackNormal); glVertex3fv(@BackDownLeft); glVertex3fv(@BackDownRight); glVertex3fv(@BackUpRight); glVertex3fv(@BackUpLeft); glEnd; end; procedure TFMainForm.SetupGL; begin glClearColor(0.3, 0.4, 0.7, 0.0); glEnable(GL_DEPTH_TEST); glEnable(GL_SMOOTH); glDepthFunc(GL_LEQUAL); glEnable(GL_TEXTURE_2D); uzglLightEnable; LightPos[0] := 0; LightPos[1] := 0; LightPos[2] := 1; LightPos[3] := 1; end; procedure TFMainForm.uzglLightEnable; begin glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); end; procedure TFMainForm.Render; var i: Integer; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluPerspective(45.0, ClientWidth / ClientHeight, NearClipping, FarClipping); glTranslatef(0, 0, -5); glPushMatrix; glRotatef(XRot, 1, 0, 0); uzglCube; glPopMatrix; glLightfv(GL_LIGHT0, GL_POSITION, @LightPos); SwapBuffers(dc); XRot := XRot + 1; end; procedure TFMainForm.IdleHandler(Sender: TObject; var Done: Boolean); begin Render; Sleep(25); Done := false; end; procedure TFMainForm.FormCreate(Sender: TObject); begin dc := GetDC(Handle); if not InitOpenGL then begin ShowMessage('????????... ????????????? ???????????'); Application.Terminate; end; hrc := CreateRenderingContext(dc, [opDoubleBuffered], 32, 24, 8, 0, 0, 0); ActivateRenderingContext(dc, hrc); SetupGL; Application.OnIdle := IdleHandler; FMainForm.OnResize(self); end; procedure TFMainForm.FormResize(Sender: TObject); var tmpBool: Boolean; begin glViewport(0, 0, ClientWidth, ClientHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluPerspective(45.0, ClientWidth / ClientHeight, NearClipping, FarClipping); glMatrixMode(GL_MODELVIEW); glLoadIdentity; idleHandler(Sender, tmpBool); end; procedure TFMainForm.FormDestroy(Sender: TObject); begin DeactivateRenderingContext; DestroyRenderingContext(hrc); ReleaseDC(Handle, dc); end; procedure TFMainForm.FormKeyPress(Sender: TObject; var Key: Char); begin case Key of 'q': LightPos[0] := LightPos[0] + 0.1; 'a': LightPos[0] := LightPos[0] - 0.1; 'w': LightPos[1] := LightPos[1] + 0.1; 's': LightPos[1] := LightPos[1] - 0.1; 'e': LightPos[2] := LightPos[2] + 0.1; 'd': LightPos[2] := LightPos[2] - 0.1; end; end; end. dglOpenGL: http://wiki.delphigl.com/index.php/dglOpenGL.pas/en Подтвержденный ответ:Итак, я вижу несколько проблем в вашем коде. Во-первых, ваши нормали некорректны. Измените их на следующее: FrontNormal: TGLvectorf3 = (0, 0, 1); BackNormal: TGLvectorf3 = (0, 0, -1); LeftNormal: TGLvectorf3 = (1, 0, 0); RightNormal: TGLvectorf3 = (-1, 0, 0); UpNormal: TGLvectorf3 = (0, -1, 0); DownNormal: TGLvectorf3 = (0, 1, 0); Во-вторых, вы трансформируете свой куб в матрице GL_PROJECTION. Матрица GL_PROJECTION должна содержать только то, что необходимо для установки проекции. Ваш куб и свет должны быть трансформированы матрицей GL_MODELVIEW. Ваша проекция меняется только при изменении размера окна, поэтому она может быть установлена в событии FormResize. procedure TForm2.FormResize(Sender: TObject); var tmpBool: Boolean; begin glViewport(0, 0, ClientWidth, ClientHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluPerspective(45.0, ClientWidth / ClientHeight, NearClipping, FarClipping); idleHandler(Sender, tmpBool); end; Матрица GL_MODELVIEW может быть установлена в процедуре SetupGL. Обратите внимание на команду gluLookAt(), которая устанавливает вид от (-2, 3, -3) к (0, 0, 0). Установите gluLookAt(0, 3, -3, 0, 0, 0, 0, 1, 0);, чтобы получить "прямой" вид. procedure TForm2.SetupGL; begin glClearColor(0.3, 0.4, 0.7, 0.0); glEnable(GL_DEPTH_TEST); glEnable(GL_SMOOTH); glDepthFunc(GL_LEQUAL); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glLoadIdentity; gluLookAt(-2, 3, -3, 0, 0, 0, 0, 1, 0); uzglLightEnable; LightPos[0] := 0; LightPos[1] := 0; LightPos[2] := 1; LightPos[3] := 1; end; Процедура Render становится следующей. procedure TForm2.Render; var i: Integer; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix; glRotatef(XRot, 1, 0, 0); uzglCube; if FTransformLights then begin glLightfv(GL_LIGHT0, GL_POSITION, @LightPos); glPopMatrix; end else begin glPopMatrix; glLightfv(GL_LIGHT0, GL_POSITION, @LightPos); end; SwapBuffers(dc); XRot := XRot + 1; end; Примечание: Я добавил приватную форму FTransformLights, которая, если true, вращает свет с кубом, в противном случае свет не вращается, так как он трансформируется после того, как матрица GL_MODELVIEW возвращается к своему исходному состоянию (единице). Я добавил клавишу 'x', чтобы переключать, вращается ли свет или нет. Вот полный модифицированный список. Надеюсь, это поможет. unit MainUnit; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, dglOpenGL; type TFMainForm = class(TForm) procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); private FTransformLights: Boolean; procedure SetupGL; procedure uzglLightEnable; procedure IdleHandler(Sender: TObject; var Done: Boolean); public procedure Render; end; var FMainForm: TFMainForm; dc: hdc; hrc: hglrc; XRot, YRot, ZRot: Single; LightPos: TGLArrayf4; BlueArray: TGLArrayf4; GreenArray: TGLArrayf4; myTex: glUint; FrontNormal: TGLvectorf3 = (0, 0, 1); BackNormal: TGLvectorf3 = (0, 0, -1); LeftNormal: TGLvectorf3 = (1, 0, 0); RightNormal: TGLvectorf3 = (-1, 0, 0); UpNormal: TGLvectorf3 = (0, -1, 0); DownNormal: TGLvectorf3 = (0, 1, 0); FrontDownLeft: TGLvectorf3 = (-1, -1, -1); FrontDownRight: TGLvectorf3 = (1, -1, -1); FrontUpLeft: TGLvectorf3 = (-1, 1, -1); FrontUpRight: TGLvectorf3 = (1, 1, -1); BackDownLeft: TGLvectorf3 = (-1, -1, 1); BackDownRight: TGLvectorf3 = (1, -1, 1); BackUpLeft: TGLvectorf3 = (-1, 1, 1); BackUpRight: TGLvectorf3 = (1, 1, 1); const NearClipping = 0.1; FarClipping = 200; procedure uzglTriangle(x1, y1, z1, x2, y2, z2, x3, y3, z3: Single); procedure uzglCube; implementation {$R *.dfm} procedure uzglTriangle(x1, y1, z1, x2, y2, z2, x3, y3, z3: Single); begin glBegin(GL_TRIANGLES); glColor3f(0.3, 0, 0); glVertex3f(x1, y1, z1); glColor3f(0.25, 1, 0); glVertex3f(x2, y2, z2); glColor3f(0.7, 0, 1); glVertex3f(x3, y3, z3); glEnd; end; procedure uzglCube; begin glBegin(GL_QUADS); glNormal3fv(@FrontNormal); glVertex3fv(@FrontDownLeft); glVertex3fv(@FrontDownRight); glVertex3fv(@FrontUpRight); glVertex3fv(@FrontUpLeft); glEnd; glBegin(GL_QUADS); glNormal3fv(@LeftNormal); glVertex3fv(@FrontDownLeft); glVertex3fv(@FrontUpLeft); glVertex3fv(@BackUpLeft); glVertex3fv(@BackDownLeft); glEnd; glBegin(GL_QUADS); glNormal3fv(@RightNormal); glVertex3fv(@FrontDownRight); glVertex3fv(@FrontUpRight); glVertex3fv(@BackUpRight); glVertex3fv(@BackDownRight); glEnd; glBegin(GL_QUADS); glNormal3fv(@UpNormal); glVertex3fv(@FrontUpRight); glVertex3fv(@FrontUpLeft); glVertex3fv(@BackUpLeft); glVertex3fv(@BackUpRight); glEnd; glBegin(GL_QUADS); glNormal3fv(@DownNormal); glVertex3fv(@FrontDownRight); glVertex3fv(@FrontDownLeft); glVertex3fv(@BackDownLeft); glVertex3fv(@BackDownRight); glEnd; glBegin(GL_QUADS); glNormal3fv(@BackNormal); glVertex3fv(@BackDownLeft); glVertex3fv(@BackDownRight); glVertex3fv(@BackUpRight); glVertex3fv(@BackUpLeft); glEnd; end; procedure TFMainForm.SetupGL; begin glClearColor(0.3, 0.4, 0.7, 0.0); glEnable(GL_DEPTH_TEST); glEnable(GL_SMOOTH); glDepthFunc(GL_LEQUAL); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glLoadIdentity; gluLookAt(-2, 3, -3, 0, 0, 0, 0, 1, 0); uzglLightEnable; LightPos[0] := 0; LightPos[1] := 0; LightPos[2] := 1; LightPos[3] := 1; end; procedure TFMainForm.uzglLightEnable; begin glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); end; procedure TFMainForm.Render; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix; glRotatef(XRot, 1 В контексте данного фрагмента кода пользователь столкнулся с проблемой при использовании OpenGL и Delphi: при вращении куба свет также вращается вместе с ним, что не является желаемым поведением. Пользователь пытался изменить координаты света в каждом кад Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
|
||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |