1.介绍
这次我们是要用手触摸达到旋转图形的效果,其实代码跟之前的代码没有什么大改动。之前OpenGL ES (9): OpenGL ES 添加运动效果-旋转 已经讲到旋转了,其中Render的简要代码如下:
//旋转矩阵
private float[] mRotationMatrix = new float[16];
public void onDrawFrame(GL10 gl) {
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
float[] scratch = new float[16];
//旋转的角度
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.1f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
mTriangle.draw(scratch);
}
当时我们的旋转角度是由时间简单计算得到的 angle,然后得到旋转矩阵与其它矩阵结合,给mTriangle.draw()绘制。
所以想要达到旋转效果,重点在于需要传入不同的angle,之前是简单计算得到。
这一次我们是监听触摸事件得到angle。
2.代码
在MyGLSurfaceView中重写onTouchEvent()方法,处理触摸事件,并计算得到需要旋转的角度angle,使用Render的get和set方法得到这个angel,然后绘制。
public class MyGLSurfaceView extends GLSurfaceView{
private final MyGLRenderer mRenderer;
public MyGLSurfaceView(Context context){
super(context);
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
mRenderer = new MyGLRenderer();
setRenderer(mRenderer);
//要求渲染器只有在数据改变时才进行重绘,响应触摸改变
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float mPreviousX;
private float mPreviousY;
@Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
if (y > getHeight() / 2) {
dx = dx * -1 ;
}
if (x < getWidth() / 2) {
dy = dy * -1 ;
}
mRenderer.setAngle(
mRenderer.getAngle() +
((dx + dy) * TOUCH_SCALE_FACTOR));
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
}
- 需要注意的是,计算完旋转角度后,需要调用requestRender()方法来告诉渲染器是时候渲染帧画面了
- 还要用setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY)方法要求渲染器只有在数据改变时才进行重绘,否则这对性能没有任何影响
Render代码如下:
public class MyGLRenderer implements GLSurfaceView.Renderer {
private Triangle mTriangle;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mTriangle = new Triangle();
}
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
//旋转矩阵
private float[] mRotationMatrix = new float[16];
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
@Override
public void onDrawFrame(GL10 gl) {
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
float[] scratch = new float[16];
//传入触摸响应的角度,得到旋转矩阵
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 1f, 0f);
// long time = SystemClock.uptimeMillis() % 4000L;
// float angle = 0.1f * ((int) time);
// Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
mTriangle.draw(scratch);
}
//编译着色器
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
//angle的set和get方法
public volatile float mAngle;
public float getAngle() {
return mAngle;
}
public void setAngle(float angle) {
mAngle = angle;
}
}
Triangle的代码不变,如下:
public class Triangle{
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = {
// in counterclockwise order:
0.5f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
};
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 0.0f};
public Triangle() {
ByteBuffer bb = ByteBuffer.allocateDirect(
triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(triangleCoords);
vertexBuffer.position(0);
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix) {
GLES20.glUseProgram(mProgram);
//获取着色器程序内成员变量的id,也可以理解为句柄、指针。
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//启用该id,句柄
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(
mPositionHandle,
COORDS_PER_VERTEX,
GLES20.GL_FLOAT,
false,
vertexStride,
vertexBuffer
);
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//获取着色器程序内成员变量的id,也可以理解为句柄、指针。
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//指定要修改的着色器中uMVPMatrix变量id
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
运行程序,手滑动屏幕可以旋转图形。