欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android OpenGL正交投影

程序员文章站 2023-12-24 22:09:15
...

Android OpenGL正交投影

首先申明下,本文为笔者学习《OpenGL ES应用开发实践指南》的笔记,并加入笔者自己的理解和归纳总结。

1、正交投影

在OpenGL里,渲染的一切物体都要映射到x轴和y轴上[-1, 1]的范围内,这个范围的坐标被称为归一化设备坐标,其独立于屏幕实际的尺寸或形状。
但在横屏模式下,东西会被压扁。

Android OpenGL正交投影
我们一般会先在虚拟坐标空间里工作,通过正交投影把虚拟空间坐标转换回归一化设备坐标

2、矩阵

矩阵是一个有多个元素的二维数组。在OpenGL里,使用矩阵作向量投影,如正交和透视投影,也用它们使物体旋转、平移和缩放。
(1) 单位矩阵
单位矩阵如下图所示

Android OpenGL正交投影
单位矩阵乘以任何向量总是得到与原来相同的向量。
Android OpenGL正交投影
(2) 平移矩阵
平移矩阵可以把一个物体沿着指定距离移动。

Android OpenGL正交投影
一个位置为(2, 2)的向量,沿x轴平移3,沿y轴平移3。把x赋值为3,把y也赋值为3。
Android OpenGL正交投影

3、定义正交投影

Matrix的orthoM方法可以生成一个正交投影
orthoM(float[] m, int mOffset, float left, float right, float bottom, float top,
                float near, float far)
  • float[] m:目标数组,存储正交投影矩阵
  • int mOffset:结果矩阵起始的偏移量
  • float left:x轴的最小范围
  • float right:x轴的最大范围
  • float bottom:y轴的最小范围
  • float top:y轴的最大范围
  • float near:z轴的最小范围
  • float far:z轴的最大范围
当我们调用这个方法的时候,应该会产生下面的正交投影矩阵。
Android OpenGL正交投影

4、着色器文件

(1) 顶点着色器,ortho_vertex_shader.glsl文件
添加u_Matrix变量,意思是这个uniform代表4x4的矩阵。

uniform mat4 u_Matrix;

attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;

void main()
{
    v_Color = a_Color;

    gl_Position = u_Matrix * a_Position;
    gl_PointSize = 10.0;
}
(2) 片段着色器,ortho_fragment_shader.glsl文件
precision mediump float;

varying vec4 v_Color;

void main()
{                    	
    gl_FragColor = v_Color;
}

5、绘制着色器

(1) 传递矩阵给着色器
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
(2) OpenGLOrthoShaderRender类
private class OpenGLOrthoShaderRender implements GLSurfaceView.Renderer {
	private final static String A_POSITION = "a_Position";
	private final static String A_COLOR = "a_Color";
	private final static String U_MATRIX = "u_Matrix";

	private static final int POSITION_COMPONENT_COUNT = 2;
	private static final int COLOR_COMPONENT_COUNT = 3;
	private static final int BYTES_PER_FLOAT = 4;
	private static final int STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT)
			* BYTES_PER_FLOAT;

	private float[] projectionMatrix = new float[16];
	private FloatBuffer vertexData;
	private int mProgramId;
	private int aPositionLocation, aColorLocation, uMatrixLocation;

	OpenGLOrthoShaderRender() {
		float[] tableVerticesWithTriangles = {
				// 中心点
				0f, 0f, 1f, 1f, 1f,

				// 四个角
				-0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
				 0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
				 0.5f,  0.8f, 0.7f, 0.7f, 0.7f,
				-0.5f,  0.8f, 0.7f, 0.7f, 0.7f,
				-0.5f, -0.8f, 0.7f, 0.7f, 0.7f,

				// 直线
				-0.5f, 0f, 1f, 0f, 0f,
				0.5f, 0f, 1f, 0f, 0f,

				// 点
				0f, -0.25f, 0, 0, 1,
				0f,  0.25f, 1, 0, 0
		};

		vertexData = ByteBuffer
				.allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		vertexData.put(tableVerticesWithTriangles);
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

		mProgramId = useProgram(R.raw.ortho_vertex_shader, R.raw.ortho_fragment_shader);

		// 获取Attribute位置
		aPositionLocation = GLES20.glGetAttribLocation(mProgramId, A_POSITION);
		aColorLocation = GLES20.glGetAttribLocation(mProgramId, A_COLOR);
		// 获取u_Matrix位置
		uMatrixLocation = GLES20.glGetUniformLocation(mProgramId, U_MATRIX);

		vertexData.position(0);
		GLES20.glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT,
				GLES20.GL_FLOAT, false, STRIDE, vertexData);
		GLES20.glEnableVertexAttribArray(aPositionLocation);

		vertexData.position(POSITION_COMPONENT_COUNT);
		GLES20.glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT,
				GLES20.GL_FLOAT, false, STRIDE, vertexData);
		GLES20.glEnableVertexAttribArray(aColorLocation);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		GLES20.glViewport(0, 0, width, height);

		final float aspectRatio = width > height ?
				(float)width / (float)height : (float)height / (float)width;
		if (width > height) {
			Matrix.orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);
		} else {
			Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, -1f, 1f);
		}
	}

	@Override
	public void onDrawFrame(GL10 gl) {
		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

		// 给着色器传递正交投影矩阵
		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);

		// 绘制三角形
		GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);

		// 绘制直线
		GLES20.glDrawArrays(GLES20.GL_LINES, 6, 2);

		// 绘制点
		GLES20.glDrawArrays(GLES20.GL_POINTS, 8, 1);

		// 绘制点
		GLES20.glDrawArrays(GLES20.GL_POINTS, 9, 1);
	}

}
显示如下
Android OpenGL正交投影


上一篇:

下一篇: