利用OpenGL ES、手机传感器、相机和调用百度语音包服务,实现AR+语音播报导航功能(导航功能为模拟,Android)

Demo展示:

几个重要模块

GLSurfaceView:

1.首先需要自定义类实现GlsurfaceView.Renderer接口

public abstract class AbstractMyRender implements GLSurfaceView.Renderer {

    public float ratio;
//    围绕X轴旋转的角度
    public float xrotate = 0f;
//    围绕Y轴旋转的角度
    public float yrotate = 0f;
//    围绕Z轴旋转的角度
    public float zrotate = 0f;
    /*
            这是第一步
     */

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//        清屏色
        gl10.glClearColor(0f,0f,0f,1f);
//        启用顶点缓冲区数组
        gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    }
    /*
            这是第二步
     */
    @Override
    public void onSurfaceChanged(GL10 gl10, int i, int i1) {
//设置视口
        gl10.glViewport(0,0,i,i1);
        ratio = (float)i/(float)i1;
//      投影矩阵
        gl10.glMatrixMode(GL10.GL_PROJECTION);
//      加载单位矩阵
        gl10.glLoadIdentity();
//      设置平截头体
        gl10.glFrustumf(-ratio,ratio,-1,1,3f,7f);
    }
    /*
            这是第三步
     */
    public  abstract void onDrawFrame(GL10 gl10);
}

2.定义子类继承自定义类并复写其中的方法(可以绘制不同的图案),例如绘制颜色立方体可以定义子类MyColorCubeRenderer

public class MyColorCubeRenderer extends AbstractMyRender {
    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//        清屏色
        gl10.glColor4f(0,0,0,1f);
//        启动顶点缓冲区数组
        gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//        颜色缓冲区
        gl10.glEnableClientState(GL10.GL_COLOR_ARRAY);
//        启用深度测试
        gl10.glEnable(GL10.GL_DEPTH_TEST);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int i, int i1) {
//        设置视口
        gl10.glViewport(0,0,i,i1);
        ratio = (float)i/(float)i1;
//        投影矩阵
        gl10.glMatrixMode(GL10.GL_PROJECTION);
//        加载单位矩阵
        gl10.glLoadIdentity();
//        设置平截头体
        gl10.glFrustumf(-ratio,ratio,-1f,1f,3f,7f);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        gl10.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
        gl10.glColor4f(1f,0f,0f,1f);
//        模型视图矩阵
        gl10.glMatrixMode(GL10.GL_MODELVIEW);
        gl10.glLoadIdentity();
        GLU.gluLookAt(gl10,0,0,5,0,0,0,0,1,0);
        gl10.glRotatef(xrotate,1,0,0);
        gl10.glRotatef(yrotate,0,1,0);
        gl10.glRotatef(zrotate,0,0,1);
        float r = 0.4f;
//        定义点坐标
        float[] coords = {
//                前面四个点坐标,分别是左上,左下,右上,右下
                -r,r,r,
                -r,-r,r,
                r,r,r,
                r,-r,r,
//                后面四个点坐标
                -r,r,-r,
                -r,-r,-r,
                r,r,-r,
                r,-r,-r
        };
//        定义顶点索引位置
        byte[] indices = {
                0,1,2,2,1,3,//front
                4,5,6,6,5,7,//back
                0,1,4,4,1,5,//left
                2,3,6,6,3,7,//right
                4,0,2,4,2,6,//top
                5,1,3,5,3,7//bottom
        };
//        定义颜色
        float[] colors = {
                0f,1f,1f,1f,//青色
                0,1,0,1,
                1,1,1,1,//白色
                1,1,0,1,//黄色
                0,0,1,1,//4
                0,0,0,1,//5
                1,0,1,1,//6
                1,0,0,1//7
        };
        gl10.glColorPointer(4,GL10.GL_FLOAT,0, BufferUtil.arr2ByteBuffer(colors));
        gl10.glVertexPointer(3,GL10.GL_FLOAT,0,BufferUtil.arr2ByteBuffer(coords));
//        使用顶点索引方式绘制
        gl10.glDrawElements(GL10.GL_TRIANGLES,indices.length, GL10.GL_UNSIGNED_BYTE,BufferUtil.arr2ByteBuffer(indices));
//        使用顶点数组索引方式绘制
//        gl10.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,coords.length/3);

    }
}

在本例中使用的MultiArrow类渲染的图案。(详细代码我会放置于我的github主页上https://github.com/slpslpslp,我渲染类写了有几个,有渲染立方体、渲染线、渲染圆环和球,详细的Android使用opengles教程可以参照https://blog.csdn.net/column/details/apidemoopengl.html)

Camera(相机已被Google弃用,可选择替代)

1.相机预览功能函数

    private void startPreview() {
        camera = Camera.open();
        try {
            camera.setPreviewDisplay(cameraPreview.getHolder());
            camera.setDisplayOrientation(90);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2.相机预览回调函数

private Camera camera;
private SurfaceHolder.Callback cameraPreviewcallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            startPreview();
            Log.i(TAG, "surfaceCreated" + Thread.currentThread().getName());
        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            Log.i(TAG, "surfaceChanged");
            camera.startPreview();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            Log.i(TAG, "surfaceDestoryed");
            if (camera != null) {
                camera.stopPreview();
                camera.release();//释放相机资源
                camera = null;
            }
        }
    };

3.设置相机预览SurfaceView

        cameraPreview = new SurfaceView(this);
        cameraPreview.getHolder().addCallback(cameraPreviewcallback);
        cameraPreview.getHolder().setFormat(PixelFormat.TRANSPARENT);

SensorManager

1.开启传感器服务

SensorManager sensorManager;
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

2.在方向传感器(TYPE_OPIENTATION,已被弃用,可以选择替代)变化的同时,请求渲染

@Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        int sensorType = sensorEvent.sensor.getType();
        switch (sensorType) {
            case Sensor.TYPE_ORIENTATION:
//                获取绕三轴的角度
                float degreeZ = sensorEvent.values[0];
                float degreeX = sensorEvent.values[1];
                float degreeY = sensorEvent.values[2];
                render.xrotate = degreeX;
                render.zrotate = degreeZ;
//                render.yrotate = degreeY;
                glSurfaceView.requestRender();    //请求渲染,和脏渲染配合使用
                break;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }

SpeechSynthesizerListener

百度语音合成接口Api(http://ai.baidu.com/docs#/TTS-Android-SDK/top),下载Android SDK,申请获得APP_ID,API_KEY,SECRET_KEY,填入即可直接使用

    private static final String APP_ID = "YOUR_APP_ID";
    private static final String API_KEY = "YOUR API_KEY";
    private static final String SECRET_KEY = "YOUR SECRET_KEY";

后记:

           这个demo是我当初为了做AR导航做的一个小项目,是自己模拟的一段导航路径,主要是实现打开摄像头将路径进行渲染,通过方向传感器,在手机摆动时而保持导航路径绝对方向不变,在本demo中并没有实际的路网。另外这是一年半以前的代码了,代码写的也比较稚嫩,且现在已忘记很多。所以其中的细节我也没法在这里讲解了,有兴趣的可以下载下来进行扩展改进。

你可能感兴趣的:(Android)