浏览器版本低!无法浏览完整内容,建议升级或更换浏览器。
OpenGL绘制
下载开发文档
OpenGL绘制简介

iOS SDK开放了OpenGL绘制功能,开发者可利用OpenGL的绘制来实现更多复杂的覆盖物绘制。

BMKMapViewDelegate中的-mapView:onDrawMapFrame:,地图渲染每一帧画面过程中,以及每次需要重绘地图时(例如添加覆盖物)都会调用此接口。开发者可以在这个接口中进行opengl的绘制。

不需要用户自己创建context和buffer,V5.0.0新增OpenGL映射矩阵(getProjectionMatrix)和视图矩阵(getViewMatrix)接口,用于3D绘制场景,具体代码请参考BaiduMap_IOSSDK_Sample BMKOpenGLESPage。

下面代码以在地图上绘制3D立方体为例,介绍如何使用OpenGL绘制接口。

绘制3D立方体
1. 初始化着色器
- (void)init3DShader
{
//顶点着色器
NSString *vertexShader = @"precision highp float;
attribute vec3 aVertex;
attribute vec4 aColor;
uniform mat4 aViewMatrix;
uniform mat4 aProjectionMatrix;
uniform mat4 aTransformMatrix;
uniform mat4 aScaleMatrix;
varying vec4 color;
void main(){
gl_Position = aProjectionMatrix * aViewMatrix * vec4(aVertex, 1.0);
color = aColor;
}";
//片段着色器
NSString *fragmentShader = @"
precision highp float;
varying vec4 color;
void main(){
gl_FragColor = color;
}";
// program对象是可以附加着色器对象的对象
// 创建一个空program并返回一个可以被引用的非零值(program ID)
_program3D = glCreateProgram();
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
GLint vlength = (GLint)[vertexShader length];
GLint flength = (GLint)[fragmentShader length];
const GLchar *vByte = [vertexShader UTF8String];
const GLchar *fByte = [fragmentShader UTF8String];
glShaderSource(vShader, 1, &vByte, &vlength);
glShaderSource(fShader, 1, &fByte, &flength);
//成功编译着色器对象
glCompileShader(vShader);
glCompileShader(fShader);
//成功地将着色器对象附加到program 对象
glAttachShader(_program3D, vShader);
glAttachShader(_program3D, fShader);
//成功的链接program 对象之后
glLinkProgram(_program3D);
//查询由program指定的先前链接的程序对象
_vertexLocation3D = glGetAttribLocation(_program3D, "aVertex");
//表示程序对象中特定统一变量的位置
_viewMatrixLocation3D = glGetUniformLocation(_program3D,"aViewMatrix");
//得到名字为“aProjectionMatrix”在shader中的位置
_projectionMatrixLocation3D = glGetUniformLocation(_program3D,"aProjectionMatrix");
_colorLocation3D = glGetAttribLocation(_program3D,"aColor");
}
2. 准备立方体数据并初始化
- (void)init3DVertext
{
//创建vertex
float vertext[] = {
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0,
1.0, 1.0, 1.0,
0.0, 1.0, 1.0,
};
for (int i = 0; i < 24; i++) {
// 对标墨卡托坐标
_vertext[i] = vertext[i] * 10000;
}
short indices[] = {
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,
};
for (int i = 0; i < 36; i++) {
_indecies[i] = indices[i];
}
float colors[] = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
};
for (int i = 0; i < 32; i++) {
_color[i] = colors[i];
}
}
3. 实现绘制方法
-(void)drawFrameFor3DCube {
if (_program3D == 0) {
[self init3DShader];
[self init3DVertext];
}
GLboolean depthMask = 0;
glGetBooleanv(GL_DEPTH_WRITEMASK,&depthMask);
glUseProgram(_program3D);
glEnable(GL_DEPTH_TEST);
if (depthMask == GL_FALSE) {
glDepthMask(GL_TRUE);
}
glEnableVertexAttribArray(_vertexLocation3D);
glVertexAttribPointer(_vertexLocation3D, 3, GL_FLOAT, false, 0, _vertext);
glEnableVertexAttribArray(_colorLocation3D);
glVertexAttribPointer(_colorLocation3D, 4, GL_FLOAT, false, 0, _color);
BMKMapPoint center = BMKMapPointForCoordinate(CLLocationCoordinate2DMake(39.965, 116.404));
CGPoint offsetPoint = [self.mapView glPointForMapPoint:center];
float *viewMatrix = [self.mapView getViewMatrix];
translateM(viewMatrix, 0, offsetPoint.x, offsetPoint.y, 0);
float *projectionMatrix = [self.mapView getProjectionMatrix];
//传值函数,该函数的第一个参数是该变量在shader中的位置,第二个参数是被赋值的矩阵的数目。第三个参数表明在向uniform变量赋值时该矩阵是否需要转置
//vec4类型的变量赋值,我们可以使用glUniform4f或者glUniform4fv。v代表数组
glUniformMatrix4fv(_viewMatrixLocation3D, 1, false, viewMatrix);
glUniformMatrix4fv(_projectionMatrixLocation3D, 1, false, projectionMatrix);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, _indecies);
glDisableVertexAttribArray(_vertexLocation3D);
glDisableVertexAttribArray(_colorLocation3D);
glDisable(GL_DEPTH_TEST);
glDepthMask(depthMask);
}
4. 在onDrawMapFrame调用drawFrameFor3DCube进行绘制
/**
地图渲染每一帧画面过程中,以及每次需要重新绘制地图时(例如添加覆盖物)都会调用此方法
@param mapView 地图View
@param status 地图的状态
*/
- (void)mapView:(BMKMapView *)mapView onDrawMapFrame:(BMKMapStatus *)status {
[self drawFrameFor3DCube];
}
5. 运行程序

效果如图:

IMG_0304%202.png

上一篇

自定义瓦片图

下一篇

绘制3D棱柱

本篇文章对您是否有帮助?