欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenGL ES正交投影實(shí)現(xiàn)方法(三)

 更新時(shí)間:2018年05月26日 10:10:47   作者:weiers  
這篇文章主要為大家詳細(xì)介紹了OpenGL ES正交投影的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了OpenGL ES正交投影展示的具體代碼,供大家參考,具體內(nèi)容如下

繪制正方形

在最開始繪制的六邊形里面好像看起來(lái)挺容易的,也沒(méi)有出現(xiàn)什么問(wèn)題,接下來(lái)不妨忘記前面繪制六邊形的代碼,讓我們按照自己的理解來(lái)繪制一個(gè)簡(jiǎn)單的正方形。

按照我的理解,要想在屏幕中間顯示一個(gè)正方形,效果如下圖所示

應(yīng)該創(chuàng)建的數(shù)據(jù)如下圖所示

即傳給渲染管線的頂點(diǎn)數(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
  };

于是代碼大概是這樣子的,這里省略掉與主題無(wú)關(guān)的代碼,顏色用純色填充,因此在片元著色器中指定顏色,也省略掉一系列矩陣變換。頂點(diǎn)著色器中直接將頂點(diǎn)傳給渲染管線,片元著色器中給片元設(shè)置固定顏色紅色。

Rectangle.java

public class Rectangle {
 private FloatBuffer mVertexBuffer;
 private int mProgram;
 private int mPositionHandle;

 public Rectangle(float r) {
  initVetexData(r);
 }

 public void initVetexData(float r) {
  // 初始化頂點(diǎn)坐標(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);
  // 將頂點(diǎn)數(shù)據(jù)傳遞到管線,頂點(diǎn)著色器
  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.java

public 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();
  }
 }

}

然后出來(lái)的效果是這樣子的,實(shí)際上屏幕上的坐標(biāo)并不是這樣子的,后面可以知道上面畫的這個(gè)樣子其實(shí)只是一個(gè)歸一化的設(shè)備坐標(biāo)。歸一化設(shè)備坐標(biāo)可以通過(guò)公式映射到實(shí)際的手機(jī)屏幕,后面會(huì)學(xué)到。

咦,實(shí)際效果好像和想象中的不太一樣呀。我的本意是顯示一個(gè)正方形,但實(shí)際上現(xiàn)實(shí)的卻是一個(gè)矩形了,y軸上被拉伸了,并且橫屏狀態(tài)下也是類似的情況。但比較巧的是,如果以屏幕中心做一個(gè)坐標(biāo)軸,就會(huì)發(fā)現(xiàn),這個(gè)矩形的四個(gè)頂點(diǎn)在這個(gè)坐標(biāo)軸x、y范圍為[-1,1]的中間。

實(shí)際上,要顯示的所有物體映射到手機(jī)屏幕上,都是要映射到x、y、z軸上的[-1,1]范圍內(nèi),這個(gè)范圍內(nèi)的坐標(biāo)稱為歸一化設(shè)備坐標(biāo),獨(dú)立于屏幕的實(shí)際尺寸和形狀。

因此按照這樣的規(guī)定,我們要?jiǎng)?chuàng)建一個(gè)正方形就非常困難了,因?yàn)橐獎(jiǎng)?chuàng)建正方形就必須考慮手機(jī)的寬高比,傳入數(shù)據(jù)的時(shí)候就比較復(fù)雜了:不能僅僅站在要繪制物體的自身角度來(lái)看了。也就是說(shuō),上面的例子中要繪制一個(gè)正方形,傳入的頂點(diǎn)數(shù)據(jù)的y坐標(biāo)要按照比例進(jìn)行一點(diǎn)轉(zhuǎn)換,比如對(duì)16:9的屏幕,將上面?zhèn)魅氲捻旤c(diǎn)數(shù)據(jù)的y坐標(biāo)都乘以9/16即可。但同時(shí)會(huì)發(fā)現(xiàn)當(dāng)處于橫屏?xí)r,又要處理傳入的x坐標(biāo)的值,顯然這不是一個(gè)好的方案。

引入投影

實(shí)際上,對(duì)于一個(gè)物體來(lái)說(shuō)它有它自身的坐標(biāo),這個(gè)空間稱為物體空間,也就是設(shè)計(jì)物體的時(shí)候采用的一個(gè)坐標(biāo)空間,物體的幾何中心在坐標(biāo)原點(diǎn)上,歸一化后坐標(biāo)范圍在[-1,1]之間,x和y軸分度是一致的。

將在這個(gè)空間的物體直接往手機(jī)屏幕的歸一化坐標(biāo)繪制時(shí),由于屏幕的寬高比的問(wèn)題,就會(huì)出現(xiàn)和預(yù)料結(jié)果不一樣。所以只需要對(duì)物體空間的坐標(biāo)做一個(gè)映射即可。

正交投影就是為了解決這個(gè)問(wèn)題的,

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)生的矩陣會(huì)把所有的左右之間、上下之間,遠(yuǎn)近之間的點(diǎn)映射到歸一化設(shè)備坐標(biāo)中。

各參數(shù)的含義如圖所示

正交投影是一種平行投影,投影線是平行的,其視景體是一個(gè)長(zhǎng)方體,坐標(biāo)位于視景體中的物體才有效,視景體里面的物體投影到近平面上的部分最終會(huì)顯示到屏幕的視口中,關(guān)于視口后面會(huì)降到。

會(huì)產(chǎn)生下面的矩陣,z軸的負(fù)值會(huì)反轉(zhuǎn)z坐標(biāo),這是因?yàn)闅w一化設(shè)備坐標(biāo)是左手系統(tǒng),而OpenGL ES中的坐標(biāo)系統(tǒng)都是右手系統(tǒng),這里還涉及到頂點(diǎn)坐標(biāo)的w分量,目前暫時(shí)用不到。


利用矩陣的就可以將物體空間[-1,1]之間的坐標(biāo)映射到屏幕歸一化設(shè)備坐標(biāo)的[-1,1]之間。歸一化屏幕坐標(biāo)是右手坐標(biāo)系統(tǒng),原點(diǎn)在屏幕正中心,向右為x軸正方向,向上為y軸正方向,z軸垂直屏幕向外。以豎屏為例,比如設(shè)置left=-1,right=1,bottom=-hight/width,top=hight/width,比如我的手機(jī)分辨率為1920*1080 =1.8 對(duì)上面的正方形點(diǎn)(0.5,0.5)坐標(biāo)而言經(jīng)過(guò)變化就成了(0.5,0.3)

在屏幕的歸一化設(shè)備坐標(biāo)中來(lái)看就是一個(gè)正方形了,因?yàn)閥軸范圍顯然比x軸大,0.3對(duì)應(yīng)的實(shí)際長(zhǎng)度和x軸的0.5長(zhǎng)度是一樣的。

上面的代碼需要做如下修改,在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);
   }
  }

接著在頂點(diǎn)著色器中對(duì)頂點(diǎn)乘以投影矩陣

private String vertexShaderCode = "uniform mat4 uProjectionMatrix;" // 增加這一行
   + "attribute vec3 aPosition;"
   + "void main(){"
   + "gl_Position = uProjectionMatrix * vec4(aPosition,1);" // 不是直接賦值而是乘以投影矩陣
   + "}";

最后增加獲取著色器中uProjectionMatrix以及傳入值的代碼部分即可。最終的效果不論橫屏還是豎屏,顯示的都是我們期望的正方形。

攝像機(jī)設(shè)置

需要補(bǔ)充的是,上面的參數(shù)near、far的含義指的是和視點(diǎn)的距離,視點(diǎn)貌似到目前還未接觸到,它指的是攝像機(jī)的位置,和實(shí)際生活中用相機(jī)看物體一樣,從不同的角度和位置拍攝同一個(gè)物體獲得的照片肯定是不一樣的,攝像機(jī)位置用setLookAtM函數(shù)指定。

 public static void setLookAtM(float[] rm, // 生成的攝像機(jī)矩陣
        int rmOffset,
   float eyeX, float eyeY, float eyeZ, // 攝像機(jī)的位置
   float centerX, float centerY, float centerZ, // 觀察目標(biāo)點(diǎn)的位置
               // 攝像機(jī)位置和觀察目標(biāo)點(diǎn)的位置確定了觀察方向
   float upX, float upY,float upZ // up向量在x、y、z軸上的分量,我覺得一般應(yīng)該是和觀察方向垂直的
        )

前面提到的確定的視景體就和上面函數(shù)指定的攝像機(jī)位置和觀察方向有關(guān)。攝像機(jī)默認(rèn)位置在(0,0,0)處,在上面的設(shè)置下,如果將改正方形沿z軸正方向平移1個(gè)單位,屏幕上就顯示不了,因?yàn)橐呀?jīng)跑到了設(shè)置的視景體外面了。

關(guān)于攝像機(jī)的參數(shù)和投影near和far參數(shù)的設(shè)置需要注意,肯定不是胡亂設(shè)置的!攝像機(jī)的位置、方向和投影矩陣定義的視景體最終確定了視景體的位置,如果設(shè)置不當(dāng)就會(huì)導(dǎo)致物體沒(méi)有顯示在屏幕上,因?yàn)槲矬w的坐標(biāo)可能位于視景體外面。

視口

前面說(shuō)過(guò)在視景體中的物體最終會(huì)投影到近平面上,最終顯示到視口上,正如前面在onSurfaceChanged設(shè)置的那樣。

public static native void glViewport(
  int x,
  int y,
  int width,
  int height
 );

視口中各參數(shù)的含義

視口用的屏幕坐標(biāo)系原點(diǎn)并不在屏幕左上角而是在左下角,x軸向右,y軸向上。其實(shí)還不是很準(zhǔn)確,準(zhǔn)確的說(shuō),視口的坐標(biāo)原點(diǎn)位于該View的左下角,因?yàn)镚LSurfaceView并不總是占據(jù)整個(gè)屏幕的。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android開發(fā)TextView內(nèi)的文字實(shí)現(xiàn)自動(dòng)換行

    Android開發(fā)TextView內(nèi)的文字實(shí)現(xiàn)自動(dòng)換行

    這篇文章主要為大家介紹了Android開發(fā)TextView內(nèi)的文字實(shí)現(xiàn)自動(dòng)換行,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Android實(shí)現(xiàn)圓角彈框功能

    Android實(shí)現(xiàn)圓角彈框功能

    這篇文章主要介紹了Android實(shí)現(xiàn)圓角彈框功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Android Koin2基本使用的那件事兒

    Android Koin2基本使用的那件事兒

    這篇文章主要給大家介紹了關(guān)于Android Koin2基本使用的那件事兒,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 詳解如何實(shí)現(xiàn)一個(gè)Kotlin函數(shù)類型

    詳解如何實(shí)現(xiàn)一個(gè)Kotlin函數(shù)類型

    這篇文章主要為大家詳細(xì)介紹了如何實(shí)現(xiàn)一個(gè)Kotlin函數(shù)類型,文中的實(shí)現(xiàn)方法講解詳細(xì),具有一定的借鑒價(jià)值,需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-10-10
  • Android?Compose狀態(tài)改變動(dòng)畫animateXxxAsState使用詳解

    Android?Compose狀態(tài)改變動(dòng)畫animateXxxAsState使用詳解

    這篇文章主要為大家介紹了Android?Compose狀態(tài)改變動(dòng)畫animateXxxAsState使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Android仿開心消消樂(lè)大樹星星無(wú)限循環(huán)效果

    Android仿開心消消樂(lè)大樹星星無(wú)限循環(huán)效果

    這篇文章主要為大家詳細(xì)介紹了Android仿開心消消樂(lè)大樹星星無(wú)限循環(huán)效果,自定義view實(shí)現(xiàn)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Android生存指南之:開發(fā)中的注意事項(xiàng)

    Android生存指南之:開發(fā)中的注意事項(xiàng)

    本篇文章是對(duì)在Android開發(fā)中的一些注意事項(xiàng),需要的朋友可以參考下
    2013-05-05
  • android仿支付寶、微信密碼輸入框效果

    android仿支付寶、微信密碼輸入框效果

    這篇文章主要為大家詳細(xì)介紹了android仿支付寶、微信密碼輸入框效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android藍(lán)牙庫(kù)FastBle的基礎(chǔ)入門使用

    Android藍(lán)牙庫(kù)FastBle的基礎(chǔ)入門使用

    這篇文章主要給大家介紹了關(guān)于Android藍(lán)牙庫(kù)FastBle的基礎(chǔ)入門使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • Android程序開發(fā)仿新版QQ鎖屏下彈窗功能

    Android程序開發(fā)仿新版QQ鎖屏下彈窗功能

    最近做了一個(gè)項(xiàng)目,其中涉及到這樣一個(gè)功能:新版的qq能在鎖屏下彈窗顯示qq消息,下面小編抽時(shí)間把實(shí)現(xiàn)代碼分享給大家感興趣的朋友參考下吧
    2016-09-09

最新評(píng)論