最通俗的安卓OpenGL教学08——正交投影、矩阵变换
在上几节,我们渲染得到到的图片纹理很明显是被拉升了的,这里我们就要利用正交投影,用矩阵变换来对坐标进行重新计算,使用了正交投影后,不管物体多远多近,物体看起来总是形状、大小相同的。
在OpenGL中要改变顶点坐标的范围,可以用矩形来重新计算,最后再归一化就可以。
正交投影的使用步骤如下:
- 在顶点着色器中添加矩阵
- 根据图形宽高和屏幕宽高计算需要显示的范围
- 使用矩阵进行变换
先看下效果:
1. 在顶点着色器中添加矩阵
attribute vec4 vPosition;
attribute vec2 fPosition;
varying vec2 ft_Position;
uniform mat4 u_Matrix;
void main(){gl_Position = vPosition * u_Matrix;ft_Position = fPosition;
}
2. 根据图形宽高和屏幕宽高计算需要显示的范围
@Overridepublic void onSurfaceChanged(int width, int height) {//设置窗口大小GLES20.glViewport(0, 0, width, height);//只获取一下要加载图片的大小,不加载BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(mContext.getResources(), R.drawable.nobb, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;if (width > height) {Matrix.orthoM(matrix, 0, -width / ((height / imageHeight * 1f) * imageWidth * 1f), width / ((height / imageHeight * 1f) * imageWidth * 1f), -1f, 1f, -1f, 1f);} else {Matrix.orthoM(matrix, 0, -1, 1, -height / ((width / imageWidth * 1f) * imageHeight * 1f), height / ((width / imageWidth * 1f) * imageHeight * 1f), -1f, 1f);}}
3. 使用矩阵进行变换
GLES20.glUniformMatrix4fv(u_matrix, 1, false, matrix, 0);
3. 完整代码
package com.york.media.opengl.demo.bitmap;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.opengl.Matrix;import com.york.media.opengl.R;
import com.york.media.opengl.egl.YGLSurfaceView;
import com.york.media.opengl.egl.YShaderUtil;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;/*** author : York* date : 2020/12/20 17:06* desc : 加入正交投影*/
public class YBitmapOrthogonalRender implements YGLSurfaceView.YGLRender {private final Context mContext;private final FloatBuffer vertexBuffer;private final FloatBuffer fragmentBuffer;private int program;private int vPosition;private int fPosition;private int[] textureIds;private int u_matrix;private final float[] matrix = new float[16];public YBitmapOrthogonalRender(Context context) {this.mContext = context;//顶点坐标float[] vertexData = {-1f, -1f,1f, -1f,-1f, 1f,1f, 1f};//读取顶点坐标vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);vertexBuffer.position(0);//纹理坐标float[] fragmentData = {0f, 1f,1f, 1f,0f, 0f,1f, 0f};//读取纹理坐标fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(fragmentData);fragmentBuffer.position(0);}@Overridepublic void onSurfaceCreated() {//加载顶点着色器 shaderString vertexSource = YShaderUtil.getRawResource(mContext, R.raw.screen_vert_matrix);//加载片元着色器 shaderString fragmentSource = YShaderUtil.getRawResource(mContext, R.raw.screen_frag);//获取源程序program = YShaderUtil.createProgram(vertexSource, fragmentSource);//从渲染程序中得到着顶点色器中的属性vPosition = GLES20.glGetAttribLocation(program, "vPosition");//从渲染程序中得到片元着色器中的属性fPosition = GLES20.glGetAttribLocation(program, "fPosition");//从渲染程序中得到投影的属性u_matrix = GLES20.glGetUniformLocation(program, "u_Matrix");//创建 1个纹理,放入到 int [] textureIds, 一共有 30多个 纹理textureIds = new int[1];GLES20.glGenTextures(1, textureIds, 0);//第三个参数是指从哪儿开始取GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);//设置环绕方式GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//设置过滤方式GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);}@Overridepublic void onSurfaceChanged(int width, int height) {//设置窗口大小GLES20.glViewport(0, 0, width, height);//只获取一下要加载图片的大小,不加载BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(mContext.getResources(), R.drawable.nobb, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;if (width > height) {Matrix.orthoM(matrix, 0, -width / ((height / imageHeight * 1f) * imageWidth * 1f), width / ((height / imageHeight * 1f) * imageWidth * 1f), -1f, 1f, -1f, 1f);} else {Matrix.orthoM(matrix, 0, -1, 1, -height / ((width / imageWidth * 1f) * imageHeight * 1f), height / ((width / imageWidth * 1f) * imageHeight * 1f), -1f, 1f);}}@Overridepublic void onDrawFrame() {//清除屏幕,此处用的是红色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);GLES20.glClearColor(1f, 0f, 0f, 1f);//使用着色器源程序GLES20.glUseProgram(program);GLES20.glUniformMatrix4fv(u_matrix, 1, false, matrix, 0);//使能顶点属性数组,使之有效GLES20.glEnableVertexAttribArray(vPosition);//使能之后,为顶点属性赋值,绑定顶点坐标GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);//使能片元属性数组,使之有效GLES20.glEnableVertexAttribArray(fPosition);//使能之后,为片元属性赋值,绑定纹理坐标GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, fragmentBuffer);//激活纹理 0号GLES20.glActiveTexture(GLES20.GL_TEXTURE0);//绑定 2D纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.nobb);//设置图片 bitmapGLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);bitmap.recycle();//用完及时回收啊//绘制图形GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);//解绑 2D纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);}
}
嗯,看:
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
