上篇我们简单的学习了纹理的显示,这篇我们先把图片等比显示,然后使纹理和颜色叠加显示。
如果图片是正方形,直接使用缩放或投影即可,但是如果非正方形则需要计算图片的宽高比,然后和显示的宽高比一起计算得到真正的缩放,计算公式:比例=显示宽/显示高/(图片宽/图片高)。随后设置观察点,计算
@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);