日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

arcball原理 旋转视图 关键点总结 及代码

發(fā)布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 arcball原理 旋转视图 关键点总结 及代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

旋轉(zhuǎn)軸

arcball原理前期計算是在相機視角下,所以計算出來的旋轉(zhuǎn)軸也在相機視角下,所以要把旋轉(zhuǎn)軸向量變換到世界坐標系。變換步驟:假設旋轉(zhuǎn)軸是一個過相機坐標系原點的單位向量(也可以看做一個坐標點),利用view矩陣的逆矩陣將這個坐標點變換到世界坐標系中,得到新的坐標點然后減去世界坐標系中相機的位置(相機坐標系的原點),就可以得到世界坐標系中的旋轉(zhuǎn)軸。

世界坐標系中的上向量

當使用lookAt函數(shù)的時候需要一個世界坐標系的上向量,很多教程給的(0,1,0)向量,但是如果一直使用這個向量,當利用arcball原理旋轉(zhuǎn)視圖的時候,由于叉乘原理相機坐標系會在相機處于世界坐標系Z軸原點附近發(fā)生突變,這會使視圖旋轉(zhuǎn)出現(xiàn)錯誤。所以需要在相機旋轉(zhuǎn)的時候保持更新這個上向量,更新方法很簡單,始終讓這個上向量和方向向量保持90度就可以,具體做法和上面類似。
之前的博文基礎:
https://blog.csdn.net/weixin_42376458/article/details/104481641?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159178073819725222460919%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159178073819725222460919&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_blog_v1-1-104481641.pc_v2_rank_blog_v1&utm_term=arcball

代碼 (Qt代碼)(這套代碼無誤可行)

完整的程序可見github:
https://github.com/chenandongtime/OpenGL/tree/master/HelloTriange

#ifndef CAMERA_H #define CAMERA_H#include <QObject> #include<QMatrix4x4> #include<QVector3D> #include<QVector4D> #include<math.h>class camera : public QObject {Q_OBJECT public:camera(QObject *parent ,QVector3D camPosition); //定義屬性 private:QVector3D position; //相機位置QVector3D target; //目標位置QVector3D worldUp; //世界坐標系 上向量(0,0,1)QMatrix4x4 view; //相機坐標系變換矩陣QMatrix4x4 worldM; //世界坐標系變換矩陣float sensitivity; //相機靈敏度 public://函數(shù)說明:獲取視圖矩陣//函數(shù)返回: 視圖矩陣QMatrix4x4 getView();//函數(shù)說明:對相機位置做旋轉(zhuǎn)變化,利用arcBall原理,改變相機的位置//參數(shù)說明:float xOffset: 水平方向的偏移,大小為根據(jù)屏幕寬度歸一化的數(shù)值// float yOffset:豎直方向的偏移:大小為根據(jù)屏幕高度歸一化的數(shù)值void rotateCamera(float xOffset,float yOffset);//函數(shù)說明:獲取世界坐標系繞任意經(jīng)過原點的軸的旋轉(zhuǎn)任意角度的變換矩陣//參數(shù)說明:QVector3D:Axis 經(jīng)過世界原點的軸的方向// float:theta 旋轉(zhuǎn)角度// 返回值: QMatrix4x4 wolrdRotate 世界坐標系旋轉(zhuǎn)矩陣QMatrix4x4 getWorldRotateM(QVector3D axis,float theta);//放大縮小 :就是拉近或者送遠的相機的距離,也就是改變相機的位置// 參數(shù)說明: scalef 拉近或者送遠的倍數(shù)void scale(float scalef);//平移變換 : 修改世界坐標系變換矩陣,使物體在世界坐標系中的位置發(fā)生變化從而改變視圖中物體位置//參數(shù)說明 : xOffset 屏幕上x的偏移 yOffset屏幕上y的偏移void translateWorldM(float xOffset,float yOffset);//獲取世界模型QMatrix4x4 getWorldM();signals:};#endif // CAMERA_H #include "camera.h" #include <QDebug> camera::camera(QObject *parent,QVector3D camPosition) : QObject(parent),position(camPosition) {this->target = QVector3D(0,0,0);this->worldUp = QVector3D(0,1,0);this->view = this->getView();this->sensitivity = 3.0;this->worldM = QMatrix4x4(); }QMatrix4x4 camera::getView() {QMatrix4x4 Identiy;Identiy.lookAt(this->position,this->target,this->worldUp); //產(chǎn)生了一個視圖變化矩陣view = Identiy;return view; }void camera::rotateCamera(float xOffset, float yOffset) {xOffset = xOffset * sensitivity;yOffset = yOffset * sensitivity;QVector3D BallCenter(0,0,-1); //arcball球心坐標//獲取球上兩個坐標點 以及形成的向量QVector3D pointOne(0,0,0);float zOffset = sqrt((1 - xOffset * xOffset - yOffset * yOffset)) - 1;QVector3D pointTwo(xOffset,yOffset,zOffset);QVector3D vecOne(pointOne - BallCenter);QVector3D vecTwo(pointTwo - BallCenter);//獲取旋轉(zhuǎn)軸QVector3D axisView = QVector3D::crossProduct(vecOne,vecTwo); //相機視野中的旋轉(zhuǎn)軸axisView.normalize();QVector4D axisWorld4D = this->view.inverted() * QVector4D(axisView[0],axisView[1],axisView[2],1); //世界坐標系中的旋轉(zhuǎn)軸QVector3D axisWorld = QVector3D(axisWorld4D[0] - this->position[0],axisWorld4D[1] - this->position[1],axisWorld4D[2] - this->position[2]);axisWorld.normalize();//獲取旋轉(zhuǎn)角float theta = acos(QVector3D::dotProduct(vecOne,vecTwo));//vecOne和vecTwo是單位向量//獲取世界變換矩陣QMatrix4x4 worldRotateM = this->getWorldRotateM(axisWorld,theta);//更新相機的位置this->position = worldRotateM * this->position;//更新worldUp, 這樣做是為了lookat函數(shù)中目標方向與世界坐標系的上方方向向量的叉乘方向避免突變QVector4D worldUpTemp = QVector4D(0,1,0,1);//當前坐標系的Y軸 單位向量 (y軸上一點)worldUpTemp = this->view.inverted() * worldUpTemp; //世界坐標系下 單位向量的坐標worldUpTemp = worldRotateM * worldUpTemp; //世界坐標系發(fā)生了旋轉(zhuǎn),所以這個點也要旋轉(zhuǎn)QVector3D worldUpPos = QVector3D(worldUpTemp[0],worldUpTemp[1],worldUpTemp[2]);this->worldUp = worldUpPos - this->position; // 新的世界坐標系的worldUp }QMatrix4x4 camera::getWorldRotateM(QVector3D axis, float theta) {if(axis.length() == 0) //輸入的軸有問題{//這里應該添加異常處理程序,方便代碼調(diào)試QMatrix4x4 Identiy;return Identiy;}//構(gòu)建平移矩陣QMatrix4x4 Trans;Trans(0,3) = -this->target[0];Trans(1,3) = -this->target[1];Trans(2,3) = -this->target[2];// //調(diào)式代碼 // QMatrix4x4 Trans2; // Trans2(0,3) = -10; // Trans2(1,3) = -9; // Trans2(2,3) = -10; // QVector4D temp(1,1,1,1); // QVector4D temp2 = Trans2 * temp; // QVector4D temp3 = temp * Trans2;//繞X軸旋轉(zhuǎn) 使軸落入xoz平面內(nèi)float cosA;float sinA;float u = sqrt(axis[1]*axis[1]+axis[2]*axis[2]);if( u < 0.001) //表示已經(jīng)在X軸上{cosA = 1;sinA = 0;}else{cosA = axis[2] / u;sinA = axis[1] / u;}QMatrix4x4 rotateToXZ;rotateToXZ(1,1) = cosA;rotateToXZ(2,1) = sinA;rotateToXZ(1,2) = -sinA;rotateToXZ(2,2) = cosA;//繞y軸旋轉(zhuǎn) 與Z軸重合float v = sqrt(u*u + axis[0]*axis[0]);float cosB = u / v;float sinB = axis[0] / v;QMatrix4x4 rotateToZ;rotateToZ(0,0) = cosB;rotateToZ(0,2) = -sinB;rotateToZ(2,0) = sinB;rotateToZ(2,2) = cosB;//旋轉(zhuǎn)theta角QMatrix4x4 rotateTheta;rotateTheta(0,0) = cos(theta);rotateTheta(0,1) = -sin(theta);rotateTheta(1,0) = sin(theta);rotateTheta(1,1) = cos(theta);//世界坐標系變換矩陣QMatrix4x4 worldRotateM = Trans.inverted() * rotateToXZ.inverted() * rotateToZ.inverted() * rotateTheta *rotateToZ * rotateToXZ * Trans;return worldRotateM; }void camera::scale(float scalef) {if(scalef <= 0) //縮放比例必須大于0return;this->position = this->position * sqrt(scalef); }void camera::translateWorldM(float xOffset, float yOffset) {//計算平移的方向QVector4D TransInView(xOffset,yOffset,0,1);//向量的變換 必須是向量的兩個端點同時變換,簡單起見可以假設向量的起始點都是原坐標系的原點QVector4D TransInWorld = this->view.inverted() * TransInView - QVector4D(position[0],position[1],position[2],1);// 計算平移的距離float TransDis = sqrt(this->position.length())/2;TransInWorld = TransInWorld * TransDis;//改變世界矩陣this->worldM(0,3) += TransInWorld.x() * TransDis;this->worldM(1,3) += TransInWorld.y() * TransDis;this->worldM(2,3) += TransInWorld.z() * TransDis; }QMatrix4x4 camera::getWorldM() {return this->worldM; }

總結(jié)

以上是生活随笔為你收集整理的arcball原理 旋转视图 关键点总结 及代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。