Mostrar gráficos en 3D en el STM32F407

Como saben, los STM más antiguos tienen frecuencias decentes y volúmenes de RAM. Bueno, si es así, ¿por qué no ejecutar gráficos 3D en tales controladores? ¡Sí, no hay nada más fácil!

Imagen de demostración

Para mostrar gráficos en 3D, conecté una pantalla de resolución de 320x240 a la placa de descubrimiento STM32F4 basada en el STM32F407. No, no FSMC: esta placa tiene los contactos necesarios. Sin embargo, para nuestros experimentos, los puertos normales son suficientes.
La pantalla está conectada así:
  • CS -> E12
  • RST -> E2
  • RS -> E15
  • WR -> E14
  • RD -> E13
  • D0 -> E4
  • D1 -> E5
  • D2 -> E6
  • D3 -> E7
  • D4 -> E8
  • D5 -> E9
  • D6 -> E10
  • D7 -> E11


El repositorio tiene clases para tres opciones de visualización diferentes (IL9325, SPFD5408, HX8347D).


Apariencia

Para dibujar gráficos en 3D, hace mucho tiempo realicé un fragmento de la biblioteca OpenGL de la primera versión. Este es el parecido que adjunté al STM32. Esta biblioteca requiere 6 bytes por píxel (2 por color y 4 por Z-buffer). La memoria del STM32F407 en esta versión solo es suficiente para 160x120. Bueno, entonces estiraremos la imagen dos veces verticalmente y horizontalmente.
Esta lección es capaz de:
1) Textura de textura con tamaños que son múltiplos de la potencia de dos;
2) recorte en Z;
3) Interpolación del color de los vértices dentro de la cara;
4) Cálculo de iluminación para ocho fuentes con ajuste de atenuación desde la distancia.

El procedimiento para trabajar con la biblioteca es el siguiente:
Primero debe inicializar la biblioteca (asignará memoria para la pantalla). Luego, al igual que con OpenGL, debe configurar la matriz de proyección y la ventana gráfica.
 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);


En realidad, ahora puede dibujar, casi de la misma manera que en OpenGL (para comandos similares).

Por ejemplo, puede especificar una fuente de luz:
 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);


Puede especificar el material para la superficie:
 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); 


Puede habilitar el cálculo de iluminación cSGL.Enable (CSGL :: SGL_LIGHTING); y una fuente de luz específica cSGL.Enable (CSGL :: SGL_LIGHT0);
La iluminación se considera igualmente para la parte delantera y trasera. Además, no corté los bordes posteriores (rara vez lo necesito). Pero si quieres hacerlo un par de cosas pequeñas.

No es necesario crear fuentes de luz. Es muy posible configurar el color de las caras usted mismo usando cSGL.Color3f. El color (y los parámetros de color del material también) se especifica normalizado [0..1];

La textura está conectada con el comando cSGL.BindTexture. ¡Tenga en cuenta que la biblioteca siempre usa texturas!Un conjunto de colores de textura se define como una secuencia de cuatro bytes (r, g, b, alfa) y aquí r, g, b, alfa son números del 0 al 255. Estrictamente hablando, son precisamente estos números los que multiplican la intensidad de los canales R, G, B especificado por glColor3f (o calculado a partir de fuentes de luz) al renderizar. Se debe mantener una matriz de datos de textura durante todo el tiempo que se muestra la cara.

La conclusión de la cara es la siguiente:
  
  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 habilita el dibujo de caras, cSGL.End finaliza este modo. Dentro de estos comandos se coloca el comando para establecer los parámetros del punto (normal, coordenada de textura normalizada, color normalizado del punto) y renderizado de punto cSGL.Vertex3f. El número de puntos dentro del inicio / final puede ser arbitrario, y en su conjunto constituye el polígono convexo que se muestra.

La textura, la proyección y el modelado están controlados, como en OpenGL, por tres matrices seleccionadas por comandos
MatrixMode(SGL_MATRIX_TEXTURE);
MatrixMode(SGL_MATRIX_PROJECTION);
MatrixMode(SGL_MATRIX_MODELVIEW);

Las operaciones con estas matrices se realizan mediante comandos.
LoadIdentity();
cSGL.Rotatef(angle,0,0,1);
cSGL.Translatef(-0.5,-0.5,0);


Para dibujar, la biblioteca usa la clase de punto CGLScreenColor. Esto afecta el rendimiento no para mejor, pero le permite transferir fácilmente la biblioteca entre diferentes pantallas y arquitecturas.
¿Qué es FPS ahora? Para un octaedro dado sin una cara (lo tomé), las mediciones de la duración, de hecho, de los procedimientos de renderización dan alrededor de 150-200 FPS. Pero la transferencia a través de los puertos del búfer a la pantalla al duplicar la imagen reduce significativamente el FPS, a aproximadamente 10-15 (sí, ni siquiera pensé en optimizarlo por ahora).
Le llamo la atención sobre el hecho de que la biblioteca no estaba optimizada en casi ningún lugar.Su tarea era simplemente hacer una herramienta de dibujo 3D comprensible con la posibilidad de modernización. Creo que al optimizar es posible acelerar la salida de gráficos a STM32 una vez más por 5-10 (por ejemplo, usando FSMC, optimizando el dibujo y la transferencia de datos a la pantalla).

¿Por qué puede ser útil esta biblioteca? Bueno, por ejemplo, muestre cualquier indicación al usuario en forma visual. Por ejemplo, la orientación de un simple objeto 3D.

Video de trabajo:


Repositorio para STM32
Repositorio para Windows.

¡Buena suerte en el desarrollo del proyecto! :)

All Articles