在STM32F407上显示3D图形

如您所知,较早的STM具有适当的频率和RAM容量。好吧,如果是这样,那为什么不在这种控制器上运行3D图形呢?是的,没有比这更简单的了!

演示图片

为了显示3D图形,我将一个320x240分辨率的显示器连接到基于STM32F407的STM32F4Discovery板上。不,不是FSMC-此板具有必要的触点。但是,对于我们的实验,普通端口就足够了。
显示器连接如下:
  • CS-> E12
  • RST-> E2
  • RS-> E15
  • 写-> E14
  • RD-> E13
  • D0-> E4
  • D1-> E5
  • D2-> E6
  • D3-> E7
  • D4-> E8
  • D5-> E9
  • D6-> E10
  • D7-> E11


该存储库具有用于三个不同显示选项的类(IL9325,SPFD5408,HX8347D)。


外观

为了绘制3D图形,我很久以前曾经对第一版OpenGL库的一部分进行了一些相似的处理。这是我附加到STM32上的相似之处。该库要求每个像素6个字节(每种颜色2个字节,每个Z缓冲区4个字节)。此版本中STM32F407的内存仅可用于160x120。好吧,那我们将垂直和水平拉伸图像两次。
本课程能够:
1)纹理纹理的大小是2的幂的倍数;
2)Z形剪裁;
3)插入人脸内部顶点的颜色;
4)八个光源的照明计算,并根据距离进行衰减调整。

使用库的过程如下:
首先,您需要初始化库(它将为屏幕分配内存)。然后,与OpenGL一样,您需要配置投影矩阵和视口。
 const int32_t WIDTH=160;
 const int32_t HEIGHT=120;
 const float VISIBLE_ANGLE=60;
 const float NEAR_PLANE=1;
 const float FAR_PLANE=1000;	
 float aspect=static_cast<float>(WIDTH)/static_cast<float>(HEIGHT);
 		
 cSGL.Init(WIDTH,HEIGHT);
 cSGL.Perspective(VISIBLE_ANGLE,aspect,NEAR_PLANE,FAR_PLANE);
 cSGL.SetViewport(0,0,WIDTH,HEIGHT);


实际上,现在您可以以几乎与OpenGL中相同的方式绘制(用于类似的命令)。

例如,您可以指定一个光源:
 cSGL.MatrixMode(CSGL::SGL_MATRIX_MODELVIEW);
 cSGL.LoadIdentity();
 float l0_position[]={0,0,0};
 float l0_ambient[]={0.1,0.1,0.1};
 float l0_diffuse[]={0.7,0.7,0.7};
 float l0_specular[]={1,1,1};
 float l0_shininess[]={1};
 cSGL.Lightfv(CSGL::SGL_LIGHT0,CSGL::SGL_POSITION,l0_position);
 cSGL.Lightfv(CSGL::SGL_LIGHT0,CSGL::SGL_AMBIENT,l0_ambient);
 cSGL.Lightfv(CSGL::SGL_LIGHT0,CSGL::SGL_DIFFUSE,l0_diffuse);
 cSGL.Lightfv(CSGL::SGL_LIGHT0,CSGL::SGL_SPECULAR,l0_specular);
 cSGL.Lightfv(CSGL::SGL_LIGHT0,CSGL::SGL_SHININESS,l0_shininess);


您可以指定表面的材质:
 float m0_ambient[]={0.1,0.1,0.1};
 float m0_diffuse[]={0.5,0.5,0.5};
 float m0_specular[]={0.5,0.5,0.5};
 float m0_emission[]={0.1,0.1,0.1};
 cSGL.Materialfv(CSGL::SGL_AMBIENT,m0_ambient);
 cSGL.Materialfv(CSGL::SGL_DIFFUSE,m0_diffuse);
 cSGL.Materialfv(CSGL::SGL_SPECULAR,m0_specular); 
 cSGL.Materialfv(CSGL::SGL_EMISSION,m0_emission); 


您可以启用照明计算cSGL.Enable(CSGL :: SGL_LIGHTING);以及特定的光源cSGL.Enable(CSGL :: SGL_LIGHT0);
前后均考虑照明。而且,我没有切断后边缘(我很少需要它)。但是,如果您要使其变得有些琐碎。

无需创建光源。您可以使用cSGL.Color3f自己设置脸部的颜色。颜色(以及材料的颜色参数)指定为归一化[0..1];

纹理与cSGL.BindTexture命令连接。请注意,库始终使用纹理!在这种情况下,纹理颜色的数组定义为四个字节(r,g,b,alpha)的序列,此处r,g,b,alpha是从0到255的数字。严格来说,正是这些数字乘以了通道R,G,渲染时由glColor3f指定(或从光源计算得出的)B。在整个显示脸部的过程中,应保留一组纹理数据。

面的结论如下:
  
  cSGL.Begin();
   cSGL.TexCoordf(0,0);	
   cSGL.Vertex3f(x6,y6,z6);
   cSGL.TexCoordf(0,1);	 
   cSGL.Vertex3f(x4,y4,z4);
   cSGL.TexCoordf(1,0);	 
   cSGL.Vertex3f(x2,y2,z2);
  cSGL.End();


cSGL.Begin启用人脸绘制,cSGL.End结束此模式。在这些命令中放置命令以设置点的参数(法线,归一化纹理坐标,点的归一化颜色)和点渲染cSGL.Vertex3f。开始/结束内部的点数可以是任意的,并且总体上可以组成显示的凸多边形。

与OpenGL中一样,纹理化,投影和建模由命令选择的三个矩阵控制
MatrixMode(SGL_MATRIX_TEXTURE);
MatrixMode(SGL_MATRIX_PROJECTION);
MatrixMode(SGL_MATRIX_MODELVIEW);

这些矩阵的运算由命令执行
LoadIdentity();
cSGL.Rotatef(angle,0,0,1);
cSGL.Translatef(-0.5,-0.5,0);


对于绘制,库使用CGLScreenColor点类。这并不会影响性能,但可以让您轻松地在不同的显示器和体系结构之间转移库。
现在是什么FPS?对于一个没有面的给定八面体(我接受了),实际上,对绘制过程的持续时间进行测量可以得出约150-200 FPS。但是将缓冲区端口传输到显示器并同时将图片增加一倍,可以将FPS降低到大约10-15(是的,我什至没有考虑过对其进行优化)。
我引起您的注意的是,该库几乎没有在任何地方进行优化。她的任务只是制作具有现代化可能性的易于理解的3D绘图工具。我相信通过优化可以将图形输出再次加速到STM32 5-10(例如,使用FSMC,优化绘图并将数据传输到显示器)。

为什么这样的库有用?好吧,例如,以可视形式向用户显示任何指示。例如,简单3D对象的方向。

视频作品:



用于Windows的STM32 存储库的存储库。

在项目开发中祝您好运!:)

All Articles