3D模型 (3D Model)

该控件支持加载由 .obj.mtl 文件组成的3D模型,并支持添加动画特效。

GUI加载3D模型

  1. 3D模型组成部分

    • .obj 文件:存储3D模型的几何数据,包括顶点、法线、纹理坐标、面等。

    • .mtl 文件:描述3D模型材质的属性,包括颜色、光泽度、透明度和纹理映射等。

    • 图片文件:模型中使用到的贴图。

    https://foruda.gitee.com/images/1735113754178839767/916a3f95_13408154.png

    3D模型组成示例

  2. 3D模型解析并生成3D信息描述子

    • 调用脚本处理 .obj 文件。

    https://foruda.gitee.com/images/1735540370568112173/cf1c0126_13408154.png

    脚本处理

    • 生成3D信息描述子,该文件包含obj解析数据、mtl解析数据以及纹理贴图。

    https://foruda.gitee.com/images/1735114445910760790/2a41eeab_13408154.png

    生成二进制数组

  3. GUI加载描述子

    将该desc文件放入工程目录下,并调用 gui_get_3d_desc() 函数加载到 gui_3d_description_t 结构体中。

    示例:

    gui_3d_description_t *desc = gui_get_3d_desc((void *)_acdesc);
    

    gui_3d_description_t 结构体定义如下:

    typedef struct
    {
        GUI_3D_FACE_TYPE face_type;
        gui_obj_attrib_t attrib;
    
        unsigned int num_shapes;
        gui_obj_shape_t *shapes;
    
        unsigned int num_materials;
        gui_obj_material_t *materials;
    
        unsigned int *texture_sizes;
        unsigned char **textures;
    
    } gui_3d_description_t;
    

    其中 GUI_3D_FACE_TYPE 表示3D对象的面类型,现支持 GUI_3D_FACE_RECTANGLE (矩形)或 GUI_3D_FACE_TRIANGLE (三角形)组成的3D模型。

3D控件用法

创建控件

使用 gui_3d_create() 创建3D模型,传入的 desc 即为脚本中提取的解析数据。

全局形状变换

使用 gui_3d_set_global_shape_transform_cb() 对3D模型进行整体变换,其中 cb 为物体的所有面设置相同的形状变换。该函数中的 worldcamera 代表了3D对象的世界坐标变换和相机视角投影,矩形面还支持设置 light 光照信息。

局部形状变换

使用 gui_3d_set_local_shape_transform_cb() 对3D模型进行局部变换,其中 cb 可以为物体的每个面设置不同的形状变换, face 为指定变换的面。该函数中的 worldcamera 代表了3D对象的世界坐标变换和相机视角投影,矩形面还支持设置 light 光照信息。

世界变换

初始化函数为 gui_3d_world_inititalize(gui_3d_matrix_t *world, float x, float y, float z, float rotX, float rotY, float rotZ, float scale)

  • world:指向世界变换矩阵的指针,将3D对象从模型坐标系转换到世界坐标系。

  • x:沿X轴进行平移的距离,用以确定对象在世界坐标系中X方向上的位置。

  • y:沿Y轴进行平移的距离,用以确定对象在世界坐标系中Y方向上的位置。

  • z:沿Z轴进行平移的距离,用以确定对象在世界坐标系中Z方向上的位置。

  • rotX:绕X轴旋转的角度(单位:度)。

  • rotY:绕Y轴旋转的角度(单位:度)。

  • rotZ:绕Z轴旋转的角度(单位:度)。

  • scale:统一缩放系数,用于在各个方向上等比例地缩放对象。

作用:

  1. 世界变换矩阵通常负责将模型坐标系转换到世界坐标系。例如,如果有一个物体位于模型坐标系的原点,通过世界变换,它可以被放置到场景中的任意位置并进行旋转缩放。

  2. 对每个面进行独立的世界变换可以实现局部动画或静态展示。

  3. 不同的面可以共享同一个世界矩阵,也可以使用 gui_3d_calculator_matrix(gui_3d_matrix_t *matrix, float x, float y, float z, gui_point_4d_t point, gui_vector_4d_t vector, float degrees, float scale) 为每个面生成不同的矩阵以实现个性化的局部变换。

相机变换

初始化函数为 gui_3d_camera_UVN_initialize(gui_3d_camera_t *camera, gui_point_4d_t cameraPosition, gui_point_4d_t cameraTarget, float near, float far, float fov, float viewPortWidth, float viewPortHeight)

  • camera:指向相机结构体的指针,用于初始化相机的属性。

  • cameraPosition:相机在世界坐标系中的位置。

  • cameraTarget:相机所指向的目标点,即相机视线的焦点。

  • near:近裁剪平面距离,定义了相机截取视锥体的近端平面到相机的距离,所有靠近相机而小于这个距离的物体将被裁剪掉。

  • far:远裁剪平面距离,定义了视锥体远端平面到相机的距离,所有远离相机而大于这个距离的物体将被裁剪掉。

  • fov:视野范围,通常以垂直角度(单位:度)表示,定义了相机的开阔程度,即相机视锥体的张开角度。

  • viewPortWidth:视口的宽度,定义渲染目标或窗口的横向尺寸。

  • viewPortHeight:视口的高度,定义渲染目标或窗口的纵向尺寸。

作用:

  1. 相机变换定义了观察者在场景中的位置和方向,它将世界坐标系转换到摄像机坐标系。

  2. 通过操作相机,可以实现不同的视角,例如平移摄像机位置和改变观察方向。

光照信息

初始化函数为 gui_3d_light_inititalize(gui_3d_light_t *light, gui_point_4d_t lightPosition, gui_point_4d_t lightTarget, float included_angle, float blend_ratio, gui_3d_RGBAcolor_t color)

  • light:指向光源结构体的指针,用于初始化光源的属性。

  • lightPosition:光源在世界坐标系中的位置。

  • lightTarget:光源的目标位置,定义光源照射的方向。

  • included_angle:光的锥形角度(单位:度),即图中的 \(\alpha\) 角,它决定聚光灯的光照范围,即图中聚光灯的外圈范围。

  • blend_ratio:光照融合区比例,定义聚光边缘的柔和度,范围为0~1,决定图中的 \(\beta\) 角,其值通过以下公式计算得出:

    \[β = α (1 - ratio)\]

    融合区域即为下图中的聚光灯内圈到外圈的范围,在内圈内光照强度一致,内圈到外圈光照强度逐渐衰减。

  • color:光源的颜色,格式为RGBA8888。

https://foruda.gitee.com/images/1735889400996762341/a4f7e0c8_13408154.png

聚光灯效果示例

作用:

  1. 光源类型为聚光灯,其属性包含初始位置、光源朝向、锥形角度、融合区比例和光源颜色。

  2. 对每个面或对象局部调整光照可以营造不同的视觉风格。

设置动画

gui_3d_set_animate() 函数用于为3D对象设置动画属性,其中 callback 为动画更新的回调函数,当动画每一帧更新时将调用这个函数。

示例

3D蝴蝶

该模型全部由矩形面组成,调用 gui_3d_set_local_shape_transform_cb() 为不同面设置局部变换可以制作动画效果。

#include "guidef.h"
#include "gui_img.h"
#include "gui_tabview.h"
#include "gui_tab.h"
#include "gui_img.h"
#include "gui_obj.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include <gui_app.h>
#include "gui_server.h"
#include "gui_components_init.h"
#include "gui_canvas.h"
#include "gui_3d.h"

#include "butterfly/desc.txt"
#include "math.h"

static int frame_counter = 0;
static float wing_angle = 0.0f;
static float butterfly_x = 0.0f;
static float butterfly_y = 0.0f;
static float butterfly_z = 0.0f;
static float butterfly_rz = 0.0f;

void update_animation()
{
    frame_counter++;
    wing_angle = 50.0f * sinf(frame_counter * 0.1f);

    float radius = 20.0f;
    float theta = frame_counter * 0.01f;

    butterfly_x = radius * cosf(theta);
    butterfly_y = radius * sinf(theta);

    butterfly_z = 10.0f * sinf(frame_counter * 0.05f);

    butterfly_rz = theta * (180.0f / M_PI);
}

static void cb(void *this, size_t face/*face offset*/, gui_3d_world_t *world,
               gui_3d_camera_t *camera, gui_3d_light_t *light)
{
    gui_dispdev_t *dc = gui_get_dc();
    gui_3d_matrix_t face_matrix;
    gui_3d_matrix_t object_matrix;

    gui_3d_camera_UVN_initialize(camera, gui_point_4d(0, 0, 50), gui_point_4d(0, 0, 0), 1, 32767, 90,
                                 dc->screen_width, dc->screen_height);

    gui_3d_world_inititalize(&object_matrix, butterfly_x, butterfly_y, butterfly_z, 0, 0,
                             butterfly_rz + 90,
                             5);


    if (face == 0)
    {
        gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 1, 0),
                                 wing_angle, 1);
    }
    else if (face == 1)
    {
        gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 1, 0),
                                 -wing_angle, 1);
    }
    else if (face == 2)
    {
        gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 1, 0),
                                 wing_angle, 1);
    }
    else if (face == 3)
    {
        gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 1, 0),
                                 -wing_angle, 1);
    }
    else
    {
        gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 1, 0), 0,
                                 1);
    }

    *world = gui_3d_matrix_multiply(face_matrix, object_matrix);

}



static void app_ui_design(gui_app_t *app)
{
    gui_3d_description_t *desc = gui_get_3d_desc((void *)_acdesc);

    void *test_3d = gui_3d_create(&(app->screen), "3d-widget", desc, 0, 0, 480, 480);

    gui_3d_set_local_shape_transform_cb(test_3d, 0, (gui_3d_shape_transform_cb)cb);

    gui_3d_set_animate(test_3d, 10000, -1, update_animation, NULL);


    return;

}


3D棱镜

该模型全部由矩形面组成,调用 gui_3d_light_inititalize() 可以添加光照效果。

#include "math.h"
#include "cube3D/desc.txt"

static float rot_angle = 0.0f;
void update_cube_animation()
{
   rot_angle++;
}

static void cube_cb(gui_3d_t *this, size_t face/*face offset*/, gui_3d_world_t *world,
               gui_3d_camera_t *camera, gui_3d_light_t *light)
{
   gui_dispdev_t *dc = gui_get_dc();
   gui_3d_matrix_t face_matrix;
   gui_3d_matrix_t object_matrix;

   gui_3d_camera_UVN_initialize(camera, gui_point_4d(0, 6, 15), gui_point_4d(0, 0, 0), 1, 32767, 90,
                                 dc->screen_width, dc->screen_height);

   gui_3d_world_inititalize(&object_matrix, 0, 22, 40, 90, 0, 0,
                           10);

   gui_3d_light_inititalize(light, gui_point_4d(0, 22, 45), gui_point_4d(0, 22, 40), 60, 0.6, (gui_3d_RGBAcolor_t){255, 215, 0, 255});

   gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 0, 1), rot_angle,
                                 1);

   *world = gui_3d_matrix_multiply(face_matrix, object_matrix);

}
static void app_ui_design(gui_app_t *app)
{

   gui_3d_t *test_3d = gui_3d_create(&(app->screen), "3d-widget", (void *)_acdesc, 0, 0, 480, 480);

   gui_3d_set_shape_transform_cb(test_3d, 0, cube_cb);

   gui_3d_set_animate(test_3d, 10000, -1, update_cube_animation, NULL);

   return;

}


3D人脸

该模型由1454个三角形面组成。

#include "guidef.h"
#include "gui_img.h"
#include "gui_tabview.h"
#include "gui_tab.h"
#include "gui_img.h"
#include "gui_obj.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include <gui_app.h>
#include "gui_server.h"
#include "gui_components_init.h"

#include "gui_3d.h"
#include "tp_algo.h"
#include "face3d/desc_1454.txt"
#include "face3d/desc_5822.txt"

static float rot_angle = 0.0f;

void update_face_animation()
{
    touch_info_t *tp = tp_get_info();

    if (tp->pressed || tp->pressing)
    {
        rot_angle += tp->deltaX / 5.0f;
    }
}


static void face_cb(void *this, gui_3d_world_t *world,
                    gui_3d_camera_t *camera)
{
    gui_dispdev_t *dc = gui_get_dc();
    gui_3d_matrix_t face_matrix;
    gui_3d_matrix_t object_matrix;

    gui_3d_camera_UVN_initialize(camera, gui_point_4d(0, 3, 60), gui_point_4d(0, 0, 0), 1, 32767, 90,
                                 dc->screen_width, dc->screen_height);

    gui_3d_world_inititalize(&object_matrix, 0, 25, 120, 0, 0, 0,
                             5);

    gui_3d_calculator_matrix(&face_matrix, 0, 0, 0, gui_3d_point(0, 0, 0), gui_3d_vector(0, 1, 0),
                             rot_angle,
                             1);

    *world = gui_3d_matrix_multiply(face_matrix, object_matrix);
}



static void app_ui_design(gui_app_t *app)
{
    gui_3d_description_t *desc = gui_get_3d_desc((void *)_acdesc_1454);

    void *test_3d = gui_3d_create(&(app->screen), "3d-widget", desc, 0, 0, 480, 480);
    gui_3d_set_global_shape_transform_cb(test_3d, (gui_3d_shape_transform_cb)face_cb);
    gui_3d_set_animate(test_3d, 10000, -1, update_face_animation, NULL);

//    extern void gui_fps_create(void *parent);
//    gui_fps_create(&(app->screen));

    return;

}



API

Typedefs

typedef void (*gui_3d_shape_transform_cb)(void *this, gui_3d_world_t *world, gui_3d_camera_t *camera, void *extra)

Functions

void *gui_3d_create(void *parent, const char *name, gui_3d_description_t *desc, int16_t x, int16_t y, int16_t w, int16_t h)

Creates a 3D widget.

参数:
  • parent – Parent widget.

  • name – Widget name.

  • desc – Description file data.

  • x – The X-axis coordinate relative to the parent widget.

  • y – The Y-axis coordinate relative to the parent widget.

  • w – Width.

  • h – Height.

返回:

The widget object pointer.

void gui_3d_set_global_shape_transform_cb(void *this, gui_3d_shape_transform_cb cb)

Sets the global shape transform callback for the 3D widget.

参数:
  • this – The 3D widget pointer.

  • cb – Callback function for the world coordinate system, camera coordinate system, and light source for all faces.

void gui_3d_set_local_shape_transform_cb(void *this, size_t face, gui_3d_shape_transform_cb cb)

Sets the local shape transform callback for the 3D widget.

参数:
  • this – The 3D widget pointer.

  • face – Face offset.

  • cb – Callback function for the world coordinate system, camera coordinate system, and light source for the specified face.

void gui_3d_set_animate(void *this, uint32_t dur, int repeat_count, void *callback, void *p)

Sets 3D animation effects for the widget.

参数:
  • this – The 3D widget pointer.

  • dur – Animation time cost in milliseconds.

  • repeat_count – Number of rounds to repeat.

  • callback – Callback function for every frame.

  • p – Parameter for the callback function.

void gui_3d_on_click(void *this, void *callback, void *parameter)

Sets a callback function for when the 3D widget is clicked.

参数:
  • this – Pointer to the 3D widget.

  • callback – Callback function to execute on click.

  • parameter – Additional parameter for the callback.

struct gui_3d_base_t

Public Members

gui_obj_t base
gui_3d_description_t *desc