OpenGL之調(diào)整屏幕寬高比

OpenGL之基礎
OpenGL之繪制簡單形狀
OpenGL之顏色

調(diào)整屏幕寬高比

不做寬高比調(diào)整導致的問題

如果不做任何處理,圖像會在橫屏模式下被壓扁,因為之前直接把坐標傳遞給OpenGL時宛逗,沒有考慮屏幕的寬高比

橫屏狀態(tài) 豎屏狀態(tài)
image-20211221121517035.png
image-20211221121648424.png

解決方案

不要直接在歸一化設備坐標上工作葛账,而應該先在虛擬坐標空間里工作腥寇,然后再使用投影技術(shù)把虛擬空間坐標轉(zhuǎn)換回歸一化設備坐標

虛擬空間坐標范圍

在虛擬坐標空間里奇颠,把較小的范圍固定在 [-1,1] 內(nèi)蒜撮,然后按屏幕尺寸的比例調(diào)整較大的范圍

例如仑扑,手機寬度是720览爵,高度是1280

豎屏 橫屏
寬度范圍 [-1,1] [-1280/720,1280/720] 即 [-1.78,1.78]
高度范圍 [-1.78,1.78] [-1,1]

正交投影

正交投影是投影技術(shù)的一種镇饮,使用正交投影蜓竹,實際上定義了三維世界內(nèi)部的一個區(qū)域,也就是虛擬空間储藐。在這個區(qū)域內(nèi)的所有東西都會顯示在屏幕上俱济,而區(qū)域外的所有東西都會被裁剪掉,如下圖所示

正交投影.jpg
創(chuàng)建正交投影矩陣

Matrix.orthoM() 方法可以創(chuàng)建一個正交投影矩陣钙勃,其方法原型如下

public static void orthoM(float[] m, int mOffset,
    float left, float right, float bottom, float top,
    float near, float far) {

參數(shù)說明

參數(shù) 說明
m 最終生成的正交投影矩陣數(shù)組蛛碌,長度至少有16個元素,才能存儲正交投影矩陣
mOffset 正交投影矩陣起始的偏移值
left x軸的最小范圍
right x軸的最大范圍
bottom y軸的最小范圍
top y軸的最大范圍
near z軸的最小范圍
far z軸的最大范圍

上面的參數(shù)中l(wèi)eft辖源、right蔚携、bottom、top克饶、near酝蜒、far對應于上一幅圖中標識的地方,也是形成虛擬坐標空間的值矾湃,

調(diào)用這個方法的時候秕硝,會產(chǎn)生下面的正交投影矩陣:


image-20211221131722796.png

這個正交投影矩陣會把所有在左右之間、上下之間和遠近之間的事物映射到歸一化設備坐標中從-1到1的范圍洲尊,在這個范圍內(nèi)的所有事物在屏幕上都是可見的

歸一化設備坐標使用的是左手坐標系統(tǒng)(使用左手远豺,大拇指指向x軸正值方向、食指指向y軸正值方向)坞嘀,而在 OpenGL的早期版本躯护,默認使用的卻是右手坐標系統(tǒng),其使用z的負值增加表示距離增加丽涩。這就是為什么Android的 Matrix會默認生成反轉(zhuǎn)z的矩陣
坐標系統(tǒng)

左手坐標系統(tǒng) 右手坐標系統(tǒng)
image-20211221133109558.png
image-20211221133131305.png

加入正交投影

修改頂點著色器

attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_Matrix;

varying vec4 v_Color;
void main(){
    v_Color=a_Color;
    gl_Position=u_Matrix*a_Position;
    gl_PointSize=10.0;
}

添加 uniform 的 u_Matrix棺滞,代表正交投影矩陣裁蚁,并把它定義為一個 mat4 類型,mat4 表示這個 uniform 是一個 4×4 的矩陣

將當前頂點的最終位置賦值為:位置與一個正交投影矩陣的乘積继准。這意味著頂點數(shù)組不再代表歸一化設備坐標了枉证,其將被理解為存在于正交投影矩陣所定義的虛擬坐標空間中,這個矩陣會把坐標從虛擬坐標空間變換回歸一化設備坐標

修改渲染器

public class MyRenderer implements GLSurfaceView.Renderer {
    private final FloatBuffer mVertexBuffer;
    private Context mContext;
    private int a_color;
    private int a_position;
    private int u_matrix;
    // 保存正交投影矩陣
    private float[] projectionMatrix = new float[16];

    public MyRenderer(Context context) {
        mContext = context;
        // 頂點位置有改動移必,因為現(xiàn)在代表虛擬空間中的坐標了室谚,范圍也不再是 [-1,1],
        // 不過要注意的是崔泵,豎屏時秒赤,如果較大范圍軸(比如豎屏時的y軸)超過了1,在橫屏時會被截斷看不到
        float[] vertex = new float[]{
                0f, 0f, 1f, 1f, 1f,
                -0.5f, -0.8f, 0f, 0f, 0f,
                0.5f, -0.8f, 0f, 0f, 0f,
                0.5f, 0.8f, 0f, 0f, 0f,
                -0.5f, 0.8f, 0f, 0f, 0f,
                -0.5f, -0.8f, 0f, 0f, 0f,

                -0.5f, 0f, 1f, 0f, 0f,
                0.5f, 0f, 1f, 0f, 0f,

                0f, -0.5f, 0f, 1f, 0f,
                0f, 0.5f, 0f, 0f, 1f
        };
        mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertex);
        mVertexBuffer.position(0);
    }

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        glClearColor(1f, 1f, 1f, 1f);

        int vertexShader = ShaderHelper.compileVertexShader(mContext, R.raw.ratio3_vertex);
        int fragmentShader = ShaderHelper.compileFragmentShader(mContext, R.raw.ratio3_fragment);
        int program = ProgramHelper.getProgram(vertexShader, fragmentShader);
        glUseProgram(program);

        a_color = glGetAttribLocation(program, "a_Color");
        a_position = glGetAttribLocation(program, "a_Position");
        // 獲取正交投影矩陣位置
        u_matrix = glGetUniformLocation(program, "u_Matrix");

        mVertexBuffer.position(0);
        glVertexAttribPointer(a_position, POSITION_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, mVertexBuffer);
        glEnableVertexAttribArray(a_position);

        mVertexBuffer.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(a_color, COLOR_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, mVertexBuffer);
        glEnableVertexAttribArray(a_color);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        glViewport(0, 0, width, height);
        // 生成正交投影矩陣
        float ratio = width > height ? (float) width / height : (float) height / width;
        if (width > height) {
            // 橫屏
            Matrix.orthoM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, -1f, 1f);
        } else {
            // 豎屏
            Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -ratio, ratio, -1f, 1f);
        }
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        glClear(GL_COLOR_BUFFER_BIT);
        // 向著色器傳遞 正交投影矩陣
        glUniformMatrix4fv(u_matrix, 1, false, projectionMatrix, 0);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 6);

        glDrawArrays(GL_LINES, 6, 2);

        glDrawArrays(GL_POINTS, 8, 1);
        glDrawArrays(GL_POINTS, 9, 1);
    }
}

效果

豎屏 橫屏
image-20211221140409098.png
image-20211221140436697.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末憎瘸,一起剝皮案震驚了整個濱河市入篮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌幌甘,老刑警劉巖潮售,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锅风,居然都是意外死亡酥诽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門遏弱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盆均,“玉大人,你說我怎么就攤上這事漱逸±嵋蹋” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵饰抒,是天一觀的道長肮砾。 經(jīng)常有香客問我,道長袋坑,這世上最難降的妖魔是什么仗处? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮枣宫,結(jié)果婚禮上婆誓,老公的妹妹穿的比我還像新娘。我一直安慰自己也颤,他們只是感情好洋幻,可當我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翅娶,像睡著了一般文留。 火紅的嫁衣襯著肌膚如雪好唯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天燥翅,我揣著相機與錄音骑篙,去河邊找鬼。 笑死森书,一個胖子當著我的面吹牛靶端,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拄氯,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼躲查,長吁一口氣:“原來是場噩夢啊……” “哼它浅!你這毒婦竟也來了译柏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤姐霍,失蹤者是張志新(化名)和其女友劉穎鄙麦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镊折,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡胯府,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恨胚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骂因。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赃泡,靈堂內(nèi)的尸體忽然破棺而出寒波,到底是詐尸還是另有隱情,我是刑警寧澤升熊,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布俄烁,位于F島的核電站,受9級特大地震影響级野,放射性物質(zhì)發(fā)生泄漏页屠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一蓖柔、第九天 我趴在偏房一處隱蔽的房頂上張望辰企。 院中可真熱鬧,春花似錦况鸣、人聲如沸牢贸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽十减。三九已至栈幸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帮辟,已是汗流浹背速址。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留由驹,地道東北人芍锚。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像蔓榄,于是被迫代替她去往敵國和親并炮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容