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加载描述子

    将包含obj解析数据、mtl解析数据和图片数据的desc文件放入工程目录下,并在 gui_3d_create() 中加载。

    示例:

    void *test_3d = gui_3d_create(gui_obj_get_root(), "3d-widget", (void *)_acdesc, 0, 0, 480, 480);
    

3D控件用法

创建控件

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

全局形状变换

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

局部形状变换

使用 gui_3d_set_local_shape_transform_cb() 对3D模型进行局部变换,其中 cb 可以为物体的每个面设置不同的形状变换, face_index 为指定变换的面。该函数中的 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_obj_create_timer() 函数可以为3D对象设置动画属性,其中 callback 为动画更新的回调函数。

示例

3D蝴蝶

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

#include "guidef.h"
#include "gui_img.h"
#include "gui_obj.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.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"
#include "tp_algo.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;

bool is_moving_to_target = false;
static float target_dx = 0.0f;
static float target_dy = 0.0f;
static float source_dx = 0.0f;
static float source_dy = 0.0f;
static float move_speed = 0.02f;
static float wing_time = 0.0f;
void update_animation()
{
    touch_info_t *tp = tp_get_info();
    gui_dispdev_t *dc = gui_get_dc();

    if (tp->pressed)
    {
        target_dx = (tp->x - dc->screen_width / 2) / 2.5f;
        target_dy = (tp->y - dc->screen_height / 2) / 2.5f;
        is_moving_to_target = true;
    }

    if (is_moving_to_target)
    {
        float dx = target_dx - source_dx;
        float dy = target_dy - source_dy;

        float distance = sqrtf(dx * dx + dy * dy);

        if (distance > 10.0f)
        {
            // Acceleration and deceleration
            float speed_factor = fminf(distance / 40.0f, 1.0f);
            source_dx += dx * move_speed * speed_factor;
            source_dy += dy * move_speed * speed_factor;

            // Caculate new rotate angle
            float desired_angle = atan2f(dy, dx) * (180.0f / M_PI) + 90;
            float angle_difference = desired_angle - butterfly_rz;

            if (angle_difference > 180.0f)
            {
                angle_difference -= 360.0f;
            }
            if (angle_difference < -180.0f)
            {
                angle_difference += 360.0f;
            }
            butterfly_rz += angle_difference * 0.1f;

            // Adjust wing flapping frequency based on speed
            wing_time += 0.2f + speed_factor * 0.2f;
            wing_angle = 60.0f * sinf(wing_time);

            butterfly_x = -source_dx;
            butterfly_y = -source_dy;
        }
        else
        {
            is_moving_to_target = false;
        }
    }
    else
    {
        frame_counter++;
        wing_time += 0.1f;
        wing_angle = 50.0f * sinf(wing_time);
        butterfly_z = 5.0f * sinf(frame_counter * 0.05f);
    }

}

static void cb(void *this, size_t face_index/*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, 80), 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,
                             5);


    if (face_index == 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_index == 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_index == 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_index == 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 int app_init(void)
{
    void *test_3d = gui_3d_create(gui_obj_get_root(), "3d-widget", (void *)_acdesc, 0, 0, 480, 480);

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

    gui_obj_create_timer(&(((gui_3d_base_t *)test_3d)->base), 17, true, update_animation);
    gui_obj_start_timer(&(((gui_3d_base_t *)test_3d)->base));

    return 0;

}


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, 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 int app_init(void)
{
   void *test_3d = gui_3d_create(gui_obj_get_root(), "3d-widget", (void *)_acdesc, 0, 0, 480, 480);

   gui_3d_set_global_shape_transform_cb(test_3d, (gui_3d_shape_transform_cb)cube_cb);

   gui_obj_create_timer(&(((gui_3d_base_t *)test_3d)->base), 17, true, update_cube_animation);
   gui_obj_start_timer(&(((gui_3d_base_t *)test_3d)->base));

   return 0;
}


3D人脸

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

#include "guidef.h"
#include "gui_img.h"
#include "gui_obj.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.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);

    gui_3d_world_inititalize(world, 0, 25, 120, 0, rot_angle, 0, 5);
}



static int app_init(void)
{
    void *test_3d = gui_3d_create(gui_obj_get_root(), "3d-widget", (void *)_acdesc_1454, 0, 0, 480,
                                  480);
    gui_3d_set_global_shape_transform_cb(test_3d, (gui_3d_shape_transform_cb)face_cb);

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

    gui_obj_create_timer(&(((gui_3d_base_t *)test_3d)->base), 17, true, update_face_animation);
    gui_obj_start_timer(&(((gui_3d_base_t *)test_3d)->base));

    return 0;

}



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, void *desc_addr, int16_t x, int16_t y, int16_t w, int16_t h)

3d widget create

参数:
  • parent – parent widget

  • name – widget name

  • desc_addr – description file data

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

  • y – the Y-axis coordinate relative to 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)

set global shape transform callback

参数:
  • this – the 3d widget pointer

  • cb – Set callback functions 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)

set local shape transform callback

参数:
  • this – the 3d widget pointer

  • face – face offset

  • cb – Set callback functions for the world coordinate system, camera coordinate system, and light source for the specified face

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

Set 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