3D Model

The widget supports loading 3D models composed of .obj and .mtl files, and supports adding animation effects.

GUI Load 3D Model

  1. Components of a 3D model

    • .obj file: Stores the geometric data of the 3D model, including vertices, normals, texture coordinates, faces, etc.

    • .mtl file: Describes the material properties of the 3D model, including color, glossiness, transparency, and texture mapping.

    • Image files: Textures used in the model.

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

    Example of 3D Model Components

  2. Parsing the 3D model and generating a 3D information descriptor

    • Invoke a script to process the .obj file.

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

    Script Processing

    • Generate a 3D information descriptor, which includes parsed OBJ data, parsed MTL data, and texture maps.

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

    Generating Binary Arrays

  3. GUI load descriptor

    Place the desc file containing parsed obj data, mtl data, and image data into the project directory, and load it using gui_3d_create().

    Example:

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

3D Widget Usage

Create Widget

Use gui_3d_create() to create the 3D model. The imported desc_addr file is the parsed data extracted by the script.

Global Shape Transformation

Use gui_3d_set_global_shape_transform_cb() to apply a global transformation to the 3D model, where cb sets the same shape transformation for all faces of the object. In this function, world and camera represent the world coordinate transformation of the 3D object and the camera view projection, respectively. Additionally, rectangular faces support the setting of light information.

Local Shape Transformation

Use gui_3d_set_local_shape_transform_cb() to apply a local transformation to the 3D model, where cb allows setting different shape transformations for each face of the object, and face_index specifies the face to be transformed. In this function, world and camera represent the world coordinate transformation of the 3D object and the camera view projection, respectively. Additionally, rectangular faces support the setting of light information.

World Transformation

The initialization function is gui_3d_world_inititalize(gui_3d_matrix_t *world, float x, float y, float z, float rotX, float rotY, float rotZ, float scale).

  • world: A pointer to the world transformation matrix, it transforms the 3D object from model coordinates to world coordinates.

  • x: The distance of translation along the X-axis, used to determine the object’s position in the X direction within the world coordinate system.

  • y: The distance of translation along the Y-axis, used to determine the object’s position in the Y direction within the world coordinate system.

  • z: The distance of translation along the Z-axis, used to determine the object’s position in the Z direction within the world coordinate system.

  • rotX: The angle of rotation around the X-axis (in degrees).

  • rotY: The angle of rotation around the Y-axis (in degrees).

  • rotZ: The angle of rotation around the Z-axis (in degrees).

  • scale: A uniform scaling factor used to proportionally scale the object in all directions.

Purpose:

  1. The world transformation matrix typically handles transforming the model coordinate system to the world coordinate system. For example, if an object is located at the origin of the model coordinate system, it can be moved to any position in the scene and scaled/rotated through world transformation.

  2. Performing independent world transformations for each face can achieve localized animations or static displays.

  3. Different faces can share the same world matrix, or you can use 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) to generate different matrices for each face to achieve personalized local transformations.

Camera Transformation

The initialization function is 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: A pointer to the camera structure, used to initialize camera properties.

  • cameraPosition: The position of the camera in world coordinates.

  • cameraTarget: The target point the camera is directed at, i.e., the focal point of the camera’s line of sight.

  • near: The near clipping plane distance, defining the distance from the camera to the near plane of the camera’s view frustum. Objects closer than this distance will be clipped.

  • far: The far clipping plane distance, defining the distance from the camera to the far plane of the view frustum. Objects farther than this distance will be clipped.

  • fov: The field of view, usually expressed as a vertical angle (in degrees), defining the openness of the camera, i.e., the opening angle of the camera’s view frustum.

  • viewPortWidth: The width of the viewport, defining the horizontal size of the rendering target or window.

  • viewPortHeight: The height of the viewport, defining the vertical size of the rendering target or window.

Purpose:

  1. Camera transformation defines the observer’s position and direction in the scene, transforming the world coordinate system to the camera coordinate system.

  2. By manipulating the camera, different perspectives can be achieved, such as translating the camera position or changing the viewing direction.

Lighting Information

The initialization function is 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: A pointer to the light source structure, used to initialize the properties of the light source.

  • lightPosition: The position of the light source in world coordinates.

  • lightTarget: The target position of the light source, defining the direction of illumination.

  • included_angle: The cone angle of the light (in degrees), represented as angle \(\alpha\) in the diagram. It determines the illumination range of the spotlight, which corresponds to the outer circle of the spotlight in the diagram.

  • blend_ratio: The ratio of the light blending region, defining the softness of the spotlight’s edge. It ranges from 0 to 1 and determines angle \(\beta\) in the diagram. The value is calculated using the following formula:

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

    The blending region extends from the inner circle to the outer circle of the spotlight. Within the inner circle, the light intensity is constant, while it gradually diminishes from the inner to the outer circle.

  • color: The color of the light source and its transparency.

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

Example of Spotlight Effect

Purpose:

  1. The light source type is a spotlight, and its properties include initial position, light direction, cone angle, blend ratio, and light color.

  2. Adjusting lighting locally for each face or object can create different visual styles.

Set Animation

The gui_obj_create_timer() function can be used to set animation properties for a 3D object. The callback parameter is a callback function for animation updates.

Example

3D Butterfly

The model is composed entirely of rectangular faces. By calling gui_3d_set_local_shape_transform_cb(), you can set local transformations for different faces to create animation effects.

#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 Prism

The model is composed entirely of rectangular faces. By calling gui_3d_light_inititalize(), you can add lighting effects.

#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 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 Face

The model is composed of 1,454 triangular faces.

#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

Parameters:
  • 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

Returns:

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

Parameters:
  • 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

Parameters:
  • 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.

Parameters:
  • 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