版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】使用OpenGL怎么實現(xiàn)ES正交投影
這篇文章將為大家詳細(xì)講解有關(guān)使用OpenGL怎么實現(xiàn)ES正交投影,文章內(nèi)容質(zhì)量較高,因此在下分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。繪制正方形在最開始繪制的六邊形里面好像看起來挺容易的,也沒有出現(xiàn)什么問題,接下來不妨忘記前面繪制六邊形的代碼,讓我們按照自己的理解來繪制一個簡單的正方形。按照我的理解,要想在屏幕中間顯示一個正方形,效果如下圖所示應(yīng)該創(chuàng)建的數(shù)據(jù)如下圖所示即傳給渲染管線的頂點數(shù)據(jù)如下圖:float[]
vertexArray
=
new
float[]
{
(float)
-0.5,
(float)
-0.5,
0,
(float)
0.5,
(float)
-0.5,
0,
(float)
-0.5,
(float)
0.5,
0,
(float)
0.5,
(float)
0.5,
0
};于是代碼大概是這樣子的,這里省略掉與主題無關(guān)的代碼,顏色用純色填充,因此在片元著色器中指定顏色,也省略掉一系列矩陣變換。頂點著色器中直接將頂點傳給渲染管線,片元著色器中給片元設(shè)置固定顏色紅色。Rectangle.javapublic
class
Rectangle
{
private
FloatBuffer
mVertexBuffer;
private
int
mProgram;
private
int
mPositionHandle;
public
Rectangle(float
r)
{
initVetexData(r);
}
public
void
initVetexData(float
r)
{
//
初始化頂點坐標(biāo)
float[]
vertexArray
=
new
float[]
{
(float)
-0.5,
(float)
-0.5,
0,
(float)
0.5,
(float)
-0.5,
0,
(float)
-0.5,
(float)
0.5,
0,
(float)
0.5,
(float)
0.5,
0
};
ByteBuffer
buffer
=
ByteBuffer.allocateDirect(vertexArray.length
*
4);
buffer.order(ByteOrder.nativeOrder());
mVertexBuffer
=
buffer.asFloatBuffer();
mVertexBuffer.put(vertexArray);
mVertexBuffer.position(0);
int
vertexShader
=
loaderShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int
fragmentShader
=
loaderShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram
=
GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram,
vertexShader);
GLES20.glAttachShader(mProgram,
fragmentShader);
GLES20.glLinkProgram(mProgram);
mPositionHandle
=
GLES20.glGetAttribLocation(mProgram,
"aPosition");
}
public
void
draw()
{
GLES20.glUseProgram(mProgram);
//
將頂點數(shù)據(jù)傳遞到管線,頂點著色器
GLES20.glVertexAttribPointer(mPositionHandle,
3,
GLES20.GL_FLOAT,
false,
0,
mVertexBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
//
繪制圖元
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,
0,
4);
}
private
int
loaderShader(int
type,
String
shaderCode)
{
int
shader
=
GLES20.glCreateShader(type);
GLES20.glShaderSource(shader,
shaderCode);
GLES20.glCompileShader(shader);
return
shader;
}
private
String
vertexShaderCode
=
"attribute
vec3
aPosition;"
+
"void
main(){"
+
"gl_Position
=
vec4(aPosition,1);"
+
"}";
private
String
fragmentShaderCode
=
"precision
mediump
float;"
+
"void
main(){"
+
"gl_FragColor
=
vec4(1,0,0,0);"
+
"}";
}RectangleView.javapublic
class
RectangleView
extends
GLSurfaceView{
public
RectangleView(Context
context)
{
super(context);
setEGLContextClientVersion(2);
setRenderer(new
MyRender());
}
class
MyRender
implements
GLSurfaceView.Renderer
{
private
Rectangle
rectangle;
@Override
public
void
onSurfaceCreated(GL10
gl,
EGLConfig
config)
{
GLES20.glClearColor(0.5f,
0.5f,
0.5f,
1);
rectangle
=
new
Rectangle(0.5f);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
}
@Override
public
void
onSurfaceChanged(GL10
gl,
int
width,
int
height)
{
GLES20.glViewport(0,
0,
width,
height);
}
@Override
public
void
onDrawFrame(GL10
gl)
{
GLES20.glClear(
GLES20.GL_DEPTH_BUFFER_BIT
|
GLES20.GL_COLOR_BUFFER_BIT);
rectangle.draw();
}
}
}然后出來的效果是這樣子的,實際上屏幕上的坐標(biāo)并不是這樣子的,后面可以知道上面畫的這個樣子其實只是一個歸一化的設(shè)備坐標(biāo)。歸一化設(shè)備坐標(biāo)可以通過公式映射到實際的手機屏幕,后面會學(xué)到。咦,實際效果好像和想象中的不太一樣呀。我的本意是顯示一個正方形,但實際上現(xiàn)實的卻是一個矩形了,y軸上被拉伸了,并且橫屏狀態(tài)下也是類似的情況。但比較巧的是,如果以屏幕中心做一個坐標(biāo)軸,就會發(fā)現(xiàn),這個矩形的四個頂點在這個坐標(biāo)軸x、y范圍為[-1,1]的中間。實際上,要顯示的所有物體映射到手機屏幕上,都是要映射到x、y、z軸上的[-1,1]范圍內(nèi),這個范圍內(nèi)的坐標(biāo)稱為歸一化設(shè)備坐標(biāo),獨立于屏幕的實際尺寸和形狀。因此按照這樣的規(guī)定,我們要創(chuàng)建一個正方形就非常困難了,因為要創(chuàng)建正方形就必須考慮手機的寬高比,傳入數(shù)據(jù)的時候就比較復(fù)雜了:不能僅僅站在要繪制物體的自身角度來看了。也就是說,上面的例子中要繪制一個正方形,傳入的頂點數(shù)據(jù)的y坐標(biāo)要按照比例進行一點轉(zhuǎn)換,比如對16:9的屏幕,將上面?zhèn)魅氲捻旤c數(shù)據(jù)的y坐標(biāo)都乘以9/16即可。但同時會發(fā)現(xiàn)當(dāng)處于橫屏?xí)r,又要處理傳入的x坐標(biāo)的值,顯然這不是一個好的方案。引入投影實際上,對于一個物體來說它有它自身的坐標(biāo),這個空間稱為物體空間,也就是設(shè)計物體的時候采用的一個坐標(biāo)空間,物體的幾何中心在坐標(biāo)原點上,歸一化后坐標(biāo)范圍在[-1,1]之間,x和y軸分度是一致的。將在這個空間的物體直接往手機屏幕的歸一化坐標(biāo)繪制時,由于屏幕的寬高比的問題,就會出現(xiàn)和預(yù)料結(jié)果不一樣。所以只需要對物體空間的坐標(biāo)做一個映射即可。正交投影就是為了解決這個問題的,public
static
void
orthoM(float[]
m,
int
mOffset,
float
left,
float
right,
float
bottom,
float
top,
float
near,
float
far)正交投影背后的數(shù)學(xué)orthoM函數(shù)產(chǎn)生的矩陣會把所有的左右之間、上下之間,遠近之間的點映射到歸一化設(shè)備坐標(biāo)中。各參數(shù)的含義如圖所示正交投影是一種平行投影,投影線是平行的,其視景體是一個長方體,坐標(biāo)位于視景體中的物體才有效,視景體里面的物體投影到近平面上的部分最終會顯示到屏幕的視口中,關(guān)于視口后面會降到。會產(chǎn)生下面的矩陣,z軸的負(fù)值會反轉(zhuǎn)z坐標(biāo),這是因為歸一化設(shè)備坐標(biāo)是左手系統(tǒng),而OpenGLES中的坐標(biāo)系統(tǒng)都是右手系統(tǒng),這里還涉及到頂點坐標(biāo)的w分量,目前暫時用不到。利用矩陣的就可以將物體空間[-1,1]之間的坐標(biāo)映射到屏幕歸一化設(shè)備坐標(biāo)的[-1,1]之間。歸一化屏幕坐標(biāo)是右手坐標(biāo)系統(tǒng),原點在屏幕正中心,向右為x軸正方向,向上為y軸正方向,z軸垂直屏幕向外。以豎屏為例,比如設(shè)置left=-1,right=1,bottom=-hight/width,top=hight/width,比如我的手機分辨率為1920*1080=1.8對上面的正方形點(0.5,0.5)坐標(biāo)而言經(jīng)過變化就成了(0.5,0.3)在屏幕的歸一化設(shè)備坐標(biāo)中來看就是一個正方形了,因為y軸范圍顯然比x軸大,0.3對應(yīng)的實際長度和x軸的0.5長度是一樣的。上面的代碼需要做如下修改,在onSurfaceChanged里面增加如下代碼@Override
public
void
onSurfaceChanged(GL10
gl,
int
width,
int
height)
{
GLES20.glViewport(0,
0,
width,
height);
//
根據(jù)屏幕方向設(shè)置投影矩陣
float
ratio=
width
>
height
?
(float)width
/
height
:
(float)height
/
width;
if
(width
>
height)
{
//
橫屏
Matrix.orthoM(mProjectionMatrix,
0,
-ratio,
ratio,
-1,
1,
0,
5);
}
else
{
Matrix.orthoM(mProjectionMatrix,
0,
-1,
1,
-ratio,
ratio,
0,
5);
}
}接著在頂點著色器中對頂點乘以投影矩陣private
String
vertexShaderCode
=
"uniform
mat4
uProjectionMatrix;"
//
增加這一行
+
"attribute
vec3
aPosition;"
+
"void
main(){"
+
"gl_Position
=
uProjectionMatrix
*
vec4(aPosition,1);"
//
不是直接賦值而是乘以投影矩陣
+
"}";最后增加獲取著色器中uProjectionMatrix以及傳入值的代碼部分即可。最終的效果不論橫屏還是豎屏,顯示的都是我們期望的正方形。攝像機設(shè)置需要補充的是,上面的參數(shù)near、far的含義指的是和視點的距離,視點貌似到目前還未接觸到,它指的是攝像機的位置,和實際生活中用相機看物體一樣,從不同的角度和位置拍攝同一個物體獲得的照片肯定是不一樣的,攝像機位置用setLookAtM函數(shù)指定。
public
static
void
setLookAtM(float[]
rm,
//
生成的攝像機矩陣
int
rmOffset,
float
eyeX,
float
eyeY,
float
eyeZ,
//
攝像機的位置
float
centerX,
float
centerY,
float
centerZ,
//
觀察目標(biāo)點的位置
//
攝像機位置和觀察目標(biāo)點的位置確定了觀察方向
float
upX
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度互聯(lián)網(wǎng)金融平臺民間借貸合同4篇
- 2025年度智能家居系統(tǒng)集成項目合同2篇
- 二零二五版教育培訓(xùn)機構(gòu)場地租賃及培訓(xùn)成果轉(zhuǎn)化合同4篇
- 二零二五年度民間擔(dān)保業(yè)務(wù)反欺詐合同3篇
- 2025年度苗木種植與水資源利用合作合同范本4篇
- 2025版秦皇島住宅買賣合同特別條款范本4篇
- 2024年度青海省公共營養(yǎng)師之四級營養(yǎng)師通關(guān)題庫(附答案)
- 2024年度陜西省公共營養(yǎng)師之四級營養(yǎng)師綜合檢測試卷A卷含答案
- 2025年度出口業(yè)務(wù)磋商與合同訂立監(jiān)管指南4篇
- 二零二五年度新型光伏發(fā)電設(shè)備銷售合同參考4篇
- 2024年全國職業(yè)院校技能大賽高職組(研學(xué)旅行賽項)考試題庫(含答案)
- 2025年溫州市城發(fā)集團招聘筆試參考題庫含答案解析
- 2025年中小學(xué)春節(jié)安全教育主題班會課件
- 2025版高考物理復(fù)習(xí)知識清單
- 除數(shù)是兩位數(shù)的除法練習(xí)題(84道)
- 2025年度安全檢查計劃
- 2024年度工作總結(jié)與計劃標(biāo)準(zhǔn)版本(2篇)
- 全球半導(dǎo)體測試探針行業(yè)市場研究報告2024
- 反走私課件完整版本
- 2024年注冊計量師-一級注冊計量師考試近5年真題附答案
- 中考數(shù)學(xué)復(fù)習(xí)《平行四邊形》專項練習(xí)題-附帶有答案
評論
0/150
提交評論