Android opengles 实现触碰屏幕,根据运动轨迹画直线的功能

  • 目录
    • 引言
    • 第一步,先自己学会绘制一条固定坐标的直线
    • 第二步,动态的绘制一条直线
    • 第三步,坐标转换
    • 第四步,绘制多条直线
    • 代码

目录

补一张效果图:

在手机里显示线很清楚的,可能是屏幕录制帧数太低了,显示出来都看不清,实际是没问题的,有机会用另一个手机拍屏幕传一个吧,2333.

宽度加粗了4倍,这下应该能看清楚了hhhh。

引言

由于项目功能需要,要做一个能自定义画直线的功能,网上找了许多文章或项目demo,没找到画直线的,反而是更进一步的实现类似“绘画板”功能的代码和教程较多;但是,这样的功能下,假如使用者想画一个规则的图形——比如直线,那么必须手不能抖笔直的画出来才行,应用到我这个项目里的话实在太反人类了,很不合适,于是就只好自己做了。

由于本人实力有限,也是刚接触opengles这玩意,磨磨蹭蹭拼拼凑凑了好几天总算是勉强实现了画直线的功能。

其实,做着做着就感觉这东西和android开发基本没啥关系了,无非就是android给他做了界面与交互而已,不过后续也要学习Opengl的也算是开个头吧,唠叨有点多了,下面是正文。

按步骤来说,想要实现根据手指运动轨迹画直线主要有以下几个要点:

  1. 实现一条固定坐标的直线的绘制----->>>>手动绘制一条直线
  2. 实现 屏幕坐标向opengles坐标的转换
  3. 任意绘制多条直线

第一步,先自己学会绘制一条固定坐标的直线

如何绘制一条直线参考官方文档里的三角形案例可以轻松实现,有现成案例,很多博主也是根据这些内容写的教程:https://developer.android.com/training/graphics/opengl/environment
本文是也是基于官方文档的三角形绘制案例改写的,具体如何绘制固定直线。
由于我没有中途保存过绘制直线的代码,下面提供的是已经实现自定义画线功能后的代码了,建议自己实现绘制一条固定坐标直线后再看后面的内容。

第二步,动态的绘制一条直线

仅仅实现这个功能其实也很简单,在renderer或者glsurfaceView里设置一个触摸事件,动态的更新直线类中的起点与终点的坐标即可。相关事件参考代码如下:(重点是事件内容)
Activity中设置时间的oncreate函数如下:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);glSurfaceView = new OneGlSurfaceView(this);mRenderer = new OneGlRenderer();glSurfaceView.setRenderer(mRenderer);setContentView(glSurfaceView);glSurfaceView.setOnTouchListener(this);//给view监听触摸事件}

之后是重写的Touch事件

@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {/*** 点击的开始位置*/case MotionEvent.ACTION_DOWN:float[] out = mRenderer.handleTouch(event.getX(),event.getY(),mRenderer.straightLine);currentLines = new StraightLine(new float[] {0, 0, 0});currentLines.setX_start(out[0]);//设置起点x坐标currentLines.setY_start(out[1]);//设置直线起点y坐标 取按下的坐标为起点break;/*** 触屏实时位置*/case MotionEvent.ACTION_MOVE://out数组保存坐标转换后的xyz坐标out = mRenderer.handleTouch(event.getX(),event.getY(),mRenderer.straightLine);Log.i("setPointer", String.format("x: %f, y: %f", event.getX(), event.getY()));Log.i("setPointer", String.format("x-start: %f, y-start: %f, z-start:%f", mRenderer.straightLine.getX_start(), mRenderer.straightLine.getY_start(),mRenderer.straightLine.getZ_start()));Log.i("setPointer", String.format("x-end: %f, y-end: %f, z-end:%f", out[0], out[1],out[2]));Log.i("setPointer", String.format("POS: %d", mRenderer.straightLine.pointBufferPos));currentLines.setX_end(out[0]);//设置直线终点x坐标 currentLines.setY_end(out[1]);//设置直线终点y坐标 随着移动不断更新// out[2]中存着z坐标,但是平面用不上,所以z坐标不变,依旧是固定值0              break;/*** 离开屏幕的位置*/case MotionEvent.ACTION_UP:break;default:break;}/*** 注意返回值* true:view继续响应Touch操作;* false:view不再响应Touch操作,故此处若为false,只能显示起始位置,不能显示实时位置和结束位置*/return true;}

简单解释一下,首先众所周知,Renderer有如下三个默认存在的方法:
onSurfaceCreated() - 调用一次以设置视图的 OpenGL ES 环境。
onDrawFrame() - 每次重新绘制视图时调用。
onSurfaceChanged() - 当视图的几何图形发生变化(例如当设备的屏幕方向发生变化)时调用。
于是,由于每次我们触摸移动,更新坐标以后,图形就发生了变化,需要重新绘制图形,所以会重新调用renderer类当中的onSurfaceChanged()和onDrawFrame()
一般的直线类的绘制函数draw()会放在**onDrawFrame()**里。

第三步,坐标转换

opengl内部的坐标范围是(-1,1),而我们通过触摸事件获取到的是屏幕坐标,想要直接把屏幕坐标作为点的坐标传值肯定是不行的。
有一点需要特别注意的是,GLES20中对于Matrix.frustumM的左右边缘上下界一定要设置为(-1,1)否则会出现坐标转换的分布无法覆盖整个屏幕,从而出现坐标转换的差异。(有不少教程是直选用了部分象限,因而左右的上下界设置为了Ratio的值)
上述代码中,我用了一个out的数组存储坐标转换后的坐标,转换函数我写在了我的Renderer类里,主要是调用了GLU库里的 GLU.gluUnProject()函数,在对得到的坐标,用变换矩阵相乘,由于笔者还没学习图形学,所以具体原理并不是很懂,但是网上有不少教程有对此做说明。
(PS:虽然我看了以后还是一知半解,估计等我学了图形学后就明白了,大概)。

public float[] handleTouch(float rx, float ry,StraightLine line) {float[] near_xyz = line.unProject(rx, ry, 0, mVMatrix, mProjMatrix, viewWidth, viewHeight);return near_xyz;}

UnProject()函数如下.

public float[] unProject(float xTouch, float yTouch, float winz,float[] viewMatrix,float[] projMatrix,int width, int height) {int[] viewport = {0, 0, width, height};float[] out = new float[3];float[] temp = new float[4];float[] temp2 = new float[4];// get the near and far ords for the clickfloat winx = xTouch, winy = (float) viewport[3] - yTouch;int result = GLU.gluUnProject(winx, winy, winz, viewMatrix, 0, projMatrix, 0, viewport, 0, temp, 0);Matrix.multiplyMV(temp2, 0, viewMatrix, 0, temp, 0);if (result == 1) {out[0] = temp2[0] / temp2[3];out[1] = temp2[1] / temp2[3];out[2] = temp2[2] / temp2[3];}return out;}

第四步,绘制多条直线

简单说明一下原理,定义一个直线类的ArrayList,不断的存储直线,每次遍历ArrayList将里面所有的直线类都绘制一遍,没想到吧,你以为是你在原先的画面上一条一条线的加上去的,实际上是每次所有的线都给你重新绘制了一边哒!!!
由于计算机处理速度很快,就给了你一种是一条线一条线加进去的错觉,hhh。
下面放代码,有两种,一种写在Activity里的:

public class StraightLineActivity extends AppCompatActivity implements View.OnTouchListener {private OneGlSurfaceView glSurfaceView;private OneGlRenderer mRenderer;public StraightLine currentLines = null;  //当前绘制的线public List<StraightLine> linesList = new ArrayList<>(); //当前绘制线的表public long frameCount = 0;  //共绘制了多少帧private float ratio;private int viewWidth;private int viewHeight;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);glSurfaceView = new OneGlSurfaceView(this);mRenderer = new OneGlRenderer();glSurfaceView.setRenderer(mRenderer);setContentView(glSurfaceView);//glSurfaceView.setOnTouchListener(this);}@Overrideprotected void onPause() {super.onPause();if (glSurfaceView != null) {glSurfaceView.onPause();}}@Overrideprotected void onResume() {super.onResume();if (glSurfaceView != null) {glSurfaceView.onResume();}}@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {/*** 点击的开始位置*/case MotionEvent.ACTION_DOWN:float[] out = mRenderer.handleTouch(event.getX(),event.getY(),mRenderer.straightLine);currentLines = new StraightLine(new float[] {0, 0, 0});currentLines.setX_start(out[0]);currentLines.setY_start(out[1]);synchronized (linesList) {linesList.add(currentLines);}break;/*** 触屏实时位置*/case MotionEvent.ACTION_MOVE:out = mRenderer.handleTouch(event.getX(),event.getY(),mRenderer.straightLine);Log.i("setPointer", String.format("x: %f, y: %f", event.getX(), event.getY()));Log.i("setPointer", String.format("x-start: %f, y-start: %f, z-start:%f", mRenderer.straightLine.getX_start(), mRenderer.straightLine.getY_start(),mRenderer.straightLine.getZ_start()));Log.i("setPointer", String.format("x-end: %f, y-end: %f, z-end:%f", out[0], out[1],out[2]));Log.i("setPointer", String.format("POS: %d", mRenderer.straightLine.pointBufferPos));currentLines.setX_end(out[0]);currentLines.setY_end(out[1]);currentLines.draw(mRenderer.mProjMatrix,mRenderer.mVMatrix);break;/*** 离开屏幕的位置*/case MotionEvent.ACTION_UP:synchronized (linesList) {linesList.add(currentLines);}break;default:break;}/*** 注意返回值* true:view继续响应Touch操作;* false:view不再响应Touch操作,故此处若为false,只能显示起始位置,不能显示实时位置和结束位置*/return true;}
}

另一种,写render里的这种方法得现在SurfaceView里重写onTouchEvent

@Overridepublic boolean onTouchEvent(MotionEvent event) {renderer.setPointer(event);return true;}

然后,renderer里写**setPointer()**方法

public void setPointer(MotionEvent event) {this.x = event.getX();this.y = event.getY();this.z = 0f;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:currentLines = new GLLine();synchronized (linesList) {linesList.add(currentLines);}break;case MotionEvent.ACTION_MOVE:Log.i("setPointer", String.format("x: %f, y: %f", x, y,z));this.x = x / height * 4f;this.y = -y / height * 4f;this.z = 0;currentLines.drawLine(x, y,z);break;case MotionEvent.ACTION_UP:break;}}

以上两种方法都可以。
到这里位置,理论上来说肯定是可以实现画多条线了,但是笔者当时到这一步以后发现还是只能绘制一条直线,排查了半天终于发现了问题所在。
由于我是参考的官方文档的draw()方法,里面有一句:

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

没注释掉这句的话,每次绘制他都会吧之前的清空掉,说是清空,其实就是全变成透明色了,前面的线重新绘制的时候就没了,每次就只剩下最后一次绘制的线了。

public class StraightLineActivity extends AppCompatActivity implements View.OnTouchListener {private OneGlSurfaceView glSurfaceView;private OneGlRenderer mRenderer;public StraightLine currentLines = null;  //当前绘制的线public List<StraightLine> linesList = new ArrayList<>(); //当前绘制线的表public long frameCount = 0;  //共绘制了多少帧private float ratio;private int viewWidth;private int viewHeight;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);glSurfaceView = new OneGlSurfaceView(this);mRenderer = new OneGlRenderer();glSurfaceView.setRenderer(mRenderer);setContentView(glSurfaceView);//glSurfaceView.setOnTouchListener(this);}@Overrideprotected void onPause() {super.onPause();if (glSurfaceView != null) {glSurfaceView.onPause();}}@Overrideprotected void onResume() {super.onResume();if (glSurfaceView != null) {glSurfaceView.onResume();}}
}

代码

由于本身也是参考了很多网上开源的资源做出来的,所以会各种相似,希望大家不要介意。
(1)在XML文件里面申明Opengles的使用

    <!-- Tell the system this app requires OpenGL ES 3.0. --><uses-feature android:glEsVersion="0x00030000" android:required="true" />

(2)GLSurfaceView
这个很简单,我的理解是基本就是给图形一个显示的空间,本身并不复杂,无需过多关注。

public class OneGlSurfaceView extends GLSurfaceView {private OneGlRenderer mRenderer;public OneGlSurfaceView(Context context) {super(context);// Create an OpenGL ES 2.0 contextsetEGLContextClientVersion(2);// Set the Renderer for drawing on the GLSurfaceView//setRenderer((Renderer) mRenderer);}@Overridepublic boolean onTouchEvent(MotionEvent event) {mRenderer.setPointer(event);return true;}@Overridepublic void setRenderer(Renderer renderer) {super.setRenderer(renderer);this.mRenderer = (OneGlRenderer) renderer;}
}

(3)Renderer类

public class OneGlRenderer implements Renderer, com.example.ty.openglndk.GLSurfaceView.Renderer {int viewWidth, viewHeight;float[] mVMatrix = new float[16];float[] mProjMatrix = new float[16];private int mwidth,mheight;float ratio;StraightLine straightLine;private StraightLine currentLines = null;  //当前绘制的线private List<StraightLine> linesList = new ArrayList<>(); //当前绘制线的表@Overridepublic void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {// Set the background frame colorGLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);}@Overridepublic void onDrawFrame(GL10 gl) {// Redraw background color//GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);// 清除屏幕和深度缓存//gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);   //不加这个可以产生残影(模拟器可以)// 重置当前的模型观察矩阵gl.glLoadIdentity();// 允许设置顶点//GL10.GL_VERTEX_ARRAY顶点数组gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// 允许设置颜色//GL10.GL_COLOR_ARRAY颜色数组gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//反走样gl.glEnable(GL10.GL_BLEND);//线条抗锯齿gl.glEnable(GL10.GL_LINE_SMOOTH);/***************绘制模型**************///StraightLine straightLine = new StraightLine();currentLines = new StraightLine(new float[] {0, 0, 0});currentLines.draw(mProjMatrix,mVMatrix);drawModel(gl);/************************************/// 取消颜色设置gl.glDisableClientState(GL10.GL_COLOR_ARRAY);// 取消顶点设置gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);//绘制结束gl.glFinish();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES20.glViewport(0, 0, width, height);viewWidth = width;viewHeight = height;// 设置透明色为清屏//gl.glClearColor(0, 0, 0, 0);mwidth = width;mheight = height;ratio = (float) width / height;// 设置OpenGL场景的大小,(0,0)表示窗口内部视口的左下角,(w,h)指定了视口的大小gl.glViewport(0, 0, width, height);// 设置投影矩阵gl.glMatrixMode(GL10.GL_PROJECTION);// 重置投影矩阵gl.glLoadIdentity();// 设置视口的大小gl.glFrustumf(-1, 1, -1, 1, 1, 10);//以下两句声明,以后所有的变换都是针对模型(即我们绘制的图形)gl.glMatrixMode(GL10.GL_MODELVIEW);gl.glLoadIdentity();Matrix.frustumM(mProjMatrix, 0, -1, 1, -1, 1, 3, 10);Matrix.setLookAtM(mVMatrix,0, 2,2,9, 0f,0f,0f, 0f,1.0f,0.0f);}public static int loadShader(int type, String shaderCode){// 创造顶点着色器类型(GLES20.GL_VERTEX_SHADER)// 或者是片段着色器类型 (GLES20.GL_FRAGMENT_SHADER)int shader = GLES20.glCreateShader(type);// 添加上面编写的着色器代码并编译它GLES20.glShaderSource(shader, shaderCode);GLES20.glCompileShader(shader);return shader;}public float[] handleTouch(float rx, float ry,StraightLine line) {float[] near_xyz = line.unProject(rx, ry, 0, mVMatrix, mProjMatrix, viewWidth, viewHeight);float[] far_xyz = line.unProject(rx, ry, 1, mVMatrix, mProjMatrix, viewWidth, viewHeight);return near_xyz;}/**帧绘制**/public void drawModel(GL10 gl) {int count = 0;synchronized (linesList) {for(StraightLine line : linesList) {count++;Log.i("drawModel", String.format("调用次数: %d",count));line.draw(mProjMatrix,mVMatrix);}}}public void setPointer(MotionEvent event) {switch (event.getAction()) {/*** 点击的开始位置*/case MotionEvent.ACTION_DOWN:float[] out = handleTouch(event.getX(),event.getY(),currentLines);currentLines = new StraightLine(new float[] {0, 0, 0});currentLines.setX_start(out[0]);currentLines.setY_start(out[1]);//mRenderer.straightLine.x_start=out[0];//mRenderer.straightLine.y_start=out[1];//mRenderer.straightLine.touch(out[0],out[1],0);//mRenderer.straightLine.z_start=out[2];//tvTouchShowStart.setText("起始位置:(" + event.getX() + "," + event.getY());break;/*** 触屏实时位置*/case MotionEvent.ACTION_MOVE://tvTouchShow.setText("实时位置:(" + event.getX() + "," + event.getY());out = handleTouch(event.getX(),event.getY(),currentLines);Log.i("setPointer", String.format("x: %f, y: %f", event.getX(), event.getY()));Log.i("setPointer", String.format("x-start: %f, y-start: %f, z-start:%f", currentLines.getX_start(), currentLines.getY_start(),currentLines.getZ_start()));Log.i("setPointer", String.format("x-end: %f, y-end: %f, z-end:%f", out[0], out[1],out[2]));Log.i("setPointer", String.format("POS: %d", currentLines.pointBufferPos));/*int pos = mRenderer.straightLine.pointBufferPos;if(mRenderer.straightLine.pointBufferPos/3%2!=0){//假如此时顶点数组内的点坐标数量不为偶数mRenderer.straightLine.touch(out[0],out[1],0,pos);mRenderer.straightLine.vertexCount++;}*/currentLines.setX_end(out[0]);currentLines.setY_end(out[1]);//currentLines.draw(mProjMatrix,mVMatrix);//mRenderer.straightLine.x_end=out[0];//mRenderer.straightLine.y_end=out[1];//mRenderer.straightLine.touch(out[0],out[1],0,pos);//mRenderer.straightLine.z_end=out[2];break;/*** 离开屏幕的位置*/case MotionEvent.ACTION_UP://tvTouchShow.setText("结束位置:(" + event.getX() + "," + event.getY());//straightLine.y_end=event.getY()/1000;out = handleTouch(event.getX(),event.getY(),currentLines);//mRenderer.straightLine.x_end=out[0];//mRenderer.straightLine.y_end=out[1];//mRenderer.straightLine.z_end=out[2];//mRenderer.straightLine.touch(out[0],out[1],0);synchronized (linesList) {linesList.add(currentLines);}currentLines.setX_end(out[0]);currentLines.setY_end(out[1]);Log.i("setPointer", String.format("List中直线个数:%d",linesList.size()));Log.i("setPointer", String.format("List中直线1:x1:%f  y1:%f   z1:%f",linesList.get(0).getX_start(),linesList.get(0).getY_start(),linesList.get(0).getZ_start()));Log.i("setPointer", String.format("List中直线1:x2:%f  y2:%f   z2:%f",linesList.get(0).getX_end(),linesList.get(0).getY_end(),linesList.get(0).getZ_end()));break;default:break;}/*** 注意返回值* true:view继续响应Touch操作;* false:view不再响应Touch操作,故此处若为false,只能显示起始位置,不能显示实时位置和结束位置*/}
}

(4)StraightLine 直线类
opengles中直线的绘制需要起始两个点的坐标,并且点的坐标都是3维的,比较关键或者看不懂的内容我都在注释里标注了。
官方文档中只提供了画三角形的实例,但是画三角形的原理与画直线是一样的,所以就根据三角形的案例直接修改了,下面是代码。

public class StraightLine {//顶点着色程序 - 用于渲染形状的顶点的 OpenGL ES 图形代码,官网里直接有提供现成的。private final String vertexShaderCode ="attribute vec4 vPosition;" +"void main() {" +"  gl_Position = vPosition;" +"}";
//片段着色程序 - 用于使用颜色或纹理渲染形状面的 OpenGL ES 代码,同上官网提供。private final String fragmentShaderCode ="precision mediump float;" +"uniform vec4 vColor;" +"void main() {" +"  gl_FragColor = vColor;" +"}";private FloatBuffer vertexBuffer;//节点缓冲区private boolean updateVertex = false;public static float x_start=0.0f;//初始起点坐标public static float y_start=0.5f;public static float z_start=0.0f;public static float x_end=0.5f;//初始终点坐标public static float y_end=-0.5f;public static float z_end=0.0f;// number of coordinates per vertex in this arraystatic final int COORDS_PER_VERTEX = 3;//每3个节点一个坐标float triangleCoords[] = {   // in counterclockwise order:x_start,  y_start, z_start, // tx_end, y_end, z_end};int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;private int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertexfloat[] mMVPMatrix = new float[16];//投影矩阵float[] mMMatrix = new float[16];//变换矩阵,用来做乘法的private float[] mMVMatrix = new float[16];//视角矩阵private float[] position;//位置public StraightLine(float[] position) {this.position = position;// 初始化ByteBuffer,长度为arr数组的长度*4,因为一个float占4个字节ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);// 数组排列用nativeOrderbb.order(ByteOrder.nativeOrder());// 从ByteBuffer创建一个浮点缓冲区vertexBuffer = bb.asFloatBuffer();// 将坐标添加到FloatBuffervertexBuffer.put(triangleCoords);// 设置缓冲区来读取第一个坐标vertexBuffer.position(0);pointBufferPos = 0;//记录当前数组位置int vertexShader = OneGlRenderer.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);int fragmentShader = OneGlRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);// 创建空的OpenGL ES程序mProgram = GLES20.glCreateProgram();// 添加顶点着色器到程序中GLES20.glAttachShader(mProgram, vertexShader);// 添加片段着色器到程序中GLES20.glAttachShader(mProgram, fragmentShader);// 创建OpenGL ES程序可执行文件GLES20.glLinkProgram(mProgram);}public void draw(float[] projMatrix, float[] viewMatrix) {//GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);// 将程序添加到OpenGL ES环境GLES20.glUseProgram(mProgram);// 获取顶点着色器的位置的句柄mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");// 启用三角形顶点位置的句柄GLES20.glEnableVertexAttribArray(mPositionHandle);//准备三角形坐标数据GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false,vertexStride, vertexBuffer);// 获取片段着色器的颜色的句柄mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");/**实现屏幕坐标向坐标转换的核心代码**/Matrix.setIdentityM(mMMatrix, 0);Matrix.translateM(mMMatrix, 0, position[0], position[1], position[2]);Matrix.multiplyMM(mMVMatrix, 0, viewMatrix, 0, mMMatrix, 0);Matrix.multiplyMM(mMVPMatrix, 0, projMatrix, 0, mMVMatrix, 0);// 设置绘制三角形的颜色GLES20.glUniform4fv(mColorHandle, 1, color, 0);// 绘制三角形GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, vertexCount);// 禁用顶点数组GLES20.glDisableVertexAttribArray(mPositionHandle);}public float[] unProject(float xTouch, float yTouch, float winz,float[] viewMatrix,float[] projMatrix,int width, int height) {int[] viewport = {0, 0, width, height};float[] out = new float[3];float[] temp = new float[4];float[] temp2 = new float[4];// get the near and far ords for the clickfloat winx = xTouch, winy = (float) viewport[3] - yTouch;int result = GLU.gluUnProject(winx, winy, winz, viewMatrix, 0, projMatrix, 0, viewport, 0, temp, 0);Matrix.multiplyMV(temp2, 0, viewMatrix, 0, temp, 0);if (result == 1) {out[0] = temp2[0] / temp2[3];out[1] = temp2[1] / temp2[3];out[2] = temp2[2] / temp2[3];}return out;}
}

(5)Activity

public class StraightLineActivity extends AppCompatActivity implements View.OnTouchListener {private OneGlSurfaceView glSurfaceView;private OneGlRenderer mRenderer;public StraightLine currentLines = null;  //当前绘制的线public List<StraightLine> linesList = new ArrayList<>(); //当前绘制线的表public long frameCount = 0;  //共绘制了多少帧private float ratio;private int viewWidth;private int viewHeight;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);glSurfaceView = new OneGlSurfaceView(this);mRenderer = new OneGlRenderer();glSurfaceView.setRenderer(mRenderer);setContentView(glSurfaceView);//glSurfaceView.setOnTouchListener(this);}@Overrideprotected void onPause() {super.onPause();if (glSurfaceView != null) {glSurfaceView.onPause();}}@Overrideprotected void onResume() {super.onResume();if (glSurfaceView != null) {glSurfaceView.onResume();}}
}

美中不足的是,为了能够实时显示直线的轨迹,其实每次最后一条线绘制了两次,按下去拖动的时候显示的是,draw的线条,手指离开时drawmodel才会把它的直线画出来,此时draw的直线也完成了绘制。
(PS:通过加粗线条以后,基本看不出来了,哈哈哈)

 /***************绘制模型**************///StraightLine straightLine = new StraightLine();currentLines = new StraightLine(new float[] {0, 0, 0});currentLines.draw(mProjMatrix,mVMatrix);drawModel(gl);/************************************/

之所以这么做是因为,引入同步机制以后,发现绘制轨迹的时候,由于只取起点与终点,没有中间的轨迹,虽然画的很准,但是在手指起来之前是看不到自己画的线的。

我知道我这么描述你们估计听不懂,想看看啥样子的可以把draw函数注释了自己看看,哈哈哈。如果有大佬知道怎么解决这个问题的欢迎评论。

补个图,注释以后是这样的

参考文献如下:
[1]: https://blog.csdn.net/soely/article/details/79183525
[2]: https://blog.csdn.net/cjzjolly/article/details/81667087?utm_medium=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param_right&depth_1-utm_source=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param_right

Android opengles 实现触碰屏幕,根据运动轨迹画直线的功能相关推荐

  1. android imageview 多点触碰(MultiTouch)实现图片拖拽移动缩放

    刚用android手机 发现手机自带的图片浏览器挺酷 可以用手指移动 缩放 还有动画效果 Intent intent = new Intent(Intent.ACTION_VIEW);         ...

  2. 我们手指触碰屏幕都做了什么?

    1:首先我自定义一个LinearLayout,和TextView,重写它们的onInterceptTouchEvent和onTouchEvent方法,观察它们都返回值. 前者onInterceptTo ...

  3. Android源码解析触碰机制

    分发  dispatchTouchEvent  触碰屏幕时会触发的view方法,原理需要看更深层次的源码,这里可以理解为入口 拦截  onInterceptTouchEvent 消费  onTouch ...

  4. android 处理多点触控手势

    编写:Andrwyw - 原文:http://developer.android.com/training/gestures/multi.html 多点触控手势是指在同一时间有多点(手指)触碰屏幕.本 ...

  5. iOS--触碰响应UIResponder UIGestureRecognizer

    疯狂iOS讲义总结 一.在iOS中,触碰的响应是以响应者链的形式进行的.也就是说,当用户和某个控件交互时,该控件会成为第一响应者(First Responder),第一响应者作为响应者链的开始,交互交 ...

  6. android 防触碰功能,类似打电话时屏幕熄灭

    防触碰功能用到的是android手机的距离感应器 1.申请距离感应器管理者 <span style="white-space:pre"> </span>Se ...

  7. Android基础新手教程——3.4 TouchListener PK OnTouchEvent + 多点触碰

    Android基础新手教程--3.4 TouchListener PK OnTouchEvent + 多点触碰 标签(空格分隔): Android基础新手教程 本节引言: 如题,本节给大家带来的是To ...

  8. android nfc标签类型,Android NFC标签 开发深度解析 触碰的艺术

    原标题:Android NFC标签 开发深度解析 触碰的艺术 本文来自于CSDN博客,作者:郭朝,已获授权,版权归原作者所有,未经作者同意,请勿转载. 欢迎同有博客好文章的作者加微信(ID:tm_fo ...

  9. 【Android 】零基础到飞升 | TouchListener PK OnTouchEvent + 多点触碰

    3.4 TouchListener PK OnTouchEvent + 多点触碰 分类 Android 基础入门教程 本节引言: 如题,本节给大家带来的是TouchListener与OnTouchEv ...

最新文章

  1. db2top详细使用方法_Py之PIL:Python的PIL库的简介、安装、使用方法详细攻略
  2. 优秀的服务器托管服务商的必备要素
  3. rz安装 xshell_利用XShell上传、下载文件(使用sz与rz命令)
  4. springboot 直接转发调用_springboot-过滤器的页面跳转【重定向与请求转发】-异常报错...
  5. if java_Java 条件语句
  6. UCMap移动GIS 时空地图GIS
  7. php cpu mac,PHP 获得计算机的唯一标识[CPU,网卡 MAC地址]
  8. Find a girl friend
  9. 华为产品技术学习笔记之路由原理(一)
  10. jQuery load() 中文乱码
  11. c++ 编写函数返回两个值最小值_结合实例来分析SQL的窗口函数
  12. 蓝桥杯第六届省赛JAVA真题----打印菱形
  13. 培养用户习惯才是软件的唯一出路!
  14. 数据结构—二叉排序树
  15. 塞雷三分钟漫画中国史1
  16. MatrixOne混沌测试之道
  17. 关于网站项目计划书的写法
  18. Dest0g3 520迎新赛WP
  19. 数学建模基本算法模型
  20. “硬核”刘强东是怎么炼成的?

热门文章

  1. 报表在linux下部署后中文变成小方块
  2. HTMLCSS学习笔记(二十四)——利用border属性制作太极图与哆啦A梦
  3. Module containing this breakpoint has not yet loaded or the breakpoint adress could not be obtained.
  4. H5 百度高德地图导航
  5. word2vec的应用:gensim相似度检测(附代码)
  6. 第四章课后习题-用Python实现羊车门问题,最大公约数计算,猜字游戏,统计不同字符个数。
  7. Go语言IDE GoLand的BUG
  8. 欧拉函数(求与n互质的数的个数)
  9. 保研历程(经验分享、保研流程介绍)
  10. java中任何变量都可以被赋值为null,java中当给一个对象赋值为null时发生了什么...