① qt android 怎樣使用opengl
qt 可以通過QGLWidget運行opengl。QGLWidget繼承QWidget,能夠直接在裡面調用opengl的介面。這個在qt文檔里有具體說明,也有相關例子,所以不贅述了。但是無法在正式軟體裡面執行,為什麼?因為正式軟體是用QGraphicsScene這個場景類操作和操作一切item,而用QGraphicsView將其顯示出來,而每一個item都是QGraphicsItem的子類。QGLWidget並不是QGraphicsItem類,我曾經嘗試用普通的QWidget類那樣,通過proxy來加進QGraphicsItem,但是沒有成功。或許有方法,但是沒有找到。
於是我放棄了用QGLWidget來操作opengl的打算,尋找直接在QGraphicsItem中操作opengl的方法。通過查看文檔和示例代碼,找到了這個方法:
1 往qt工程文件里添加opengl以及對應的lib。
2 對QGraphicsView進行一個三維對話框的指定,代碼如下:
QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
widget->makeCurrent();
QGraphicsView view;
view.setViewport(widget);
上述代碼告訴了 QGraphicsView 類當前繪制的對象是支持opengl的。於是所有的場景中的item都將繪制到widget 上。
3 寫一個QGraphicsItem的繼承類,特別要重寫paint函數。代碼如下:
void XXX::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->beginNativePainting();
glColor3f(0.5,1.0,0.2);
glBegin(GL_TRIANGLES);
glVertex3f(100.0,100.0,-100.0);
glVertex3f(150.0, 100.0, -100.0);
glVertex3f(100.0, 150.0, -100.0);
glEnd();
painter->endNativePainting();
}
上面這個函數主要是用opengl介面繪制了一個三角形。記住,在opengl繪制之前一定要執行painter->beginNativePainting()以及painter->endNativePainting()這兩個語句。
QGraphicsScene、 QGraphicsView和QGraphicsItem的關系可以查閱相關文檔,也不贅述了。
不過我按照這個方式畫的三角形,怎麼也在窗口上顯示不出來,找了半天才發現問題在這個函數上QGraphicsItem::boundingRect()。這個函數是 干什麼用的呢?主要用來返回該item的初始化大小,這個大小不會輕易改變,後續的改變都可以通過矩陣來完成,但是初始大小是不變的。QGraphicsView通過這個矩形來判斷當前item是不是需要重繪,如果在重繪區外,則不調用重繪函數了。同時碰撞檢測之類,也可以用這個矩形來判斷。原來,item本身的矩陣外包框不對,所以才導致了重回不出來,改過來就正確了。
上面說的很潦草,具體怎麼改的步驟就不說了。要想正確的繪制,必須得弄清楚坐標系的關系,QGraphicsScene、QGraphicsView以及QGraphicsItem這三個坐標繫到底是什麼關系。我看了文檔,也自己進行了測試,但是感覺文檔和測試的結果有些出入。具體出入不說了。說一下自己得心的吧。
先說明:涉及到一切大小和長度,都是像素大小,至少我測試的結果是這樣的。
在建立QGraphicsScene對象的時候,有一個構造函數是矩形,這個矩形是什麼含義呢?經過測試,發現這個矩形並沒有指定彈出窗口的位置,比如,我把矩形的左上角點指定為-1000,-1000,顯示的位置和1000,1000是一樣的,而長度則正確指定了(當然,可能會有滾動條)。所以,這個矩形的左上角點並不是顯示的窗口的位置,而是它在邏輯上的左上角點。我們顯示一切item,都是以這個邏輯上的坐標系為准來繪制的。比如,左上角點是-1000,-1000,而item的位置在-500,-500,則這個-500,-500相當於在顯示窗口的左上角往下各加500個像素的坐標的位置。
那麼 QGraphicsItem的boundingRect是什麼意思呢?返回的是什麼大小?是以什麼坐標系顯示的大小?首先,這個大小肯定是以像素為單位的,其次,這個矩形的坐標是以QGraphicsScene的邏輯坐標為準的。當然這個大小是沒有任何矩陣疊加的大小。有了矩陣疊加後,實際的矩形可能會發生變化。假如在boundingRect中指定矩形的左上角為100,100,那麼最終體現的位置則是QGraphicsScene邏輯坐標100,100的位置,如果QGraphicsScene的左上角點已經指定為-1000,-1000,那麼這個位置實際上就是離窗口左上角點1100,1100的位置(由於有滾動條,所以也不一定是這個長度。)
那麼在QGraphicsItem的paint函數中進行了opengl繪制用的是什麼坐標呢?其實用的也是QGraphicsScene的邏輯坐標。如上面的例子,繪制的直角三角形直角頂點是0,0,那麼顯示的位置就是距離顯示窗口左上角點1000,1000的位置。不過opengl的所有繪制都是沒有矩陣疊加的基礎上,如果用矩陣疊加,則顯示的位置肯定和指定的有區別了。比如,我用setPos強制指定一個位置,這個位置將和opengl繪圖坐標相疊加,最後顯示到窗口上。我推測setPos其實是改變了矩陣,是一個平移矩陣。
② Android OpenGL 的基本使用
由於本人現在在公司做Android上的OpenGL圖像處理相關功能,以前沒有搞過這方面的知識,所以一切只能從頭開始搞起,接下來將會慢慢分享其他方面的內容,先用這篇比較基礎的文章來開頭。
剛才我們談到圖像處理,在做圖像處理我們不是可以用Canvas來繪制嗎,怎麼還要用OpenGL那麼陌生的東西來搞?為什麼要用OpenGL,肯定有它的好處。
接下來我們會來講解如何在Android項目開發過程中加入OpenGL,在開始前我們先了解同OpenGL ES密切相關的載體:GLSurfaceView:
要用OpenGL繪制,首先要有GLSurfaceVie的實例
現在OpenGL ES版本已經到3.0了,Android平台上目前有1.0和2.0,我們使用的是2.0,在使用前在onCreate()方法中檢查是否支持2.0的版本並且確定使用2.0
一般我們只需要使用「configurationInfo.reqGlEsVersion >= 0x20000」,至於加後面主要是用於模擬器檢查,假定模擬器支持2.0。
前面說到GLSurfaceView挖了一個洞,就是為了看見下面的渲染表面,同樣實在onCreate()方法中
通過setEGLContextClientVersion()方法配置surface視圖,設定好使用的OpenGL版本,然後調用setRenderer()傳進有自定義Renderer類的新實例。當Surface創建或者發生變化的時候,以及繪制一幅新幀時,渲染器都會被GLSurfaceView調用。
GLSurfaceView的生命周期要協同好Activity的生命周期,避免造成內存泄漏。
Renderer類也就是我們的渲染類了,它是通過實現Renderer介面來實現功能的。
渲染器介面定義的方法:
實現Renderer的介面方法
首選在onSurfaceCreated()中調用glClearColor設置清空屏幕用的顏色,這里使用紅色。
設置視口的大小
在onDrawFrame()中調用glClear(GL_COLOR_BUFFER_BIT)清空屏幕,會調用glClearColor中定義的顏色來填充整個屏幕。通過這幾個步驟,基本上就可以在GLSurfaceView繪制出東西了,在這里我只是簡單的用紅色繪制整個屏幕。
OpenGL在Android上的使用基本上是這樣,但是,當然沒那麼簡單,在使用OpenGL進行繪制算是比較繁瑣的過程,後面也會慢慢去揭曉其他使用方法,來構造一幅一幅精美的特效靜/動圖。
③ android 使用opengl es2.0瀏覽全景圖片
先上效果圖
我是android opengl es的初學者,有很多東西還不懂,仍在學習;這里實現全景圖瀏覽的一個思路是,先使用opengl繪制一個球體,這個球體中心位置在手機屏幕的中心,球體的半徑為3。默認攝像機的位置在球體正前方半徑為3的位置上,看著球體的中心,在收觸摸屏幕的時候,不斷調整攝像機的位置,但是保持距離球體中心的位置不變。
球體繪製成功後,將准備好的全景圖,貼在球體的表面,就完成了(不需要對全景圖進行特殊處理,我剛開始的思路是繪制一個正方體天空盒,然後對全景圖進行處理,獲得天空盒六個面的圖像,然後將圖像貼在六個面上,結果發現我不會。。。。)。
這里涉及到
opengl的繪制,可以看看 android opengl es2.0完全入門這篇文章
繪制球體,opengl es2.0隻能繪制點,線和三角形,如果要繪制球體的話,需要將球體表面切分成成千上萬個小矩形,矩形又可以切分成三角形來繪制,只要切分的夠細,看上去就是球體。
繪制球體需要你掌握一點三維空間和三角函數的知識
④ 如何在Android上使用OpenGL ES 2.0繪制點
如何在Android使用OpenGL
ES
2.0繪制點,看上去並不是一個復雜的問題,但是上網一搜,滿眼都是繪制點的代碼。
如果你看到類似如下代碼,基本上你已經掉坑裡了。
···
c
glBeging();
...
glDrawPoint(...);
...
glEnd();
```
如上是使用OpenGL
ES
1.0繪制點的代碼。因為架構不同,在OPENGL
ES
2.0的世界裡,這一套已經徹底不管用了。
在OpenGL
ES
2.0里繪制點,要使用Shader,使用Shader,用Shader。。。。。。
具體怎麼繪制呢,首先你要搞清楚,如何用Shader繪制一個普通帶顏色的三角形。我這里假設你已經會了。
三角形顯示出來的那一刻,你一定會有這樣的代碼:
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,
0,
vertexCount);
那麼,只顯示三角形的三個頂點該怎麼辦,說來簡單,這行代碼改成
GLES20.glDrawArrays(GLES20.GL_POINTS,
0,
vertexCount);
即可。
但是,理想和現實的差距總是很大,改完後三角形消失了但是頂點沒有出現。正常OpenGL
2.0環境下應該怎麼做呢?
1)首先調用
GL20.glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
這樣在Shader中可以訪問glPointSize;
2)然後類似准備每個頂點色彩那樣准備頂點的大小的數值,三角形是三個頂點,就准備3個float。把頂點數據像色彩數據那樣,綁定到VOB,再綁定到Shader的參數中。基本上就是照準備色彩那樣准備頂點大小數據,不同之處在於每個色彩4個float,每個頂點尺寸1個float。
3)最後,把你的頂點Shader文件改好,增加頂點大小的輸入參數和gl_PointSize賦值。
4)另外,如果你打算顯示圓形頂點,而不是方形的,還要用GL20.glEnable()函數設置其他參數,具體可查OpenGL官網。
比如:
uniform
mat4
matrix;
attribute
vec4
aVertex;
attribute
vec4
aColor;
attribute
float
aPointSize;
varying
vec4
vColor;
void
main(){
vColor
=
aColor;
gl_Position
=
matrix
*
aVertex;
gl_PointSize
=
aPointSize;
}
這樣,基本上就搞定了。
現在,坑爹的問題來了,在Android上你找不到GLES20.GL_VERTEX_PROGRAM_POINT_SIZE的常量,谷歌似乎認為在手機的3D環境下繪制點沒多大必要性,所以並沒有加上這個參數,好在預設情況下,模擬器中Shader中的gl_PointSize是打開的(Android
4.4.x)。所以你可以跳過第一步,直接傳遞點大小的參數,並把Shader改好就成。
那麼,為什麼你不寫gl_PointSize
=
aPointSize,點就顯示不出來呢。我估計預設情況下,gl_PointSize
=
0.0f,所以顯示不出來。
如果你顯示點的大小總是固定不變的,你甚至可以把傳遞頂點大小數值的步驟也省略掉,直接在Shader中寫上gl_PointSize
=
10.0f;即可。
閱讀本文,當你打算在Android上用OPENGL
ES
2.0顯示點時,即可跳過谷歌的那些坑了。我想,手機GPU硬體廠商的開發包應該對OpenGL
ES
2.0支持的更好些,比如高通的AdrenoSDK,建議大家下載嘗試。