更新时间:2020-06-23
OpenGL绘制(绘制3D模型)
百度地图SDK为开发者开放了OpenGL绘制接口,以帮助开发者在地图上实现灵活的样式绘制,丰富地图的显示效果和使用体验。
自V4.2.0起,百度地图SDK支持OpenGLES 2.0,请开发者调用OnMapDrawFrameCallback接口的onMapDrawFrame(MapStatus drawingMapStatus)方法来进行绘制,在地图渲染每一帧的过程中,以及每次需要重绘地图时(如添加覆盖物),该接口都会被调用。
自V4.2.0起,旧版的onMapDrawFrame(GL10 gl, MapStatus drawingMapStatus)方法废弃。
绘制3D立方体
下面代码以在地图上绘制3D立方体为例,介绍如何使用OpenGL绘制接口。
定义3D立方体着色器类
private class CubeShader { int mVertex; int mMvpMatrix; int mColor; int mProgram; public CubeShader() { } String vertexShader = "precision highp float;\n" + " attribute vec3 mVertex;//顶点数组,三维坐标\n" + " attribute vec4 mColor;//颜色数组,三维坐标\n" + " uniform mat4 mMvpMatrix;//mvp矩阵\n" + " varying vec4 color;//\n" + " void main(){\n" + " gl_Position = mMvpMatrix * vec4(mVertex, 1.0);\n" + " color = mColor;\n" + " }"; String fragmentShader = "//有颜色 没有纹理\n" + " precision highp float;\n" + " varying vec4 color;//\n" + " void main(){\n" + " gl_FragColor = color;\n" + " }"; public void init() { int vertexLocation = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); GLES20.glShaderSource(vertexLocation, vertexShader); GLES20.glCompileShader(vertexLocation); int fragmentLocation = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); GLES20.glShaderSource(fragmentLocation, fragmentShader); GLES20.glCompileShader(fragmentLocation); mProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(mProgram, vertexLocation); GLES20.glAttachShader(mProgram, fragmentLocation); GLES20.glLinkProgram(mProgram); mVertex = GLES20.glGetAttribLocation(mProgram, "mVertex"); mMvpMatrix = GLES20.glGetUniformLocation(mProgram,"mMvpMatrix"); mColor = GLES20.glGetAttribLocation(mProgram,"mColor"); } }
准备立方体数据并初始化
1、声明所需数据及属性
// 3D立方体顶点绘制顺序列表 private short[] mDrawIndices = { 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3, 0, 1, 3, 1, 2 }; // 3D立方体8个顶点颜色值 private float[] mVertexColors = { 1f, 1f, 0f, 1f, 0f, 1f, 1f, 1f, 1f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f, 0f, 0f, 1f, 0f, 1f, 0f, 1f, 0f, 0f, 1f, 1f }; // 立方体顶点坐标Buffer private FloatBuffer mVertextBuffer; // 顶点绘制顺序Buffer private ShortBuffer mIndexBuffer; // 立方体顶点颜色Buffer private FloatBuffer mColorBuffer; // 3D立方体着色器 private CubeShader mCubeShader;
2、初始化数据
private void initCubeModelData(float width, float height, float depth) { // 对标墨卡托坐标 width = width * 10000 / 2; height = height * 10000 / 2; depth = depth * 10000 / 2; // 立方体8个顶点坐标 float[] vertices = { -width, -height, -0, width, -height, -0, width, height, -0, -width, height, -0, -width, -height, depth, width, -height, depth, width, height, depth, -width, height, depth, }; mVertextBuffer = ByteBuffer.allocateDirect(vertices.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); mVertextBuffer.put(vertices).position(0); // 立方体顶点绘制顺序Buffer ByteBuffer byteBuffer = ByteBuffer.allocateDirect(mDrawIndices.length * 4); byteBuffer.order(ByteOrder.nativeOrder()); mIndexBuffer = byteBuffer.asShortBuffer(); mIndexBuffer.put(mDrawIndices); mIndexBuffer.position(0); // 立方体顶点颜色Buffer ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(mVertexColors.length * 4); byteBuffer1.order(ByteOrder.nativeOrder()); mColorBuffer = byteBuffer1.asFloatBuffer(); mColorBuffer.put(mVertexColors); mColorBuffer.position(0); }
调用OnMapDrawFrameCallback接口绘制
1、创建OnMapDrawFrameCallback实例
BaiduMap.OnMapDrawFrameCallback callback = new BaiduMap.OnMapDrawFrameCallback() { //废弃 @Override public void onMapDrawFrame(GL10 gl, MapStatus drawingMapStatus) { } @Override public void onMapDrawFrame(MapStatus drawingMapStatus) { if (null == mBaiduMap.getProjection()) { return; } drawFrameFor3DCube(drawingMapStatus, 0.2f, 0.2f, 0.3f); } };
2、设置OnMapDrawFrameCallback接口
mBaiduMap.setOnMapDrawFrameCallback(callback);
3、绘制方法
/** * 绘制3D立方体 * @param drawingMapStatus */ private void drawCube(MapStatus drawingMapStatus) { if (null == mCubeShader || null == drawingMapStatus) { return; } // Step1 初始化数据 float[] mvpMatrix = new float[16]; Matrix.setIdentityM(mvpMatrix, 0); // 获取投影矩阵 float[] projectMatrix = mBaiduMap.getProjectionMatrix(); // 获取视图矩阵 float[] viewMatrix = mBaiduMap.getViewMatrix(); Matrix.multiplyMM(mvpMatrix,0, projectMatrix,0, viewMatrix,0); // 绑定地图移动 PointF p1f = mBaiduMap.getProjection().toOpenGLLocation(latlng1, drawingMapStatus); Matrix.translateM(mvpMatrix, 0 , p1f.x, p1f.y, 0); // 设置缩放比例 int scale = 1; Matrix.scaleM(mvpMatrix, 0 , scale, scale, scale); // Step2 开始绘制设置 GLES20.glUseProgram(mCubeShader.mProgram); GLES20.glEnable(GLES20.GL_DEPTH_TEST); // 顶点指针 GLES20.glEnableVertexAttribArray(mCubeShader.mVertex); GLES20.glVertexAttribPointer(mCubeShader.mVertex, 3, GLES20.GL_FLOAT, false, 0, mVertextBuffer); // 颜色指针 GLES20.glEnableVertexAttribArray(mCubeShader.mColor); GLES20.glVertexAttribPointer(mCubeShader.mColor, 4, GLES20.GL_FLOAT,false, 0, mColorBuffer); GLES20.glUniformMatrix4fv(mCubeShader.mMvpMatrix, 1, false, mvpMatrix, 0); // 开始画 GLES20.glDrawElements(GLES20.GL_TRIANGLES, mDrawIndices.length, GLES20.GL_UNSIGNED_SHORT, mIndexBuffer); GLES20.glDisableVertexAttribArray(mCubeShader.mVertex); GLES20.glDisable(GLES20.GL_DEPTH_TEST); }
效果如图: