上篇我們簡單的學習了紋理的顯示,這篇我們先把圖片等比顯示,然後使紋理和顏色疊加顯示。
如果圖片是正方形,直接使用縮放或投影即可,但是如果非正方形則需要計算圖片的寬高比,然後和顯示的寬高比一起計算得到真正的縮放,計算公式:比例=顯示寬/顯示高/(圖片寬/圖片高)。隨後設置觀察點,計算
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
super.onSurfaceChanged(gl, width, height);
// 根據圖片寬高比和屏幕寬高比把紋理顯示爲正常比例(不拉伸)
float ratio = (float) width / height / imageWH;
// 設置透視投影矩陣,近點是3,遠點是7
Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
Matrix.setLookAtM(tempMatrix, 0, 0, 0, 4f,
0f, 0f, 0f,
0f, 1f, 0f);
Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, tempMatrix, 0);
}
當然我們使用投影和顏色疊加需要修改我們的着色器代碼,要定義投影變量和顏色變量。着色器代碼如下
vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 aPos;" +
"attribute vec2 aTextCoord;" +
"varying vec2 TextCoord;" +
"attribute vec3 aColor;" +
"varying vec3 ourColor;" +
"void main() {" +
" gl_Position = uMVPMatrix * aPos;" +
" ourColor = aColor;" +
" TextCoord = aTextCoord;" +
"}";
fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D ourTexture;" +
"varying vec2 TextCoord;" +
"varying vec3 ourColor;" +
"void main() {" +
" gl_FragColor = texture2D(ourTexture, TextCoord) * vec4(ourColor, 1.0);" +
"}";
我們還需要定義座標和顏色,使用一個數組存放這些數據,
private float[] vertices = {
// ---- 位置 ---- ---- 顏色 ---- - 紋理座標 -
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1 - 1.0f, // 右上
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1 - 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1 - 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1 - 1.0f // 左上
};
把數據轉換爲FloatBuffer後使用position方法進行定位然後分別設置位置、顏色和紋理,最後設置轉換再進行繪製,
@Override
public void onDrawFrame(GL10 gl) {
super.onDrawFrame(gl);
int shaderProgram = OpenGLUtil.createProgram(vertexShaderCode, fragmentShaderCode);
GLES20.glUseProgram(shaderProgram);
FloatBuffer vertexBuffer = OpenGLUtil.createFloatBuffer(vertices);
vertexBuffer.position(0);
int positionHandle = GLES20.glGetAttribLocation(shaderProgram, "aPos");
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT,
false, 8 * 4, vertexBuffer);
vertexBuffer.position(3);
int colorHandle = GLES20.glGetAttribLocation(shaderProgram, "aColor");
GLES20.glEnableVertexAttribArray(colorHandle);
GLES20.glVertexAttribPointer(colorHandle, 3, GLES20.GL_FLOAT,
false, 8 * 4, vertexBuffer);
vertexBuffer.position(6);
int coordHandle = GLES20.glGetAttribLocation(shaderProgram, "aTextCoord");
GLES20.glEnableVertexAttribArray(coordHandle);
GLES20.glVertexAttribPointer(coordHandle, 2, GLES20.GL_FLOAT,
false, 8 * 4, vertexBuffer);
int textureHandle = GLES20.glGetUniformLocation(shaderProgram, "ourTexture");
//GLES20.glUniform1i(textureHandle, 0);
OpenGLUtil.bindTexture(textureHandle, texture, 0);
int mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
// 將視圖轉換傳遞給着色器
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, vPMatrix, 0);
// 用 glDrawElements 來繪製,mVertexIndexBuffer 指定了頂點繪製順序
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, OpenGLUtil.createShortBuffer(indices));
GLES20.glDisableVertexAttribArray(positionHandle);
GLES20.glDisableVertexAttribArray(colorHandle);
GLES20.glDisableVertexAttribArray(textureHandle);
}
這樣我們就看到了一個沒有縮放的紋理,而且和顏色疊加顯示,效果圖如下
注:我們的計算沒有判斷寬高的顯示是否會超出屏幕(例如:當顯示一個很長的圖片時寬可能會超出屏幕),接下來我們可以修改這部分代碼來處理,
// 根據圖片寬高比和屏幕寬高比把紋理顯示爲正常比例(不拉伸)
float ratio = (float) width / height;
float w = ratio / imageWH, h = 1;
if (w < 0.5f) {
// 寬度超出
w = 0.5f;
// 相應的需要增加垂直方向的比例
h = 0.5f / (ratio / imageWH);
}
// 設置透視投影矩陣,近點是3,遠點是7
Matrix.frustumM(projectionMatrix, 0, -w, w, -h, h, 3, 7);