LBS 开发微课堂|通过openGL ES轻松实现建筑物渲染及动画

为了让广大开发者

更深入地了解

百度地图开放平台的

技术能力

轻松掌握满满的

技术干货

更加简单地接入

位置服务

我们特别推出了

"位置服务(LBS)开发微课堂"

系列技术案例

第五期的主题是

通过openGL ES轻松实现

建筑物渲染及动画

对于智能穿戴设备的开发者来说,在亲子守护这类应用场景下,精确展示儿童当前的位置信息尤为重要。特别是在复杂的建筑物中,需要能够详尽地指示出儿童所在的建筑物及具体位置。

那么,如何能够在地图上结合定位技术,贴合楼块轮廓,对定位所在的楼块进行自定义纹理展示,并实现当前所在楼栋内的楼层变化的动画效果呢?

今天,我们将详细介绍如何在移动端使用OpenGL ES绘制一个n面棱柱,并探讨纹理贴图、侧面索引的原理及楼层动画的实现过程。

通过代码的方式,帮助开发者更好地理解地图SDK自定义建筑物渲染的整个过程,就让我们一起来学习一下吧!

01 绘制建筑物

1.1 定义顶点与索引

绘制建筑物本质上是绘制n面棱柱体。n面棱柱的顶点数据包括底面顶点、顶面顶点和侧面顶点。

底面和顶面是n边形,侧面由底面和顶面的对应顶点连接而成。

核心代码示例:

// 示例:绘制一个六面棱柱(即长方体)GLfloat vertices[] = {    // 底面顶点    -0.5f, -0.5f, -0.5f,    0.5f, -0.5f, -0.5f,    0.5f, -0.5f,  0.5f,    -0.5f, -0.5f,  0.5f,    // 顶面顶点    -0.5f,  0.5f, -0.5f,    0.5f,  0.5f, -0.5f,    0.5f,  0.5f,  0.5f,    -0.5f,  0.5f,  0.5f};

索引数据用于指定顶点的连接顺序,形成棱柱的各个面。

// 示例索引数据GLushort indices[] = {    // 底面    0, 1, 2, 2, 3, 0,    // 顶面    4, 5, 6, 6, 7, 4,    // 侧面    0, 1, 5, 5, 4, 0,    1, 2, 6, 6, 5, 1,    2, 3, 7, 7, 6, 2,    3, 0, 4, 4, 7, 3};

索引数组

索引数组定义了顶点的连接顺序,从而形成了棱柱的各个面。

侧面生成

通过连接底面和顶面对应的顶点,生成棱柱的侧面。索引数组中的每个侧面由六个顶点组成(两个三角形)。

1.2 顶点着色器和片元着色器

顶点着色器负责处理顶点数据,将其转换为屏幕坐标。

片元着色器负责为每个像素着色。

const char* vertexShaderSource = R"(attribute vec4 vPosition;uniform mat4 uModelViewProjectionMatrix;void main() {    gl_Position = uModelViewProjectionMatrix * vPosition;})";
const char* fragmentShaderSource = R"(precision mediump float;uniform vec4 vColor;void main() {    gl_FragColor = vColor;})";

02 纹理贴图

2.1 纹理坐标

纹理贴图是将二维图像映射到三维模型表面的过程。因此需要定义纹理坐标,并加载纹理图像。

纹理坐标

纹理坐标是一个二维坐标系统,范围为[0, 1]。它定义了如何将纹理图像映射到三维模型的表面上。

// 纹理坐标(示例)GLfloat textureCoords[] = {    0.0f, 0.0f,    1.0f, 0.0f,    1.0f, 1.0f,    0.0f, 1.0f,    // 顶面纹理坐标(重复上述过程)};

2.2 纹理绘制

在绘制函数中,我们需要绑定纹理、设置着色器参数、传递顶点数据和索引数据,然后调用glDrawElements进行绘制。

纹理环绕

当纹理坐标超出 [0, 1] 范围时,OpenGL提供了多种处理方式,如重复(GL_REPEAT)、镜像重复(GL_MIRRORED_REPEAT)、约束到边缘(GL_CLAMP_TO_EDGE)等。

纹理过滤

纹理过滤用于处理纹理在放大或缩小时的像素处理。常用的过滤方式有邻近过滤(GL_NEAREST)和线性过滤(GL_LINEAR)。

// 加载纹理图像(示例)GLuint textureId;glGenTextures(1, &textureId);glBindTexture(GL_TEXTURE_2D, textureId);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

绘制

void draw() {    glUseProgram(program);
    // 设置顶点属性位置    glEnableVertexAttribArray(positionAttribLocation);    glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    // 设置纹理坐标属性位置    glEnableVertexAttribArray(textureAttribLocation);    glVertexAttribPointer(textureAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
    // 绑定纹理    glBindTexture(GL_TEXTURE_2D, textureId);
    // 设置着色器中的矩阵参数(示例)    glUniformMatrix4fv(modelViewProjectionMatrixLocation, 1, GL_FALSE, modelViewProjectionMatrix);
    // 绘制棱柱    glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(GLushort), GL_UNSIGNED_SHORT, indices);
    glDisableVertexAttribArray(positionAttribLocation);    glDisableVertexAttribArray(textureAttribLocation);}

03 楼层动画

实现楼层z轴非线性动画,通过使用顶点着色器(Vertex Shader)来动态修改顶点位置实现。

这种方法可以减少 CPU 到 GPU 的数据传输,提高性能,特别是在顶点数据较多的情况下。

3.1 定义楼层的顶点着色器

定义一个顶点着色器,其中包含一个时间变量和缓动函数,用于计算当前的 Z 坐标偏移。​​​​​​​

// Vertex Shaderattribute vec3 aPosition; // 顶点位置uniform float uTime; // 动画时间,从外部传入uniform float uHeight; // 最大高度
// 缓动函数// 开始和结束时速度较慢,中间加速float easeInOutCubic(float t) {    return t < 0.5 ? 4.0 * t * t * t : (t - 1.0) * (2.0 * t - 2.0) * (2.0 * t - 2.0) + 1.0;}
void main() {    float t = easeInOutCubic(uTime);    float z = uHeight * t; // 计算当前高度    vec3 transformedPosition = vec3(aPosition.xy, aPosition.z + z); // 更新 Z 坐标    gl_Position = vec4(transformedPosition, 1.0);}

缓动函数

缓动函数(Easing Functions)是在动画和运动图形中常用的一种技术,用于创建更加平滑和自然的动画效果。主要用于控制动画的速度变化,使得动画不是以恒定速度进行,而是可以加速或减速,或者两者结合。

3.2 更新时间和高度​​​​​​​

// 更新时间,高度并传递到着色器float time = fmod(currentTime, animationDuration) / animationDuration; // 计算归一化时间glUniform1f(glGetUniformLocation(shaderProgram, "uTime"), time);glUniform1f(glGetUniformLocation(shaderProgram, "uHeight"), buildingHeight);

3.3 渲染循环​​​​​​​

void render() {    // 更新时间    updateDeltaTime();    // 设置时间和高度    glUniform1f(glGetUniformLocation(shaderProgram, "uTime"), time);    glUniform1f(glGetUniformLocation(shaderProgram, "uHeight"), buildingHeight);    // 绘制楼层    drawFloorBuilding();}

04 效果展示

怎么样,你学会了吗?登录百度地图开放平台官网,轻松实现建筑物的渲染及动画效果!

查看路径:

开发者频道>开发文档>Android地图SDK>开发指南>在地图上绘制>绘制3D建筑物(https://lbsyun.baidu.com/faq/api?title=androidsdk/guide/render-map/3dbuilding)

开发者频道>开发文档>iOS地图SDK>开发指南>在地图上绘制>绘制3D建筑物(https://lbsyun.baidu.com/faq/api?title=iossdk/guide/map-render/3dBuilding)

·END·

你还想了解哪些技术内容?

快来评论区留言告诉我们吧!

相关推荐
yqcoder19 分钟前
NPM 包管理问题汇总
前端·npm·node.js
程序菜鸟营25 分钟前
nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)
前端·npm·node.js
bsr198336 分钟前
前端路由的hash模式和history模式
前端·history·hash·路由模式
杨过姑父1 小时前
ES6 简单练习笔记--变量申明
前端·笔记·es6
Sunny_lxm1 小时前
<keep-alive> <component ></component> </keep-alive>缓存的组件实现组件,实现组件切换时每次都执行指定方法
前端·缓存·component·active
咔咔库奇2 小时前
【TypeScript】命名空间、模块、声明文件
前端·javascript·typescript
兩尛3 小时前
订单状态定时处理、来单提醒和客户催单(day10)
java·前端·数据库
又迷茫了3 小时前
vue + element-ui 组件样式缺失导致没有效果
前端·javascript·vue.js
哇哦Q3 小时前
原生HTML集合
前端·javascript·html
SoWhat~3 小时前
随遇随记篇
前端·javascript