Android OpenGL透视投影

Android OpenGL透视投影

Android OpenGL透视投影

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

1、透视除法

OpenGL会把每个gl_Position的x、y和z分量都除以它的w分量。当w分量用来表示距离的时候,会使得较远处的物体被移动到距离渲染区域中心更近的地方。

添加w分量创建三维图

private static final int POSITION_COMPONENT_COUNT = 4;

float[] tableVerticesWithTriangles = {

// 中心点

0f, 0f, 0f, 1.5f, 1f, 1f, 1f,

// 四个角

-0.5f, -0.8f, 0f, 1f, 0.7f, 0.7f, 0.7f,

0.5f, -0.8f, 0f, 1f, 0.7f, 0.7f, 0.7f,

0.5f, 0.8f, 0f, 2f, 0.7f, 0.7f, 0.7f,

-0.5f, 0.8f, 0f, 2f, 0.7f, 0.7f, 0.7f,

-0.5f, -0.8f, 0f, 1f, 0.7f, 0.7f, 0.7f,

// 直线

-0.5f, 0f, 0f, 1.5f, 1f, 0f, 0f,

0.5f, 0f, 0f, 1.5f, 1f, 0f, 0f,

// 点

0f, -0.25f, 0f, 1.25f, 0, 0, 1,

0f, 0.25f, 0f, 1.75f, 1, 0, 0

};显示如下

2、视椎体

视椎体是一个立方体,其远端比近端大,从而使其变成一个被截断的金字塔。视椎体有一个焦点,当你用透视投影观察一个场景时,那个场景看上去就像你的头被放在了焦点处。焦点和视椎体小端的距离被称为焦距。

3、定义透视投影

Matrix的perspectiveM方法可以生成一个透视投影

perspectiveM(float[] m, int offset,

float fovy, float aspect, float near, float far)

float[] m:目标数组,存储正交投影矩阵int mOffset:结果矩阵起始的偏移量float fovy:视眼角度float aspect:屏幕的宽高比,等于宽度/高度float near:到近处平面的距离,必须是正值。float far:到远处平面的距离,必须是正值且大于到近处平面距离。

投影矩阵,a代表焦距

a = 1.0f / Math.tan((fovy * Math.PI / 180.0f) / 2.0f)

4、绘制着色器

(1) 使用投影矩阵

Matrix.perspectiveM(projectionMatrix, 0, 45, (float)width / (float)height, 1, 10);(2) 在z轴上移动物体,先定义一个modelMatrix模型

Matrix.setIdentityM(modelMatrix, 0);

Matrix.translateM(modelMatrix, 0, 0, 0, -2.8f);(3) 利用模型移动物体

Matrix.multiplyMM(modelProjectionMatrix, 0, projectionMatrix, 0, modelMatrix, 0);

(4) OpenGLPerspectiveShaderRender类

在onSurfaceChanged方法,定义透视矩阵,并使用模型矩阵把数据显示出来。

private class OpenGLPerspectiveShaderRender 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 float[] modelMatrix = new float[16];

private float[] modelProjectionMatrix = new float[16];

private FloatBuffer vertexData;

private int mProgramId;

private int aPositionLocation, aColorLocation, uMatrixLocation;

OpenGLPerspectiveShaderRender() {

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, 1.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);

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);

// 创建透视投影

Matrix.perspectiveM(projectionMatrix, 0, 45, (float)width / (float)height, 1, 10);

// 定义模型矩阵

Matrix.setIdentityM(modelMatrix, 0);

// z轴平移-2.8

Matrix.translateM(modelMatrix, 0, 0, 0, -2.8f);

// 把投影矩阵和模型矩阵相乘

Matrix.multiplyMM(modelProjectionMatrix, 0, projectionMatrix, 0, modelMatrix, 0);

}

@Override

public void onDrawFrame(GL10 gl) {

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

// 给着色器传递正交投影矩阵

GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, modelProjectionMatrix, 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);

}

}显示如下

5、增加旋转

旋转矩阵,绕x轴、y轴和z轴旋转所用矩阵的定义

在modelMatrix进行平移以后,对模型进行旋转操作

Matrix.rotateM(modelMatrix, 0, -60, 1f, 0f, 0f);显示如下

你可能也喜欢

关于月亮的诗词(271首)
365bet有没有app

关于月亮的诗词(271首)

07-27 8312
电竞游戏有哪些介绍2025 高质量的电竞游戏分享
和平精英物资币怎么买
365正规官网

和平精英物资币怎么买

09-08 4313