feat(gltf): gltf view raycasting and 3d point to screen point conversion (#9143)
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Install LVGL using CMake / build-examples (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
Matt
2025-10-30 17:34:04 -04:00
committed by GitHub
parent e6bd7fcd9b
commit 30dbe045bf
4 changed files with 196 additions and 3 deletions
+71 -2
View File
@@ -15,6 +15,7 @@
#if LV_USE_GLTF
#include "../../../misc/lv_types.h"
#include "../../../misc/lv_area.h"
#include "../../../misc/lv_color.h"
#include "../gltf_data/lv_gltf_model.h"
@@ -43,6 +44,19 @@ typedef enum {
LV_GLTF_BG_MODE_ENVIRONMENT = 1, /** Environnement background*/
} lv_gltf_bg_mode_t;
typedef struct {
float x;
float y;
float z;
} lv_3dpoint_t;
typedef struct {
lv_3dpoint_t origin;
lv_3dpoint_t direction;
} lv_3dplane_t;
typedef lv_3dplane_t lv_3dray_t;
#define LV_GLTF_ANIM_SPEED_TENTH 100
#define LV_GLTF_ANIM_SPEED_QUARTER 250
#define LV_GLTF_ANIM_SPEED_HALF 500
@@ -130,12 +144,19 @@ float lv_gltf_get_pitch(const lv_obj_t * obj);
void lv_gltf_set_distance(lv_obj_t * obj, float value);
/**
* Get the camera distance from the focal point
* Get the camera distance scale factor from the focal point
* @param obj pointer to a GLTF viewer object
* @return distance value
* @return distance scaling factor value
*/
float lv_gltf_get_distance(const lv_obj_t * obj);
/**
* Get the camera distance from the focal point in world units
* @param obj pointer to a GLTF viewer object
* @return world unit distance value
*/
float lv_gltf_get_world_distance(const lv_obj_t * obj);
/**********************
* Viewport Functions
**********************/
@@ -340,6 +361,54 @@ void lv_gltf_set_antialiasing_mode(lv_obj_t * obj, lv_gltf_aa_mode_t value);
*/
lv_gltf_aa_mode_t lv_gltf_get_antialiasing_mode(const lv_obj_t * obj);
/***********************
* Raycasting Functions
***********************/
/**
* Get a plane that faces the current view camera, centered some units in front of it
* @param obj pointer to a GLTF viewer object
* @param distance distance in front of the camera to set the plane, in world units. see lv_gltf_get_world_distance to get the auto-distance
* @return camera facing plane
*/
lv_3dplane_t lv_gltf_get_current_view_plane(lv_obj_t * obj, float distance);
/**
* Get a plane that faces upward, centered at a given height
* @param obj pointer to a GLTF viewer object
* @param elevation elevation of the ground plane, in world units. this is usually zero
* @return ground plane
*/
lv_3dplane_t lv_gltf_get_ground_plane(float elevation);
/**
* Calculates a ray originating from the camera and passing through the specified mouse position on the screen.
* @param obj pointer to a GLTF viewer object
* @param screen_pos screen co-ordinate, in pixels
* @return mouse point ray
*/
lv_3dray_t lv_gltf_get_ray_from_2d_coordinate(lv_obj_t * obj, const lv_point_t * screen_pos);
/**
* Get the point that a given ray intersects with a specified plane at, if any
* @param ray the intersection test ray
* @param screen_y the plane to test ray intersection with
* @param collision_point output lv_3dpoint_t holder, values are only valid if true is the return value
* @return LV_RESULT_OK if intersection, LV_RESULT_INVALID if no intersection
*/
lv_result_t lv_gltf_intersect_ray_with_plane(const lv_3dray_t * ray, const lv_3dplane_t * plane,
lv_3dpoint_t * collision_point);
/**
* Get the screen position of a 3d point
* @param obj pointer to a GLTF viewer object
* @param world_pos world position to convert
* @param lv_point_t the resulting point, in pixels. only valid if return value is true
* @return LV_RESULT_OK if conversion valid, LV_RESULT_INVALID if no valid conversion
*/
lv_result_t lv_gltf_world_to_screen(lv_obj_t * obj, const lv_3dpoint_t world_pos, lv_point_t * screen_pos);
/**********************
* MACROS
**********************/
+123
View File
@@ -209,6 +209,19 @@ float lv_gltf_get_distance(const lv_obj_t * obj)
return viewer->desc.distance;
}
float lv_gltf_get_world_distance(const lv_obj_t * obj)
{
LV_ASSERT_NULL(obj);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * viewer = (lv_gltf_t *)obj;
lv_gltf_view_desc_t * view_desc = &viewer->desc;
if(viewer->models.size == 0) {
return 0.0f;
}
lv_gltf_model_t * model = *(lv_gltf_model_t **)lv_array_at(&viewer->models, 0);
return (lv_gltf_data_get_radius(model) * LV_GLTF_DISTANCE_SCALE_FACTOR) * view_desc->distance;
}
void lv_gltf_set_animation_speed(lv_obj_t * obj, uint32_t value)
{
LV_ASSERT_NULL(obj);
@@ -427,6 +440,116 @@ void lv_gltf_recenter(lv_obj_t * obj, lv_gltf_model_t * model)
viewer->desc.focal_z = center_position[2];
}
lv_3dray_t lv_gltf_get_ray_from_2d_coordinate(lv_obj_t * obj, const lv_point_t * screen_pos)
{
LV_ASSERT_NULL(obj);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * viewer = (lv_gltf_t *)obj;
float norm_mouse_x = (float)screen_pos->x / (float)(lv_obj_get_width(obj));
float norm_mouse_y = (float)screen_pos->y / (float)(lv_obj_get_height(obj));
lv_3dray_t outray = {0};
fastgltf::math::fmat4x4 proj_mat = fastgltf::math::invert(fastgltf::math::fmat4x4(viewer->projection_matrix));
/* Convert mouse coordinates to NDC */
float x = norm_mouse_x * 2.0f - 1.0f;
float y = 1.0f - (norm_mouse_y * 2.0f);
float z = -1.0f; /* Clip space z */
fastgltf::math::fvec4 clip_space_pos = fastgltf::math::fvec4(x, y, z, 1.f);
auto ray_eye = (proj_mat) * clip_space_pos;
ray_eye[2] = -1.0f;
ray_eye[3] = 0.0f;
/* Calculate ray world direction */
fastgltf::math::fvec4 ray_world = fastgltf::math::invert(viewer->view_matrix) * ray_eye;
auto ray_direction = fastgltf::math::normalize(fastgltf::math::fvec3(ray_world[0], ray_world[1], ray_world[2]));
outray.direction = {ray_direction[0], ray_direction[1], ray_direction[2]};
outray.origin = {viewer->camera_pos[0], viewer->camera_pos[1], viewer->camera_pos[2]};
return outray;
}
lv_result_t lv_gltf_intersect_ray_with_plane(const lv_3dray_t * ray, const lv_3dplane_t * plane,
lv_3dpoint_t * collision_point)
{
fastgltf::math::fvec3 plane_center = fastgltf::math::fvec3(plane->origin.x, plane->origin.y, plane->origin.z);
fastgltf::math::fvec3 plane_normal = fastgltf::math::fvec3(plane->direction.x, plane->direction.y, plane->direction.z);
fastgltf::math::fvec3 ray_start = fastgltf::math::fvec3(ray->origin.x, ray->origin.y, ray->origin.z);
fastgltf::math::fvec3 ray_direction = fastgltf::math::fvec3(ray->direction.x, ray->direction.y, ray->direction.z);
float denom = fastgltf::math::dot(plane_normal, ray_direction);
if(fabs(denom) > 1e-6) { /* Check if the ray is not parallel to the plane */
fastgltf::math::fvec3 diff = plane_center - ray_start;
float t = fastgltf::math::dot(diff, plane_normal) / denom;
if(t >= 0) { /* Intersection occurs ahead of the ray origin */
/* Calculate the collision point */
(*collision_point).x = ray_start[0] + t * ray_direction[0];
(*collision_point).y = ray_start[1] + t * ray_direction[1];
(*collision_point).z = ray_start[2] + t * ray_direction[2];
return LV_RESULT_OK; /* Collision point found */
}
}
return LV_RESULT_INVALID; /* No intersection */
}
lv_3dplane_t lv_gltf_get_ground_plane(float elevation)
{
lv_3dplane_t outplane = {0};
outplane.origin = {0.0f, elevation, 0.0f};
outplane.direction = {0.0f, 1.0f, 0.0f};
return outplane;
}
lv_3dplane_t lv_gltf_get_current_view_plane(lv_obj_t * obj, float distance)
{
LV_ASSERT_NULL(obj);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * viewer = (lv_gltf_t *)obj;
lv_3dplane_t outplane = {0};
/* Forward vector is the third column of the matrix */
auto forward = fastgltf::math::fvec3(viewer->view_matrix[0][2], viewer->view_matrix[1][2], viewer->view_matrix[2][2]);
forward = fastgltf::math::normalize(forward);
/* Calculate the plane center */
const auto & camera_pos = viewer->camera_pos;
auto plane_pos = fastgltf::math::fvec3(camera_pos[0], camera_pos[1], camera_pos[2]) - forward * distance;
outplane.origin = {plane_pos[0], plane_pos[1], plane_pos[2]};
outplane.direction = {-forward[0], -forward[1], -forward[2]};
return outplane;
}
lv_result_t lv_gltf_world_to_screen(lv_obj_t * obj, const lv_3dpoint_t world_pos, lv_point_t * screen_pos)
{
LV_ASSERT_NULL(obj);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * viewer = (lv_gltf_t *)obj;
fastgltf::math::fvec4 world_position_h = fastgltf::math::fvec4(world_pos.x, world_pos.y, world_pos.z, 1.0f);
fastgltf::math::fvec4 clip_space_pos = viewer->projection_matrix * viewer->view_matrix * world_position_h;
/* Check for perspective division (w must not be zero) */
if(clip_space_pos[3] == 0.0f) {
screen_pos->x = -1;
screen_pos->y = -1;
return LV_RESULT_INVALID; /* Position is not valid for screen mapping */
}
clip_space_pos /= clip_space_pos[3];
float norm_screen_x = clip_space_pos[0] * 0.5f + 0.5f;
float norm_screen_y = 0.5f - (clip_space_pos[1] * 0.5f);
int32_t win_width = lv_obj_get_width(obj);
int32_t win_height = lv_obj_get_height(obj);
screen_pos->x = norm_screen_x * win_width;
screen_pos->y = norm_screen_y * win_height;
return LV_RESULT_OK;
}
/**********************
* STATIC FUNCTIONS
**********************/
@@ -25,6 +25,7 @@
* DEFINES
*********************/
#define LV_GLTF_DISTANCE_SCALE_FACTOR 2.5f
/**********************
* TYPEDEFS
@@ -1035,7 +1035,7 @@ static void setup_view_proj_matrix(lv_gltf_t * viewer, lv_gltf_view_desc_t * vie
bool transmission_pass)
{
auto b_radius = lv_gltf_data_get_radius(gltf_data);
float radius = b_radius * 2.5;
float radius = b_radius * LV_GLTF_DISTANCE_SCALE_FACTOR;
radius *= view_desc->distance;
fastgltf::math::fvec3 rcam_dir = fastgltf::math::fvec3(0.0f, 0.0f, 1.0f);