OpenGL中的轨迹球问题
OpenGL鼠標(biāo)軌跡球(Trackball)原理
什么是鼠標(biāo)軌跡球
類似AutoCAD里的“動(dòng)態(tài)觀察”,三維模型都是要投影到二維的屏幕上才能顯示給用戶,而用戶如果想觀察一下三維模型的立體形狀使用“動(dòng)態(tài)觀察”是再好不過(guò)了。我們一般的操作是這樣的:鼠標(biāo)(按中健或者其他健)在二維屏幕上拖動(dòng),之后三維模型就會(huì)以屏幕中心點(diǎn)為中心進(jìn)行相應(yīng)的旋轉(zhuǎn),鼠標(biāo)拖動(dòng)得越長(zhǎng),三維模型旋轉(zhuǎn)的角度就越大。AutoCAD這種重量級(jí)的商業(yè)軟件在這方面的用戶體驗(yàn)自然是非常完美的了,可你知道它的原理么,如果自己用OpenGL如果實(shí)現(xiàn)呢?
OpenGL里的軌跡球
計(jì)算機(jī)的三維顯示類似生活中的攝影,屏幕就是一個(gè)相機(jī),三維模型就是被攝物體。我們可以調(diào)整相機(jī)與被攝物之間的距離來(lái)在屏幕顯示不同大小影像。軌跡球就是在屏幕之外虛構(gòu)一個(gè)球形曲面,使鼠標(biāo)在二維屏幕上的移動(dòng)投影到球形曲面上,這樣就能得到更佳的用戶體驗(yàn)(不使用軌跡球也能實(shí)現(xiàn)動(dòng)態(tài)觀察,只是效果很生硬)。
以屏幕為中心為球心,x軸向右,Y軸向上,z軸向屏幕之外,很容易建立一個(gè)球體的幾何方程如下:
x2+y2+z2=r2x2+y2+z2=r2 這里,r代表球體的半徑。當(dāng)鼠標(biāo)在球面的范圍內(nèi)移動(dòng)時(shí),我們可以由鼠標(biāo)在二維屏幕上的二維點(diǎn)坐標(biāo)P(x,y)通過(guò)數(shù)學(xué)關(guān)系求得其在球面上的投影點(diǎn)P',鼠標(biāo)從P1點(diǎn)移動(dòng)到P2點(diǎn),對(duì)應(yīng)的在球面上就是從P1'移動(dòng)到P2'。P1'和P2'與球心之間可以形成兩個(gè)向量,鼠標(biāo)移動(dòng)轉(zhuǎn)化成了向量從V1(OP1'向量)轉(zhuǎn)到V2(OP2'向量),V1和V2的向量叉乘得到向量N即是三維物體的旋轉(zhuǎn)軸,V1到V2的轉(zhuǎn)角量就是三維物體的旋轉(zhuǎn)角度。
使軌跡球更連續(xù)
實(shí)際的屏幕是個(gè)矩形,而球體在平面的投影只會(huì)是個(gè)圓,因此只要軌跡球的半徑不是無(wú)限大,就總會(huì)有一些區(qū)域的點(diǎn)投影后會(huì)落在球面之外。此時(shí)怎么辦呢?
一個(gè)好的辦法就是在球體投影不能覆蓋的區(qū)域使用另外一個(gè)曲面與之拼接。一個(gè)現(xiàn)成的二次曲面能夠勝任,它的表達(dá)式如下:
z(x,y)=r2/2x2+y2??????√? ? ?
這個(gè)曲面與球面的交線正好一個(gè)圓(下圖中所示紅線),其半徑為r/2–√r/2。
經(jīng)過(guò)這樣處理的軌跡球就比較平滑,于是整個(gè)坐標(biāo)計(jì)算過(guò)程如下:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
由于一般安裝opengl時(shí),并沒(méi)有包含glew32.dll和頭文件及.lib文件,所以要先將相關(guān)文件包含到相關(guān)目錄中,這里給出glew的下載鏈接:點(diǎn)擊打開(kāi)鏈接點(diǎn)擊打開(kāi)鏈接
這里給出實(shí)現(xiàn)軌跡球的代碼
ArcBall.h:
#include "StdAfx.h"#ifndef _ArcBall_h #define _ArcBall_h#include <stdlib.h>// 僅在Debug模式下,啟用斷言 #ifdef _DEBUG # include "assert.h" #else # define assert(x) { } #endif//2維點(diǎn) typedef union Tuple2f_t {struct{GLfloat X, Y;} s;GLfloat T[2]; } Tuple2fT; //3維點(diǎn) typedef union Tuple3f_t {struct{GLfloat X, Y, Z;} s;GLfloat T[3]; } Tuple3fT; //4維點(diǎn) typedef union Tuple4f_t {struct{GLfloat X, Y, Z, W;} s;GLfloat T[4]; } Tuple4fT; //3x3矩陣 typedef union Matrix3f_t {struct{//column majorunion { GLfloat M00; GLfloat XX; GLfloat SX; }; union { GLfloat M10; GLfloat XY; }; union { GLfloat M20; GLfloat XZ; }; union { GLfloat M01; GLfloat YX; }; union { GLfloat M11; GLfloat YY; GLfloat SY; }; union { GLfloat M21; GLfloat YZ; }; union { GLfloat M02; GLfloat ZX; }; union { GLfloat M12; GLfloat ZY; }; union { GLfloat M22; GLfloat ZZ; GLfloat SZ; }; } s;GLfloat M[9]; } Matrix3fT; //4x4矩陣 typedef union Matrix4f_t {struct{//column majorunion { GLfloat M00; GLfloat XX; GLfloat SX; }; union { GLfloat M10; GLfloat XY; }; union { GLfloat M20; GLfloat XZ; }; union { GLfloat M30; GLfloat XW; }; union { GLfloat M01; GLfloat YX; }; union { GLfloat M11; GLfloat YY; GLfloat SY; }; union { GLfloat M21; GLfloat YZ; }; union { GLfloat M31; GLfloat YW; }; union { GLfloat M02; GLfloat ZX; }; union { GLfloat M12; GLfloat ZY; }; union { GLfloat M22; GLfloat ZZ; GLfloat SZ; }; union { GLfloat M32; GLfloat ZW; }; union { GLfloat M03; GLfloat TX; }; union { GLfloat M13; GLfloat TY; }; union { GLfloat M23; GLfloat TZ; }; union { GLfloat M33; GLfloat TW; GLfloat SW; }; } s;GLfloat M[16]; } Matrix4fT; //定義類型的別名 #define Point2fT Tuple2fT #define Quat4fT Tuple4fT #define Vector2fT Tuple2fT #define Vector3fT Tuple3fT #define FuncSqrt sqrtf # define Epsilon 1.0e-5//2維點(diǎn)相加 inlinestatic void Point2fAdd(Point2fT* NewObj, const Tuple2fT* t1) {assert(NewObj && t1);NewObj->s.X += t1->s.X;NewObj->s.Y += t1->s.Y; }//2維點(diǎn)相減 inlinestatic void Point2fSub(Point2fT* NewObj, const Tuple2fT* t1) {assert(NewObj && t1);NewObj->s.X -= t1->s.X;NewObj->s.Y -= t1->s.Y; }//3維點(diǎn)矢積 inlinestatic void Vector3fCross(Vector3fT* NewObj, const Vector3fT* v1, const Vector3fT* v2) {Vector3fT Result; assert(NewObj && v1 && v2);Result.s.X = (v1->s.Y * v2->s.Z) - (v1->s.Z * v2->s.Y);Result.s.Y = (v1->s.Z * v2->s.X) - (v1->s.X * v2->s.Z);Result.s.Z = (v1->s.X * v2->s.Y) - (v1->s.Y * v2->s.X);*NewObj = Result; }//3維點(diǎn)點(diǎn)積 inlinestatic GLfloat Vector3fDot(const Vector3fT* NewObj, const Vector3fT* v1) {assert(NewObj && v1);return (NewObj->s.X * v1->s.X) +(NewObj->s.Y * v1->s.Y) +(NewObj->s.Z * v1->s.Z); }//3維點(diǎn)的長(zhǎng)度的平方 inlinestatic GLfloat Vector3fLengthSquared(const Vector3fT* NewObj) {assert(NewObj);return (NewObj->s.X * NewObj->s.X) +(NewObj->s.Y * NewObj->s.Y) +(NewObj->s.Z * NewObj->s.Z); }//3維點(diǎn)的長(zhǎng)度 inlinestatic GLfloat Vector3fLength(const Vector3fT* NewObj) {assert(NewObj);return FuncSqrt(Vector3fLengthSquared(NewObj)); }//設(shè)置3x3矩陣為0矩陣 inlinestatic void Matrix3fSetZero(Matrix3fT* NewObj) {NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 = NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 = NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = 0.0f; }//設(shè)置4x4矩陣為0矩陣 inlinestatic void Matrix4fSetZero(Matrix4fT* NewObj) {NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 = NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 = NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = NewObj->s.M30 = NewObj->s.M31 = NewObj->s.M32 = 0.0f; }//設(shè)置3x3矩陣為單位矩陣 inlinestatic void Matrix3fSetIdentity(Matrix3fT* NewObj) {Matrix3fSetZero(NewObj);NewObj->s.M00 = NewObj->s.M11 = NewObj->s.M22 = 1.0f; }//設(shè)置4x4矩陣為單位矩陣 inlinestatic void Matrix4fSetIdentity(Matrix4fT* NewObj) {Matrix4fSetZero(NewObj);NewObj->s.M00 = 1.0f;NewObj->s.M11 = 1.0f;NewObj->s.M22 = 1.0f;NewObj->s.M33=1.0f; }//從四元數(shù)設(shè)置旋轉(zhuǎn)矩陣 inlinestatic void Matrix3fSetRotationFromQuat4f(Matrix3fT* NewObj, const Quat4fT* q1) {GLfloat n, s;GLfloat xs, ys, zs;GLfloat wx, wy, wz;GLfloat xx, xy, xz;GLfloat yy, yz, zz;assert(NewObj && q1);n = (q1->s.X * q1->s.X) + (q1->s.Y * q1->s.Y) + (q1->s.Z * q1->s.Z) + (q1->s.W * q1->s.W);s = (n > 0.0f) ? (2.0f / n) : 0.0f;xs = q1->s.X * s; ys = q1->s.Y * s; zs = q1->s.Z * s;wx = q1->s.W * xs; wy = q1->s.W * ys; wz = q1->s.W * zs;xx = q1->s.X * xs; xy = q1->s.X * ys; xz = q1->s.X * zs;yy = q1->s.Y * ys; yz = q1->s.Y * zs; zz = q1->s.Z * zs;NewObj->s.XX = 1.0f - (yy + zz); NewObj->s.YX = xy - wz; NewObj->s.ZX = xz + wy;NewObj->s.XY = xy + wz; NewObj->s.YY = 1.0f - (xx + zz); NewObj->s.ZY = yz - wx;NewObj->s.XZ = xz - wy; NewObj->s.YZ = yz + wx; NewObj->s.ZZ = 1.0f - (xx + yy); }//3x3矩陣相乘 inlinestatic void Matrix3fMulMatrix3f(Matrix3fT* NewObj, const Matrix3fT* m1) {Matrix3fT Result; assert(NewObj && m1);Result.s.M00 = (NewObj->s.M00 * m1->s.M00) + (NewObj->s.M01 * m1->s.M10) + (NewObj->s.M02 * m1->s.M20);Result.s.M01 = (NewObj->s.M00 * m1->s.M01) + (NewObj->s.M01 * m1->s.M11) + (NewObj->s.M02 * m1->s.M21);Result.s.M02 = (NewObj->s.M00 * m1->s.M02) + (NewObj->s.M01 * m1->s.M12) + (NewObj->s.M02 * m1->s.M22);Result.s.M10 = (NewObj->s.M10 * m1->s.M00) + (NewObj->s.M11 * m1->s.M10) + (NewObj->s.M12 * m1->s.M20);Result.s.M11 = (NewObj->s.M10 * m1->s.M01) + (NewObj->s.M11 * m1->s.M11) + (NewObj->s.M12 * m1->s.M21);Result.s.M12 = (NewObj->s.M10 * m1->s.M02) + (NewObj->s.M11 * m1->s.M12) + (NewObj->s.M12 * m1->s.M22);Result.s.M20 = (NewObj->s.M20 * m1->s.M00) + (NewObj->s.M21 * m1->s.M10) + (NewObj->s.M22 * m1->s.M20);Result.s.M21 = (NewObj->s.M20 * m1->s.M01) + (NewObj->s.M21 * m1->s.M11) + (NewObj->s.M22 * m1->s.M21);Result.s.M22 = (NewObj->s.M20 * m1->s.M02) + (NewObj->s.M21 * m1->s.M12) + (NewObj->s.M22 * m1->s.M22);*NewObj = Result; }//4x4矩陣相乘 inlinestatic void Matrix4fSetRotationScaleFromMatrix4f(Matrix4fT* NewObj, const Matrix4fT* m1) {assert(NewObj && m1);NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ; }//進(jìn)行矩陣的奇異值分解,旋轉(zhuǎn)矩陣被保存到rot3和rot4中,返回矩陣的縮放因子 inlinestatic GLfloat Matrix4fSVD(const Matrix4fT* NewObj, Matrix3fT* rot3, Matrix4fT* rot4) {GLfloat s, n;assert(NewObj);s = FuncSqrt(( (NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) + (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) +(NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ) ) / 3.0f );if (rot3) {rot3->s.XX = NewObj->s.XX; rot3->s.XY = NewObj->s.XY; rot3->s.XZ = NewObj->s.XZ;rot3->s.YX = NewObj->s.YX; rot3->s.YY = NewObj->s.YY; rot3->s.YZ = NewObj->s.YZ;rot3->s.ZX = NewObj->s.ZX; rot3->s.ZY = NewObj->s.ZY; rot3->s.ZZ = NewObj->s.ZZ;n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) +(NewObj->s.XY * NewObj->s.XY) +(NewObj->s.XZ * NewObj->s.XZ) );rot3->s.XX *= n;rot3->s.XY *= n;rot3->s.XZ *= n;n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) +(NewObj->s.YY * NewObj->s.YY) +(NewObj->s.YZ * NewObj->s.YZ) );rot3->s.YX *= n;rot3->s.YY *= n;rot3->s.YZ *= n;n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) +(NewObj->s.ZY * NewObj->s.ZY) +(NewObj->s.ZZ * NewObj->s.ZZ) );rot3->s.ZX *= n;rot3->s.ZY *= n;rot3->s.ZZ *= n;}if (rot4) {if (rot4 != NewObj){Matrix4fSetRotationScaleFromMatrix4f(rot4, NewObj); }n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) +(NewObj->s.XY * NewObj->s.XY) +(NewObj->s.XZ * NewObj->s.XZ) );rot4->s.XX *= n;rot4->s.XY *= n;rot4->s.XZ *= n;n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) +(NewObj->s.YY * NewObj->s.YY) +(NewObj->s.YZ * NewObj->s.YZ) );rot4->s.YX *= n;rot4->s.YY *= n;rot4->s.YZ *= n;n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) +(NewObj->s.ZY * NewObj->s.ZY) +(NewObj->s.ZZ * NewObj->s.ZZ) );rot4->s.ZX *= n;rot4->s.ZY *= n;rot4->s.ZZ *= n;}return s; }//從3x3矩陣變?yōu)?x4的旋轉(zhuǎn)矩陣 inlinestatic void Matrix4fSetRotationScaleFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) {assert(NewObj && m1);NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ; }//4x4矩陣的與標(biāo)量的乘積 inlinestatic void Matrix4fMulRotationScale(Matrix4fT* NewObj, GLfloat scale) {assert(NewObj);NewObj->s.XX *= scale; NewObj->s.YX *= scale; NewObj->s.ZX *= scale;NewObj->s.XY *= scale; NewObj->s.YY *= scale; NewObj->s.ZY *= scale;NewObj->s.XZ *= scale; NewObj->s.YZ *= scale; NewObj->s.ZZ *= scale; }//設(shè)置旋轉(zhuǎn)矩陣 inlinestatic void Matrix4fSetRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) {GLfloat scale;assert(NewObj && m1);scale = Matrix4fSVD(NewObj, NULL, NULL);Matrix4fSetRotationScaleFromMatrix3f(NewObj, m1);Matrix4fMulRotationScale(NewObj, scale); }typedef class ArcBall_t { protected://把二維點(diǎn)映射到三維點(diǎn)inlinevoid _mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const;public://構(gòu)造/析構(gòu)函數(shù)ArcBall_t(GLfloat NewWidth, GLfloat NewHeight);~ArcBall_t() { };//設(shè)置邊界inlinevoid setBounds(GLfloat NewWidth, GLfloat NewHeight){assert((NewWidth > 1.0f) && (NewHeight > 1.0f));//設(shè)置長(zhǎng)寬的調(diào)整因子this->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);this->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);}//鼠標(biāo)點(diǎn)擊void click(const Point2fT* NewPt);//鼠標(biāo)拖動(dòng)計(jì)算旋轉(zhuǎn)void drag(const Point2fT* NewPt, Quat4fT* NewRot);//更新鼠標(biāo)狀態(tài)void upstate();//void mousemove(WPARAM wParam,LPARAM lParam);protected:Vector3fT StVec; //保存鼠標(biāo)點(diǎn)擊的坐標(biāo)Vector3fT EnVec; //保存鼠標(biāo)拖動(dòng)的坐標(biāo)GLfloat AdjustWidth; //寬度的調(diào)整因子GLfloat AdjustHeight; //長(zhǎng)度的調(diào)整因子 public:Matrix4fT Transform; //計(jì)算變換 Matrix3fT LastRot; //上一次的旋轉(zhuǎn) Matrix3fT ThisRot; //這次的旋轉(zhuǎn)float zoomRate;float lastZoomRate;bool isDragging; // 是否拖動(dòng)bool isRClicked; // 是否右擊鼠標(biāo)bool isClicked; // 是否點(diǎn)擊鼠標(biāo)bool isZooming; //是否正在縮放Point2fT LastPt; Matrix4fT origTransform;Point2fT MousePt; // 當(dāng)前的鼠標(biāo)位置} ArcBallT;#endifArcBall.cpp:文件 /** KempoApi: The Turloc Toolkit *****************************/ /** * * **/ /** ** ** Filename: ArcBall.cpp **/ /** ** Version: Common **/ /** ** **/ /** **/ /** Arcball class for mouse manipulation. **/ /** **/ /** **/ /** **/ /** **/ /** (C) 1999-2003 Tatewake.com **/ /** History: **/ /** 08/17/2003 - (TJG) - Creation **/ /** 09/23/2003 - (TJG) - Bug fix and optimization **/ /** 09/25/2003 - (TJG) - Version for NeHe Basecode users **/ /** **/ /*************************************************************/ // #include "StdAfx.h" #include <windows.h> #include <GL/glew.h> #include <math.h> #include "ArcBall.h" //軌跡球參數(shù): //直徑 2.0f //半徑 1.0f //半徑平方 1.0fvoid ArcBall_t::_mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const {Point2fT TempPt;GLfloat length;//復(fù)制到臨時(shí)變量TempPt = *NewPt;//把長(zhǎng)寬調(diào)整到[-1 ... 1]區(qū)間TempPt.s.X = (TempPt.s.X * this->AdjustWidth) - 1.0f;TempPt.s.Y = 1.0f - (TempPt.s.Y * this->AdjustHeight);//計(jì)算長(zhǎng)度的平方length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y);//如果點(diǎn)映射到球的外面if (length > 1.0f){GLfloat norm;//縮放到球上norm = 1.0f / FuncSqrt(length);//設(shè)置z坐標(biāo)為0NewVec->s.X = TempPt.s.X * norm;NewVec->s.Y = TempPt.s.Y * norm;NewVec->s.Z = 0.0f;}//如果在球內(nèi)else {//利用半徑的平方為1,求出z坐標(biāo)NewVec->s.X = TempPt.s.X;NewVec->s.Y = TempPt.s.Y;NewVec->s.Z = FuncSqrt(1.0f - length);} }ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight) {this->StVec.s.X = 0.0f;this->StVec.s.Y = 0.0f;this->StVec.s.Z = 0.0f;this->EnVec.s.X = 0.0f;this->EnVec.s.Y = 0.0f;this->EnVec.s.Z = 0.0f;Matrix4fSetIdentity(&Transform);Matrix3fSetIdentity(&LastRot);Matrix3fSetIdentity(&ThisRot);this->isDragging=false;this->isClicked= false;this->isRClicked = false;this->isZooming = false;this->zoomRate = 1;this->setBounds(NewWidth, NewHeight); }void ArcBall_t::upstate() {if(!this->isZooming && this->isRClicked){ // 開(kāi)始拖動(dòng)this->isZooming = true; // 設(shè)置拖動(dòng)為變量為true this->LastPt = this->MousePt;this->lastZoomRate = this->zoomRate;}else if(this->isZooming){//正在拖動(dòng)if(this->isRClicked){ //拖動(dòng) Point2fSub(&this->MousePt, &this->LastPt);this->zoomRate = this->lastZoomRate + this->MousePt.s.X * this->AdjustWidth * 2;}else{ //停止拖動(dòng)this->isZooming = false;}}else if (!this->isDragging && this->isClicked){ // 如果沒(méi)有拖動(dòng)this->isDragging = true; // 設(shè)置拖動(dòng)為變量為truethis->LastRot = this->ThisRot; this->click(&this->MousePt); }else if(this->isDragging){if (this->isClicked){ //如果按住拖動(dòng)Quat4fT ThisQuat;this->drag(&this->MousePt, &ThisQuat); // 更新軌跡球的變量Matrix3fSetRotationFromQuat4f(&this->ThisRot, &ThisQuat); // 計(jì)算旋轉(zhuǎn)量Matrix3fMulMatrix3f(&this->ThisRot, &this->LastRot); Matrix4fSetRotationFromMatrix3f(&this->Transform, &this->ThisRot); }else // 如果放開(kāi)鼠標(biāo),設(shè)置拖動(dòng)為falsethis->isDragging = false;} }//按下鼠標(biāo),記錄當(dāng)前對(duì)應(yīng)的軌跡球的位置 void ArcBall_t::click(const Point2fT* NewPt) {this->_mapToSphere(NewPt, &this->StVec); }//鼠標(biāo)拖動(dòng),計(jì)算旋轉(zhuǎn)四元數(shù) void ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot) {//新的位置this->_mapToSphere(NewPt, &this->EnVec);//計(jì)算旋轉(zhuǎn)if (NewRot){Vector3fT Perp;//計(jì)算旋轉(zhuǎn)軸Vector3fCross(&Perp, &this->StVec, &this->EnVec);//如果不為0if (Vector3fLength(&Perp) > Epsilon) {//記錄旋轉(zhuǎn)軸NewRot->s.X = Perp.s.X;NewRot->s.Y = Perp.s.Y;NewRot->s.Z = Perp.s.Z;//在四元數(shù)中,w=cos(a/2),a為旋轉(zhuǎn)的角度NewRot->s.W= Vector3fDot(&this->StVec, &this->EnVec);}//是0,說(shuō)明沒(méi)有旋轉(zhuǎn)else {NewRot->s.X = NewRot->s.Y = NewRot->s.Z = NewRot->s.W = 0.0f;}} } sample.cpp: #include "StdAfx.h" #pragma comment( lib, "opengl32.lib" ) #pragma comment( lib, "glut32.lib") #pragma comment( lib, "glew32.lib") #include <GL/glew.h> #include <GL/glut.h> #include <GL/glu.h> #include <math.h> #include "ArcBall.h" //初始化,必須用全局變量的方式,不能用new ArcBallT arcBall(600.0f,400.0f); ArcBallT* ArcBall =&arcBall;// new ArcBallT(600.0f,400.0f);//&arcBall;void reshape(int w, int h){glViewport(0,0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();glFrustum(-1, 1, -1, 1, 1.5, 20);glMatrixMode(GL_MODELVIEW);ballArcBall->setBounds((GLfloat)w, (GLfloat)h);//1. 設(shè)置窗口邊界 } void init(){glClearColor(0,0,0,0);glShadeModel(GL_FLAT); }void display (void) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0,1.0,1.0);glLoadIdentity();gluLookAt(0.0, 0.0, 5.0,0.0, 0.0, 0.0,0.0, 1.0, 0.0);glScalef(1.0, 2.0, 1.0);//glPushMatrix(); glTranslatef(0,0,-3); glScalef(ArcBall->zoomRate, ArcBall->zoomRate, ArcBall->zoomRate);//2. 縮放glMultMatrixf(ArcBall->Transform.M); //3. 旋轉(zhuǎn)glutWireCube(1.0);//glPopMatrix(); glFlush (); } //移動(dòng) void move(int x, int y) {ArcBall->MousePt.s.X = x;ArcBall->MousePt.s.Y = y;ArcBall->upstate();glutPostRedisplay(); } //點(diǎn)擊 void mouse(int button, int state, int x, int y) {if(button == GLUT_LEFT_BUTTON && state==GLUT_DOWN){ArcBall->isClicked = true;move(x,y);}else if(button == GLUT_LEFT_BUTTON && state==GLUT_UP)ArcBall->isClicked = false;else if(button == GLUT_RIGHT_BUTTON && state==GLUT_DOWN){ArcBall->isRClicked = true;move(x,y);}else if(button == GLUT_RIGHT_BUTTON && state == GLUT_UP)ArcBall->isRClicked = false;ArcBall->upstate();glutPostRedisplay(); } int main(int argc, char** argv) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);glutInitWindowSize(640,480);glutCreateWindow("HI");init();glutDisplayFunc(display);glutReshapeFunc(reshape);glutMouseFunc(mouse); //registered the mouse event.glutMotionFunc(move); //registered the move eventglutMainLoop();return 0; }另推薦一個(gè)博客,也是講解軌跡球:點(diǎn)擊打開(kāi)鏈接總結(jié)
以上是生活随笔為你收集整理的OpenGL中的轨迹球问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: OpenCV中阈值操作
- 下一篇: C语言学习之时钟函数clock()函数