3D模型 (3D Model)
该控件支持加载由 .obj
和 .mtl
文件组成的3D模型,并支持添加动画特效。
GUI加载3D模型
3D模型组成部分
.obj
文件:存储3D模型的几何数据,包括顶点、法线、纹理坐标、面等。.mtl
文件:描述3D模型材质的属性,包括颜色、光泽度、透明度和纹理映射等。图片文件:模型中使用到的贴图。
3D模型组成示例
3D模型解析并生成3D信息描述子
调用脚本处理
.obj
文件。
脚本处理
生成3D信息描述子,该文件包含obj解析数据、mtl解析数据以及纹理贴图。
生成二进制数组
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
为物体的所有面设置相同的形状变换。该函数中的 world
和 camera
代表了3D对象的世界坐标变换和相机视角投影,矩形面还支持设置 light
光照信息。
局部形状变换
使用 gui_3d_set_local_shape_transform_cb()
对3D模型进行局部变换,其中 cb
可以为物体的每个面设置不同的形状变换, face_index
为指定变换的面。该函数中的 world
和 camera
代表了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
:统一缩放系数,用于在各个方向上等比例地缩放对象。
作用:
世界变换矩阵通常负责将模型坐标系转换到世界坐标系。例如,如果有一个物体位于模型坐标系的原点,通过世界变换,它可以被放置到场景中的任意位置并进行旋转缩放。
对每个面进行独立的世界变换可以实现局部动画或静态展示。
不同的面可以共享同一个世界矩阵,也可以使用
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
:视口的高度,定义渲染目标或窗口的纵向尺寸。
作用:
相机变换定义了观察者在场景中的位置和方向,它将世界坐标系转换到摄像机坐标系。
通过操作相机,可以实现不同的视角,例如平移摄像机位置和改变观察方向。
光照信息
初始化函数为 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。

聚光灯效果示例
作用:
光源类型为聚光灯,其属性包含初始位置、光源朝向、锥形角度、融合区比例和光源颜色。
对每个面或对象局部调整光照可以营造不同的视觉风格。
设置动画
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