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ū)域外的所有東西都會被裁剪掉,如下圖所示
創(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)生下面的正交投影矩陣:
這個正交投影矩陣會把所有在左右之間、上下之間和遠近之間的事物映射到歸一化設備坐標中從-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
|