OpenGL - 旋转不起作用 [英] OpenGL - Rotation not working

查看:28
本文介绍了OpenGL - 旋转不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我目前有一个我创建的环境,我在其中加载了一些形状(用于参考我所在的位置),并试图让控件向前、向后和旋转我正在看的地方.

I currently have an environment I have created to which I load some shapes (for reference to where I am) and am trying to get the controls to move forward, backwards, and rotate where I am looking.

我使用我的观察点和相机位置点计算了向前和向后.我正在尝试旋转 360 度,但根据我目前的情况似乎得到了一些奇怪的限制.我正在输出我的 xangle 以查看我总是在哪里..

I have the forward and backwards worked out using my lookat point and camera position point. I am trying to rotate 360 degrees but appear to get some strange limits based on what I have so far. I am outputting my xangle to see where I am at always..

为了旋转,我改变了观察变量(x,y, and z),同时保持位置(x,y,z)不变.

In order to rotate, I change the lookat variable (x,y, and z) while keeping the position (x,y,z) the same.

问题

当不断增加角度时,我击中了出现旋转改变方向的两个反射点.无论出于何种原因,这些似乎都发生在 60 度和 300 度,如下所示:

When continuously increasing the angle, I hit two reflection points where the appeared rotation changes direction. For whatever reason these seem to happen at 60 degrees and 300 degrees as shown below:

显然这些角度是不正确的.我已经评估了旋转发生时应该发生的行为,并且计算出的笛卡尔坐标似乎是正确的,但角度的显示是关闭的.

Obviously these angles are not correct. I have evaluated the behavior that should happen as the rotation happens and the calculated Cartesian coordinates seem to be correct but the display of the angle is what is off.

我的 setupviewport 子:

My setupviewport sub:

Private Sub SetupViewport()
    Dim w As Integer = GLcontrol1.Width
    Dim h As Integer = GLcontrol1.Height

    Dim perspective1 As Matrix4 = cam.GetViewMatrix() * Matrix4.CreatePerspectiveFieldOfView(1.3F, GLcontrol1.Width / CSng(GLcontrol1.Height), 0.1F, 2000.0F)


    GL.MatrixMode(MatrixMode.Projection)
    GL.LoadIdentity()
    GL.Ortho(0, w, h, 0, -1, 1)
    GL.LoadMatrix(perspective1)
    GL.MatrixMode(MatrixMode.Modelview)
    GL.LoadIdentity()
    GL.Viewport(0, 0, w, h)
    GL.Enable(EnableCap.DepthTest)
    GL.DepthFunc(DepthFunction.Less)

End Sub

我的相机类:

Class Camera
Public Position As Vector3 = Vector3.Zero
Public Orientation As New Vector3(0.0F, 0.0F, 0.0F)
Public MoveSpeed As Single = 0.2F
Public MouseSensitivity As Single = 0.01F
Public lookat As New Vector3()

Public manual_lookat As Boolean = False

Public invert_y As Boolean = False

Public Function aim_at_origin()
    Position.X = 0
    Position.Y = 0
    Position.Z = 2

    If invert_y = False Then
        Return Matrix4.LookAt(Position, Position + lookat, Vector3.UnitY)
    Else
        Return Matrix4.LookAt(Position, Position + lookat, -Vector3.UnitY)
    End If
End Function




Public Function GetViewMatrix() As Matrix4


    If invert_y = False Then
        Return Matrix4.LookAt(Position, lookat, Vector3.UnitY)
    Else
        Return Matrix4.LookAt(Position, lookat, -Vector3.UnitY)
    End If

End Function

End Class

相机类建立矩阵以与当前矩阵相乘.调用 setupviewport 时,每帧都会发生乘法.

The camera class establishes the matrix to multiply against the current one. The multiplication happens every frame when setupviewport is called.

我不明白为什么它有 300 度和 60 度的反射点.对我来说 180 度或 360 度是有意义的.从视觉上看,似乎旋转区域总共是 45 度.

I can't figure out why it has the reflection points at 300 and 60 degrees. To me 180 degrees or 360 would make sense. It appears like the area of rotation is a total of 45 degrees from visually looking.

我将其标记为 MATH、C# 和 VB .NET,因为答案在大多数编程语言中都是可以接受的.

I am tagging this is MATH, C#, and VB .NET as answers can be acceptable in most programming languages.

为了旋转,我调用这个类:

In order to rotate, I call this class:

Private Sub rotate_view(ByVal delta_camanglex As Single, ByVal delta_camangley As Single)
    Dim curdistance As Single = 1
    curdistance = Math.Sqrt((cam.Position.X - cam.lookat.X) ^ 2 + (cam.Position.Y - cam.lookat.Y) ^ 2 + (cam.Position.Z - cam.lookat.Z) ^ 2)

    Dim invertx As Boolean = False
    Dim inverty As Boolean = False

    camanglex = camanglex + delta_camanglex
    camangley = camangley + delta_camangley

    If camanglex >= 360 Then
        camanglex = camanglex - 360
    End If

    If camangley >= 360 Then
        camangley = camangley - 360
    End If


    If camanglex < 0 Then
        camanglex = camanglex + 360
    End If

    If camangley < 0 Then
        camangley = camangley + 360
    End If

    cam.manual_lookat = True

    Dim sigma As Single = camanglex
    Dim theda As Single = camangley

    lookatx = curdistance * Sin(sigma * (PI / 180)) * Cos((theda) * (PI / 180))



    lookaty = curdistance * Sin((sigma) * (PI / 180)) * Sin((theda) * (PI / 180))

    lookatz = curdistance * Cos((sigma) * (PI / 180))

    cam.lookat.X = lookatx
    cam.lookat.Y = lookaty
    cam.lookat.Z = lookatz

End Sub

推荐答案

不要为此使用欧拉角,因为它们有很多问题,就像您遇到的问题.而是使用累积变换矩阵.看起来这个问题一次又一次地被问到......现在有一段时间了.所以我决定举一个例子来说明如何使用纯 OpenGL 1.0 没有 GLM 或有趣的东西.

Do not use Euler angles for this as they have many issues like the one you got. Instead use cumulative transform matrices. It looks like this question is asked again and again... for some time now. So I decided to make an example how to do it with pure OpenGL 1.0 no GLM or funny stuff.

  1. 定义

让玩家控制名为 obj 的对象和相机 eye.它们中的每一个都应由单独的 4x4 变换矩阵表示.OpenGL 将它们存储为一维数组.欲了解更多信息,请参阅

Lets have Player control-able object called obj and camera eye. Each of them should be represented by separate 4x4 transform matrix. The OpenGL stores them as 1D arrays. For more info see

我们希望在独立于相机视图的本地坐标系中控制 obj.如果您习惯于在 GL_MODELVIEW 中同时将相机和对象矩阵相乘以避免 GL_PROJECTION 矩阵滥用,那么您很快就会意识到这无法通过简单的 glRotate/解决glTranslate 以通常的方式调用.

We want to control obj in its local coordinate system independent on camera view. If you are used to have both camera and object matrices multiplied together in GL_MODELVIEW to avoid GL_PROJECTION matrix abuse then you quickly realize that this is not solvable by simply glRotate/glTranslate calls in usual manner.

因为很多人切换到 Euler 角度,这可以轻松解决这个问题,但带来了一大堆其他问题(如今许多游戏仍在不该使用的地方使用它们,因此存在大量错误和问题).

Because of that many people switch to Euler angles which can handle this easily but brings up a whole bunch of other problems (many nowadays games are still using them where they should not and there are a tons of bugs and issues because of it).

因此将其添加到您的项目中:

So add this to your project:

GLfloat mobj[16],meye[16];

  • 对我们的矩阵使用 GL

    这很简单,只需这样做:

    This is simple just do this:

    glMatrixMode(GL_MODELVIEW); // set matrix target we want to work with does not matter really which)
    glPushMatrix(); // store original matrix so we do not mess something up
    glLoadMatrixf(mobj); // load our matrix into GL
    //here do your stuff like glRotatef(10.0,0.0,1.0,0.0);
    glGetFloatv(GL_MODELVIEW_MATRIX,mobj); // get our updated matrix from GL 
    glPopMatrix(); // restore original state
    

    有了这个,我们可以在渲染循环之外对我们的矩阵使用 GL 调用.(例如在键盘处理程序或某些计时器中).

    With this we can use GL calls for our matrices outside the rendering loop. (for example in keyboard handler or in some timer).

    渲染循环矩阵

    现在,如果我们想用我们的矩阵渲染我们的对象,那么我们需要正确设置 GL 矩阵.假设设置了投影矩阵,那么只有 Modelview 有问题.模型视图矩阵应该是:

    Now if we want to render our object with our matrices then we need to set the GL matrices properly. Let assume Projection matrix is set then just Modelview is in question. The modelview matrix should be:

    GL_MODELVIEW = Inverse(meye) * mobj
    

    但是OpenGL没有任何矩阵逆函数.所以这是我们唯一需要编码的东西.由于矩阵总是4x4,所以它并不难.

    But OpenGL does not have any matrix inverse function. So this is the only thing we need to code. As the matrix is always 4x4 then it is not that hard.

    我把所有这些放在一个简单的 GL/C++/VCL 示例中:

    //---------------------------------------------------------------------------
    #include <vcl.h>        // you can ignore this
    #include <gl/gl.h>
    #include <gl/glu.h>
    #pragma hdrstop         // you can ignore this
    #include "Unit1.h"      // you can ignore this
    //---------------------------------------------------------------------------
    // you can ignore this
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    // here some global variables
    int     xs,ys;          // window resolution
    HDC     hdc;            // device context
    HGLRC   hrc;            // rendering context
    // 4x4 transform matrices
    GLfloat mobj[16];   // object transform matrix
    GLfloat meye[16];   // camera transform matrix
    // key codes for controling (Arrows + Space)
    WORD key_left =37;
    WORD key_right=39;
    WORD key_up   =38;
    WORD key_down =40;
    WORD key_forw =32;
    // key pressed state
    bool _left =false;
    bool _right=false;
    bool _up   =false;
    bool _down =false;
    bool _forw =false;
    bool _shift=false;
    // sceene need repaint?
    bool _redraw=true;
    //---------------------------------------------------------------------------
    // here inverse matrix computation
    GLfloat matrix_subdet   (         GLfloat *a,int r,int s)
            {
            GLfloat   c,q[9];
            int     i,j,k;
            k=0;                            // q = sub matrix
            for (j=0;j<4;j++)
             if (j!=s)
              for (i=0;i<4;i++)
               if (i!=r)
                    {
                    q[k]=a[i+(j<<2)];
                    k++;
                    }
            c=0;
            c+=q[0]*q[4]*q[8];
            c+=q[1]*q[5]*q[6];
            c+=q[2]*q[3]*q[7];
            c-=q[0]*q[5]*q[7];
            c-=q[1]*q[3]*q[8];
            c-=q[2]*q[4]*q[6];
            if (int((r+s)&1)) c=-c;       // add signum
            return c;
            }
    void  matrix_subdet    (GLfloat *c,GLfloat *a)
            {
            GLfloat   q[16];
            int     i,j;
            for (i=0;i<4;i++)
             for (j=0;j<4;j++)
              q[j+(i<<2)]=matrix_subdet(a,i,j);
            for (i=0;i<16;i++) c[i]=q[i];
            }
    GLfloat matrix_det       (         GLfloat *a)
            {
            GLfloat c=0;
            c+=a[ 0]*matrix_subdet(a,0,0);
            c+=a[ 4]*matrix_subdet(a,0,1);
            c+=a[ 8]*matrix_subdet(a,0,2);
            c+=a[12]*matrix_subdet(a,0,3);
            return c;
            }
    GLfloat matrix_det       (         GLfloat *a,GLfloat *b)
            {
            GLfloat c=0;
            c+=a[ 0]*b[ 0];
            c+=a[ 4]*b[ 1];
            c+=a[ 8]*b[ 2];
            c+=a[12]*b[ 3];
            return c;
            }
    void  matrix_inv       (GLfloat *c,GLfloat *a)
            {
            GLfloat   d[16],D;
            matrix_subdet(d,a);
            D=matrix_det(a,d);
            if (D) D=1.0/D;
            for (int i=0;i<16;i++) c[i]=d[i]*D;
            }
    //---------------------------------------------------------------------------
    // here OpenGL stuff
    //---------------------------------------------------------------------------
    int TForm1::ogl_init()
        {
        // just init OpenGL
        if (ogl_inicialized) return 1;
        hdc = GetDC(Form1->Handle);             // get device context
        PIXELFORMATDESCRIPTOR pfd;
        ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
        pfd.nSize = sizeof( pfd );
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
        pfd.cDepthBits = 24;
        pfd.iLayerType = PFD_MAIN_PLANE;
        SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
        hrc = wglCreateContext(hdc);            // create current rendering context
        if(hrc == NULL)
                {
                ShowMessage("Could not initialize OpenGL Rendering context !!!");
                ogl_inicialized=0;
                return 0;
                }
        if(wglMakeCurrent(hdc, hrc) == false)
                {
                ShowMessage("Could not make current OpenGL Rendering context !!!");
                wglDeleteContext(hrc);          // destroy rendering context
                ogl_inicialized=0;
                return 0;
                }
        ogl_resize();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_BLEND);
        glShadeModel(GL_SMOOTH);
        ogl_inicialized=1;
        return 1;
        }
    //---------------------------------------------------------------------------
    void TForm1::ogl_exit()
        {
        // just exit from OpneGL
        if (!ogl_inicialized) return;
        wglMakeCurrent(NULL, NULL);     // release current rendering context
        wglDeleteContext(hrc);          // destroy rendering context
        ogl_inicialized=0;
        }
    //---------------------------------------------------------------------------
    void TForm1::ogl_draw()
        {
        // rendering routine
        _redraw=false;
    
        // here the whole rendering
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);   // background color
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        GLfloat ieye[16];   // inverse camera transform matrix
        matrix_inv(ieye,meye);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadMatrixf(ieye);
        glMultMatrixf(mobj);
    
        // render player controlable object
        // centered by (0,0,0)
        // +z forward, +x right, +y up
        float x=0.5,y=0.1,z=0.7;    // half sizes of object
        glColor3f(0.7,0.7,0.7);
        glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0,0.0,+z);
        glVertex3f( -x,-y,-z);
        glVertex3f( +x,-y,-z);
        glVertex3f(0.0,+y,-z);
        glVertex3f( -x,-y,-z);
        glEnd();
        glColor3f(0.5,0.5,0.5);
        glBegin(GL_TRIANGLES);
        glVertex3f( -x,-y,-z);
        glVertex3f( +x,-y,-z);
        glVertex3f(0.0,+y,-z);
        glEnd();
        // render x,y,z axises as r,g,b lines
        glBegin(GL_LINES);
        glColor3f(1.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(1.0,0.0,0.0);
        glColor3f(0.0,1.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,1.0,0.0);
        glColor3f(0.0,0.0,1.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,0.0,1.0);
        glEnd();
    
        glFlush();
        SwapBuffers(hdc);
        }
    //---------------------------------------------------------------------------
    void TForm1::ogl_resize()
        {
        xs=ClientWidth;
        ys=ClientHeight;
        if (xs<=0) xs = 1;                  // Prevent a divide by zero
        if (ys<=0) ys = 1;
        if (!ogl_inicialized) return;
        glViewport(0,0,xs,ys);              // Set Viewport to window dimensions
        glMatrixMode(GL_PROJECTION);        // use projection matrix
        glLoadIdentity();                   // set it to unit matrix
        gluPerspective(30,float(xs)/float(ys),0.1,100.0); // perspective projection 30 degrees FOV and 0.1 focal length view depth 100-0.1
        glMatrixMode(GL_TEXTURE);           // use texture matrix
        glLoadIdentity();                   // set it to unit matrix
        glMatrixMode(GL_MODELVIEW);         // use modelview marix
        glLoadIdentity();                   // set it to unit matrix
        }
    //---------------------------------------------------------------------------
    // here window stuff
    //---------------------------------------------------------------------------
    // window constructor
    __fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
        {
        ogl_inicialized=0;
        hdc=NULL;
        hrc=NULL;
        ogl_init();
    
        // init matrices
        glMatrixMode(GL_MODELVIEW);
        // object is at (0,0,0) rotatet so Z+ is pointing to screen
        glLoadIdentity();
        glRotatef(180.0,0.0,1.0,0.0);
        glGetFloatv(GL_MODELVIEW_MATRIX,mobj);
        // camera is behind object looking at object
        glLoadIdentity();
        glTranslatef(0.0,0.0,+20.0);
        glGetFloatv(GL_MODELVIEW_MATRIX,meye);
        }
    //---------------------------------------------------------------------------
    // window destructor
    void __fastcall TForm1::FormDestroy(TObject *Sender)
        {
        ogl_exit();
        }
    //---------------------------------------------------------------------------
    // common window events
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormResize(TObject *Sender)
        {
        ogl_resize();
        _redraw=true;
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormPaint(TObject *Sender)
        {
        _redraw=true;
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::tim_updateTimer(TObject *Sender)
        {
        // here movement and repaint timer handler (I have 20ms interval)
    
        GLfloat da=5.0; // angular turn speed in [deg/timer_iteration]
        GLfloat dp=0.1; // movement speed in [world_units/timer_iteration]
    
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
    
        if (_shift) // if Shift pressed control camera
            {
            // copy meye to GL
            glLoadMatrixf(meye);
            // handle keyboard with GL functions
            if (_left ) { _redraw=true; glRotatef(+da,0.0,1.0,0.0); }
            if (_right) { _redraw=true; glRotatef(-da,0.0,1.0,0.0); }
            if (_up   ) { _redraw=true; glRotatef(-da,1.0,0.0,0.0); }
            if (_down ) { _redraw=true; glRotatef(+da,1.0,0.0,0.0); }
            // obtain meye from GL
            glGetFloatv(GL_MODELVIEW_MATRIX,meye);
            }
        else{ // else control object
            // copy meye to GL
            glLoadMatrixf(mobj);
            // handle keyboard with GL functions
            if (_left ) { _redraw=true; glRotatef(+da,0.0,1.0,0.0); }
            if (_right) { _redraw=true; glRotatef(-da,0.0,1.0,0.0); }
            if (_up   ) { _redraw=true; glRotatef(-da,1.0,0.0,0.0); }
            if (_down ) { _redraw=true; glRotatef(+da,1.0,0.0,0.0); }
            // obtain mobj from GL
            glGetFloatv(GL_MODELVIEW_MATRIX,mobj);
            }
    
        glPopMatrix();
        // handle keyboard directly
        if (_forw )
            {
            _redraw=true;
            mobj[12]+=dp*mobj[8];       // mobj[12,13,14] is object position
            mobj[13]+=dp*mobj[9];       // mobj[8,9,10] is object Z axis direction vector
            mobj[14]+=dp*mobj[10];      // if not glScale is used then it is unit in size
            }
    
        // render if needed
        if (_redraw) ogl_draw();
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
        {
        // move camera matrix forward
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadMatrixf(meye);
        glTranslatef(0,0,+2.0);
        glGetFloatv(GL_MODELVIEW_MATRIX,meye);
        glPopMatrix();
        Handled=true;
        _redraw=true;
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
        {
        // move camera matrix backward
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadMatrixf(meye);
        glTranslatef(0,0,-2.0);
        glGetFloatv(GL_MODELVIEW_MATRIX,meye);
        glPopMatrix();
        Handled=true;
        _redraw=true;
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,TShiftState Shift)
        {
        _shift=Shift.Contains(ssShift);
        // on key down event
        if (Key==key_left ) _left =true;
        if (Key==key_right) _right=true;
        if (Key==key_up   ) _up   =true;
        if (Key==key_down ) _down =true;
        if (Key==key_forw ) _forw =true;
        Key=0;  // key is handled
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
        {
        _shift=Shift.Contains(ssShift);
        // on key release event
        if (Key==key_left ) _left =false;
        if (Key==key_right) _right=false;
        if (Key==key_up   ) _up   =false;
        if (Key==key_down ) _down =false;
        if (Key==key_forw ) _forw =false;
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormActivate(TObject *Sender)
        {
        _left =false; // clear key flags after focus change
        _right=false; // just to avoid constantly "pressed" keys
        _up   =false; // after window focus swaping during key press
        _down =false; // many games are ignoring this and you need to
        _forw =false; // press&release the stuck key again to stop movement ...
        }
    //---------------------------------------------------------------------------
    

    这是一个简单的单形式 VCL 应用程序,其中包含一个 20 毫秒的计时器.因此,将事件移植到您的环境样式代码中.您可以忽略 VCL 编译指示和包含.这个例子是由箭头驱动的.如果按下 shift 则箭头正在转动相机否则物体.空间正在向前移动物体.

    It is simple single form VCL application with single 20ms timer in it. So port the events to your environment style code. You can ignore the VCL pragmas and includes. This example is driven by arrows. If shift is pressed then the arrows are turning camera otherwise the object. Space is moving object forward.

    这里编译的Win32独立演示:

    这种方法有一个缺点

    随着变换的累积,您会失去精度.为了解决这个问题,您可以利用向量乘法(叉积).只需计算对此类矩阵执行的操作次数,如果达到阈值,则对矩阵进行归一化并重置计数器.

    With cumulating the transforms you are loosing precision. To remedy that you can exploit vector multiplication (cross product). Simply count the number of operations performed on such matrix and if threshold is reached normalize the matrix and reset the counter.

    归一化我的意思是确保所有的轴都是单位并且彼此垂直,保持主轴的方向(通常是视图或物体的前方)保持原样.2 个向量的叉积返回每个向量的垂直向量.例如,如果您提取 X,Y,Z 轴(位置在 #1 中的链接中描述)并且 Z 是主要的然后轴:

    By normalization I mean ensuring all the axises are unit and perpendicular to each other Leaving the direction of main axis (usually forward of view or object) as is. Cross product of 2 vectors returns perpendicular vector to each. So for example if you extract the X,Y,Z axises (locations are described in the link in #1) and Z is the main axis then:

    X = Y x Z
    Y = Z x X
    Z = Z / |Z|
    X = X / |X|
    Y = Y / |Y|
    

    地点:

    // cross product: W = U x V
    W.x=(U.y*V.z)-(U.z*V.y)
    W.y=(U.z*V.x)-(U.x*V.z)
    W.z=(U.x*V.y)-(U.y*V.x)
    // dot product: a = (U.V)
    a=U.x*V.x+U.y*V.y+U.z*V.z
    // abs of vector a = |U|
    a=sqrt((U.x*U.x)+(U.y*U.y)+(U.z*U.z))
    

    如果您的坐标系不是从单位矩阵派生的,那么您需要否定某些轴或更改叉积操作数的顺序,以确保轴的方向保持原样.

    In case your coordinate system is not derived from unit matrix then you need to negate some axis or change the order of cross product operands to ensure the direction of your axises stays as should.

    有关更多信息,请查看:

    For more info take a look at:

    这篇关于OpenGL - 旋转不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆