openGL實現第一人稱視角

2021-09-23 15:41:57 字數 3925 閱讀 4491

最近做的乙個題目要求用opengl實現乙個漫遊功能,雖然不知道這個漫遊是不是指第一人稱(其實我覺得第三人稱俯視的那種也算),不過都差不多

主要使用opengl的glulookat函式,通過計算球面座標來實現

目錄

glulookat()

實現過程

demo

最終效果

void glulookat( gldouble eyex, gldouble eyey, gldouble eyez, gldouble centerx, gldouble centery, gldouble centerz, gldouble upx, gldouble upy, gldouble upz);

可以看到glulookat函式中有三組三維座標

第一組eye xyz是攝像機的位置,第二組center xyz是攝像機看向的位置,第三組up xyz是向上向量

注意第一組和第二組是座標,而第三組是向量

可以這麼理解

第一組:腦袋/眼睛的位置

第二組:眼睛看向的位置

第三組:頭頂的方向(躺著和坐著看乙個物體,看到的景象是不同的)

一開始有人跟我這麼解釋「up為頭頂方向」的時候,我並不理解,覺得如果抬頭看乙個物體的話,那麼頭頂的位置不也得向後傾斜?emmm,其實頭頂方向這個說法並不嚴謹,應該說你正視前方時頭頂的方向,或者你理解成看東西的時候眼珠子動腦袋不動

就比如上面這兩個小人,兩人眼睛的位置是相同的(你可以認為這個人是獨眼怪),眼睛看向的位置是相同的,但頭頂的方向是不同的,看到的影象也是不同的

實現的思路是根據滑鼠相對於螢幕中心點的距離來控制轉頭的幅度

glutpassivemotionfunc(yourfunc0);//不按滑鼠移動

glutmotionfunc(yourfunc1);//按滑鼠移動

opengl兩個滑鼠事件返回的滑鼠座標都以左上角為原點,如下圖,所以會導致最後實現的第一人稱視角y軸反轉,這個很容易解決,計算出的角度加乙個負號或者處理一下螢幕座標將原點變為左下角。

//不按滑鼠移動

void onmousemovepassive(int screen_x,int screen_y)

因為在水平方向最大要能轉180度,而豎直方向最大轉90度,所以滑鼠相對中心點移動比例轉換成角度時,水平方向要乘以180度,豎直方向乘以90度

(這個第一人稱仍然有它的問題,比如滑鼠移動到邊框後不可繼續移動。以往我們在fps遊戲中的視角都是只要滑鼠在往右拖動就可以一直轉向,但由於我們使用的是滑鼠相對中心點的偏移,導致最大只能轉向180度,將水平方向偏移角度的pi增大幾倍可以一定程度緩解這個問題,但同時也會使得「靈敏度」過高,目前還沒有想到乙個好的解決辦法)

因為glulookat引數的第一組和第二組點都是座標,第一人稱攝像機是可以移動的,我們要計算第二組攝像機看向的點,就要計算攝像機看向的點相對於攝像機的位置

計算球面座標

先看水平方向,a為scrrenrate_x,通過螢幕座標在水平方向上的偏移量計算出的角度,先從y軸俯視xoz平面

可以得到水平方向上相機看向的點的xz座標為( r*sin(a),r*cos(a) ),r隨便設乙個數字即可

將y豎直方向考慮進來,b即是screenrate_y,根據螢幕座標在水平方向上偏移量計算出的角度,

y = r*sin(b)

半徑r在xoz平面的投影長度r_castlength為abs(r*cos(b)),即原點到(x,o,z)點的距離,結合之前在水平方向上求出的點(x',0,z')

x' =  r*sin(a),z' = r*cos(a) ,相似三角形就能求出x,z的值

得到球面座標(x,y,z)是相對於相機的座標

在glulookat函式中將相對於攝像機的座標變為世界座標系中的座標

glulookat(cpos_x, cpos_y, cpos_z, cpos_x + look_x, look_y+look_y, cpos_z - look_z, 0, 1, 0);
其中cpos_xyz是攝像機的座標,因為我的相機因為其他功能需求的原因,初始是面朝z軸負方向,所以第6個引數是cpos_z - look_z。如果沒有特殊需求,為了方便理解初始面還是面朝z正方向比較不容易出錯

相機移動就很簡單了,glutkeyboardfunc設定鍵盤函式,根據上面計算xoz面的座標來控制wasd往對應方向移動

因為z軸反過來了所以想起來有些繞,為了保險還是在紙上自己畫一畫對照著做。

float step = 0.01;

void keyboardfunc(unsigned char key,int x,int y)

if (key == 's')

if (key == 'a')

if (key == 'd')

}

因為使用的是只考慮平面的look_x_temp,look_z_temp,而不是根據球面座標計算的look_x,look_z,所以不會有抬頭低頭速度不一樣、斜著走比正著走快(因為根本沒法斜著走hhhhh)等問題

#define _crt_secure_no_warnings

#define windowwidth 400

#define windowheight 400

#define windowtitle "第一人稱視角漫遊demo"

#include #include #include #include #includeusing namespace std;

float pi = 3.14;

//視角控制

float look_x = 0,

look_y = 0,

look_z = 0,

look_x_temp = 0,

look_z_temp = 0;

float screenrate_x, screenrate_y;//滑鼠螢幕座標相對於中心點移動的比例

float r = 10;

//相機位置

float cpos_x = 0,

cpos_y = 2,

cpos_z = 10;

int centerpoint_x = windowwidth / 2,

centerpoint_y = windowheight / 2;

void display(void)

void myidle(void)

//不按滑鼠移動事件

void onmousemovepassive(int screen_x, int screen_y)

//按下滑鼠移動事件

第一人稱視角漫遊(unity 暴風魔鏡)

沒用的話就不說了,直接開始。1 開啟unity,將場景的攝像機刪除掉。找到mojingmain.prefab,新增到場景中。2 搭建場景。3 場景中新增mojingfirstcharactercontroller.prefab和integrateinputmanager.prefab 4 建立乙個空...

第一人稱視角的一種解決方案

a模型在以b模型為基準點,實現b模型旋轉,其a模型還是會在a模型原來相對的乙個點上。比如說,a模型在b模型左上方的某個位置,如果b模型繞摸個軸旋轉了某個度數,其a模型還是相對與b模型在左上方某個位置。一次類推,可以位移縮放等。現在就來簡單的介紹一下這中情況在android開發中的實現的具體的策略。1...

Unity VR學習 第一人稱射擊遊戲(1)

1 封裝標籤 1.標籤有player,enemy,gamecontroller,fader 畫布 maincamera 2.使用const常量進行封裝 const 宣告某個常量欄位或常量區域性變數。注意 常量欄位和常量區域性變數不是變數並且不能修改 利用const管理遊戲標籤 2 場景淡入淡出 1....