基于 NXP i.MX8QM Bumblebee 智能座舱 GPU Cluster Demo

一. 前言

这篇博文主要是向大家介绍使用 openGL ES 来做仪表盘的 Demo 显示 ,从 GPU 环境搭建到用怎么使用 openGL ES 顶点图形绘制 ,纹理贴图 ,及顶点坐标位置变化等知识 ,通过这篇博文的介绍希望能帮助大家加快导入 GPU 开发进度。

二. GPU 环境搭建 

2.1 硬件环境
使用 i.MX8QM Bumblebee 智能座舱

2.2 软件环境
2.2.1 下载三角形渲染的 Demo 程序
下载 binaries_gpu_userspace_vtk_6.2.4.zip ,下载地址为 : https://nxp.flexnetoperations.com/control/frse/download?element=10553047
解压 binaries_gpu_userspace_vtk_6.2.4.zip 得到以下三个文件:


                                          图1 binaries_gpu_userspace_vtk_6.2.4.zip 解压文件


在 Vivante_VTK 下面有 vEmulator.zip 文件里的 vEmulator 选择 x64 Setup进行安装


                                            图2 vEmulator 安装路径


在 C:\Program Files (x86)\Vivante\vEmulator\x64\ 目录下我们将看到以下文件
可以看到 vEmulator Demo 程序就在下面目录中 :
C:\Program Files (x86)\Vivante\vEmulator\x64\samples\es20\tutorial1


                                                                         图3 vEmulator Demo 程序目录

tutorial1.cpp 是应用程序部分 ,vs_es20t1.vert 是顶点函数处理部分 ,ps_es20t1.frag 是片元函数处理部分

2.2.2 搭建 openGL ES windows 运行环境
安装 Microsoft Visual Studio 2015
安装教程: http://c.biancheng.net/cpp/html/3386.html

选择 tutorial3.vcproj 点击右键,用鼠标点选属性,将链接器常规的附加库目录设置为 Vivante\vEmulator\x64\lib


                                                图4 在 visual stadio 上设置 openGL ES 路径

2.3 实现渲染的 Demo
编译 Demo 程序 ,将 Debug 的环境选择为 x64


                                                                 图5  Debug 的环境选择为 x64

编译完成后再 C:\Program Files (x86)\Vivante\vEmulator\x64\samples\es20\output\Debug\tutorial3.exe


                                                    图5 tutorial3 Demo 程序演示

以上便实现了在 windows 上对 openGL ES 的环境搭建 ,可以在  windows 上把程序开发完成后移植到 Linux 上运行

三. 实现仪表盘 Demo

3.1 纹理贴图
我们首先定义四个顶点坐标,组成一个四边形 ,然后把背景图片贴到这个四边形上

const GLfloat vertices[VERTEX_COUNT][4] =
{
  // Position, texture coordinates
  { -1.0f, 1.0f, 0.0f, 1.0f},
  { 1.0f, 1.0f, 1.0f, 1.0f},
  { -1.0f, -1.0f, 0.0f, 0.0f},
  { 1.0f, -1.0f, 1.0f, 0.0f}
};

其中 const GLfloat vertices[VERTEX_COUNT][0] ,const GLfloat vertices[VERTEX_COUNT][1] 是对应的顶点坐标 ;const GLfloat vertices[VERTEX_COUNT][2] ,
const GLfloat vertices[VERTEX_COUNT][3] 对应的是纹理贴图的坐标 

创建纹理 :

void CreateTexture()
{
  glGenTextures(1, &texObj);
  glActiveTexture(GL_TEXTURE0); //选择当前活跃的纹理单元0
  glBindTexture(GL_TEXTURE_2D, texObj); //绑定纹理目标
  glUniform1i(locSampler2D, 0);
}

以下是添加处理纹理贴图的代码 :

void TextureProcess(const char * filename)
{
  GLint bitmapFormat = 0;
  GLuint width = 0;
  GLuint height = 0;
  GLenum format = 0;
  GLenum type = 0;

  //printf("== start ReadBitmap === \r\n");

  pTexData = ReadBitmap(filename, &width, &height, &bitmapFormat);
  if (pTexData == NULL)
  return;

  GetTexFormat(bitmapFormat, &format, &type);

  if (bitmapFormat == BGR_888)
  {
     WriteBitmap(filename,pTexData,width,height,0,bitmapFormat,1);
  }

  glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, pTexData); //根据指定的参数生成 2D 纹理

  //线性滤图
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

  // Get texture sampler
  locSampler2D = glGetUniformLocation(programHandle, "sampler");
  locFragsel = glGetUniformLocation(programHandle, "fragsel");


  free(pTexData);

  glUniform1i(locFragsel, 1);
  glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 16, &vertices[0][0]);
  glBindTexture(GL_TEXTURE_2D, texObj);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, VERTEX_COUNT);
}
BMP 图片默认的格式是 BGR888 ,由于 openGL ES2.0 只能支持 RGB888 ,需要通过 WriteBitmap() 函数进行转换格式

if (bitmapFormat == BGR_888)
{
   WriteBitmap(filename,pTexData,width,height,0,bitmapFormat,1);
}


对 Bitmap.cpp 里面的 WriteBitmap() 函数做如下处理 :

int WriteBitmap(const char * filename,
const void * data,
unsigned int width,
unsigned int height,
unsigned int stride,
int format,
int flip)
{
  .................................................................
  case BGR_888:
  /* No conversion: BGR 888. */
  //fconv(buff, BGR_888, line, BGR_888, width);
  fconv(buff, RGB_888, line, BGR_888, width);
  break;
  .................................................................
}


通过指定 locFragsel 的值来指定片元着色器为纹理贴图还是顶点颜色渲染

void main (void)
{
  if (fragsel == 1)
    gl_FragColor = texture2D(sampler, v_Texcoord);
  else
    gl_FragColor = color;
}


3.2 绘制仪表指针

GLfloat line_vertices[2][2] =
{
  { 0.66f, 0.0f},
  { -0.022f, 0.6f},
};

GLfloat line_vertices_1[2][2] =
{
  { -0.665f, 0.016f},
  { -0.022f, 0.6f},
};

glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0, &line_vertices[0][0]);
glVertexAttribPointer(locColors, 2, GL_FLOAT, GL_FALSE, 0, &color[0][0]);
glLineWidth(8);  // 指针的宽度
glDrawArrays(GL_LINES,0,2);

3.3 计算仪表指针转动轨迹
在直角三角形 ABC 中(其中角 C 为 90°),角 A 的余弦就是它的临边长度和三角形斜边长度的比值,如下图所示,cosA = b / c


要得出 B 点相对A 点的长度 ,得出 B 点的绝对坐标 :x =(B点坐标 -A点坐标)* cos(A) = b/c , y =(B点坐标 -A点坐标)* sin(A)= b/c ;
以下是通过角度的变化来显示两个指针的位置

#define MAX_ANGLE 300.0f
#define CLUSTER_LEN 0.5f
#define CLUSTER_START 230.0f
// Actual rendering here.
void Render()
{
  static GLfloat angle = CLUSTER_START;
  static GLfloat angle1 = CLUSTER_START;
  static GLuint count = 0;
  static GLuint Revertflag = 1;
  static GLuint Revertflag1 = 1;

  // Clear background.
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  TextureProcess("./cluster.bmp");

  glUniform1i(locFragsel, 2);
  if (Revertflag == 0)
  {
    angle += 1.5f;
    if ((angle >= CLUSTER_START)&&(angle < MAX_ANGLE))
    Revertflag = 1;

    if(angle >= 360.0f)
    angle = 0.0f;
  }
  else
  {
    angle -= 1.5f;
    if (angle <= 0.0f)
    angle = 360.0f;

    if ((angle > CLUSTER_START)&&(angle <= MAX_ANGLE))
      Revertflag = 0;
  }

  line_vertices[1][0] = (GLfloat)cos(angle*PI/180.0f)*((CLUSTER_LEN*9)/23) + line_vertices[0][0];
  line_vertices[1][1] = (GLfloat)sin(angle*PI/180.0f)*CLUSTER_LEN + line_vertices[0][1];

  //printf("line_vertices[1][0]:%03f,line_vertices[1][1]:%03f ,angle:%03f \r\n",line_vertices[1][0],line_vertices[1][1],angle);
  glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0, &line_vertices[0][0]);
  glVertexAttribPointer(locColors, 2, GL_FLOAT, GL_FALSE, 0, &color[0][0]);
  glLineWidth(8);
  glDrawArrays(GL_LINES,0,2);


  if (Revertflag1 == 0)
  {
    angle1 += 1.0f;
    if ((angle1 >= CLUSTER_START)&&(angle1 < MAX_ANGLE))
    Revertflag1 = 1;

    if (angle1 >= 360.0f)
    angle1 = 0.0f;
  }
  else
  {
    angle1 -= 1.0f;
    if (angle1 <= 0.0f)
    angle1 = 360.0f;

    if ((angle1 > CLUSTER_START)&&(angle1 <= MAX_ANGLE))
    Revertflag1 = 0;
  }

  line_vertices_1[1][0] = (GLfloat)cos(angle1*PI/180.0f)*((CLUSTER_LEN*9)/23) + line_vertices_1[0][0];
  line_vertices_1[1][1] = (GLfloat)sin(angle1*PI/180.0f)*CLUSTER_LEN + line_vertices_1[0][1];

  glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0, &line_vertices_1[0][0]);
  glVertexAttribPointer(locColors, 2, GL_FLOAT, GL_FALSE, 0, &color[0][0]);
  glLineWidth(8);
  glDrawArrays(GL_LINES,0,2);
}



3.4 仪表盘双指针 Demo


                                    图6 仪表盘双指针 Demo 


四. 参考文档

【1】OpenGLES3.0 Programing Guide.pdf    Second Edition Dan Ginsburg  Budirijanto Purnomo  With Earlier Contributions From
          Dave Shreiner   Aaftab Munshi

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论