feat(gltf): support sharing the background environment across multiple objects (#9009)

This commit is contained in:
André Costa
2025-11-17 14:36:57 +01:00
committed by GitHub
parent 8ed4b5f3f3
commit dd827489d6
11 changed files with 518 additions and 235 deletions
@@ -73,8 +73,8 @@ For complete implementation details, see :ref:`OpenGL driver <opengl_driver>`.
3D/glTF Support
===============
The glTF extension provides support for loading and rendering 3D models using the glTF 2.0 specification within LVGL applications.
This extension requires OpenGL ES 3.0 and provides comprehensive 3D rendering capabilities including PBR materials,
The glTF module provides support for loading and rendering 3D models using the glTF 2.0 specification within LVGL applications.
This support requires OpenGL ES 2.0 with some extra extensions and provides comprehensive 3D rendering capabilities including PBR materials,
animations, and interactive camera controls for embedded 3D visualization.
For complete implementation details, see :ref:`glTF <gltf>`.
+155 -76
View File
@@ -10,64 +10,7 @@ The glTF extension in LVGL provides 3D model loading, rendering, and animation c
For a detailed introduction to glTF, see: https://www.khronos.org/gltf/
Features
********
LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
**File Format Support:**
* Loading glTF (.gltf) and binary GLB (.glb) files from local filesystem
* Support for hex-encoded bytes in source include files when filesystem is not available
* JPG, PNG, and WebP compressed texture support
* External texture files or textures embedded within the glTF source
**Rendering & Lighting:**
* Image-Based Lighting (IBL) for realistic environmental lighting
* Punctual lighting support with animated light sources
* Physically Based Rendering (PBR) materials with full texture support:
* Diffuse/albedo textures
* Roughness and metallic workflow textures
* Normal maps for surface detail
* Ambient occlusion textures
**Advanced Materials:**
* Emissive materials for glowing effects and self-illuminated surfaces
* Refractive materials with realistic distortion effects revealing geometry behind surfaces
* Clearcoat material support for multi-layer surface effects (like automotive paint finishes)
* Full transparency support with alpha blending
**Animation System:**
* Keyframe-based animations for object transformations
* Single-skeleton skinned character animations
* Animated punctual lights with dynamic lighting effects
* Parameter binding for real-time monitoring and control of object properties (position, rotation, scale)
* Dynamic parameter override from host application
**Camera & Viewport:**
* Programmatic viewport control with full camera manipulation
* Support for cameras defined within 3D editor software
* Multiple camera switching for different scene perspectives
* Orthographic and perspective projection modes
**Rendering Quality:**
* Configurable antialiasing with multiple modes:
* Always-on for consistent quality
* Always-off for maximum performance
* Auto-on that activates when scene movement stops
* Flexible background rendering:
* Environment-based backgrounds using IBL
* Solid color backgrounds
* Transparent backgrounds for overlay effects
What is glTF?
*************
@@ -85,19 +28,25 @@ glTF files can be stored as:
- **.gltf**: JSON format with external binary and image files
- **.glb**: Binary format with all assets embedded in a single file
Features
********
LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
**File Format Support:**
File Format Support
-------------------
* Loading glTF (.gltf) and binary GLB (.glb) files from local filesystem
* Support for hex-encoded bytes in source include files when filesystem is not available
* JPG, PNG, and WebP compressed texture support
* External texture files or textures embedded within the glTF source
**Rendering & Lighting:**
Rendering & Lighting
---------------------
* Image-Based Lighting (IBL) for realistic environmental lighting
* Punctual lighting support with animated light sources
@@ -108,14 +57,18 @@ LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
* Normal maps for surface detail
* Ambient occlusion textures
**Advanced Materials:**
Advanced Materials
------------------
* Emissive materials for glowing effects and self-illuminated surfaces
* Refractive materials with realistic distortion effects revealing geometry behind surfaces
* Clearcoat material support for multi-layer surface effects (like automotive paint finishes)
* Full transparency support with alpha blending
**Animation System:**
Animation System
----------------
* Keyframe-based animations for object transformations
* Single-skeleton skinned character animations
@@ -123,14 +76,18 @@ LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
* Parameter binding for real-time monitoring and control of object properties (position, rotation, scale)
* Dynamic parameter override from host application
**Camera & Viewport:**
Camera & Viewport
-----------------
* Programmatic viewport control with full camera manipulation
* Support for cameras defined within 3D editor software
* Multiple camera switching for different scene perspectives
* Orthographic and perspective projection modes
**Rendering Quality:**
Rendering Quality
-----------------
* Configurable antialiasing with multiple modes:
@@ -144,13 +101,18 @@ LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
* Solid color backgrounds
* Transparent backgrounds for overlay effects
Requirements
************
The glTF extension relies on **OpenGL ES 3.0** for 3D rendering. LVGL includes built-in support for OpenGL ES through the GLFW driver, which provides cross-platform window management and OpenGL context creation.
The glTF extension relies on **OpenGL ES 2.0** with some extension support for 3D rendering. LVGL includes built-in support for OpenGL ES through the GLFW driver, which provides cross-platform window management and OpenGL context creation.
The renderer uses OpenGL ES 3.0 shaders (GLSL version 300 es) to provide modern PBR (Physically Based Rendering) capabilities.
The full list of extensions required can be found `here <https://gen.glad.sh/#generator=c&api=egl%3D1.5%2Cgles2%3D2.0&profile=gl%3Dcompatibility%2Cgles1%3Dcommon&extensions=EGL_EXT_image_dma_buf_import%2CEGL_EXT_image_dma_buf_import_modifiers%2CEGL_EXT_platform_base%2CEGL_EXT_platform_wayland%2CEGL_KHR_fence_sync%2CEGL_KHR_image_base%2CEGL_KHR_platform_gbm%2CEGL_KHR_platform_wayland%2CGL_APPLE_texture_max_level%2CGL_ARM_rgba8%2CGL_EXT_color_buffer_float%2CGL_EXT_color_buffer_half_float%2CGL_EXT_texture_format_BGRA8888%2CGL_EXT_texture_storage%2CGL_EXT_unpack_subimage%2CGL_OES_depth24%2CGL_OES_mapbuffer%2CGL_OES_rgb8_rgba8%2CGL_OES_texture_float%2CGL_OES_texture_half_float%2CGL_OES_texture_storage_multisample_2d_array%2CGL_OES_vertex_array_object&options=ALIAS>`__.
Dependencies
------------
@@ -159,12 +121,15 @@ The glTF extension requires the following external libraries:
:fastgltf: A C++20 library for parsing glTF files (https://github.com/spnda/fastgltf)
:libwebp: WebP image format support for textures (https://github.com/webmproject/libwebp)
Setup
*****
1. **Install Dependencies with CMake**
Install Dependencies with CMake
--------------------------------
The recommended way to integrate the required libraries is using CMake's FetchContent:
The recommended way to integrate the required libraries is using CMake's FetchContent:
.. code-block:: cmake
@@ -195,21 +160,27 @@ Setup
# Link libraries to LVGL
target_link_libraries(lvgl PUBLIC webp fastgltf)
2. **Enable glTF Support**
Set :c:macro:`LV_USE_GLTF` to ``1`` in ``lv_conf.h``.
Enable glTF Support
-------------------
Also enable other required dependencies by setting the following defines to ``1``:
Set :c:macro:`LV_USE_GLTF` to ``1`` in ``lv_conf.h``.
- :c:macro:`LV_USE_OPENGLES`
- :c:macro:`LV_USE_DRAW_OPENGLES`
- :c:macro:`LV_USE_3DTEXTURE`
Also enable other required dependencies by setting the following defines to ``1``:
3. **Setup OpenGL ES Driver**
- :c:macro:`LV_USE_OPENGLES`
- :c:macro:`LV_USE_DRAW_OPENGLES`
- :c:macro:`LV_USE_3DTEXTURE`
Follow the OpenGL ES driver setup documentation (:ref:`opengl_driver`) to configure GLFW and OpenGL ES support for your platform.
4. **Basic Setup Example**
Setup OpenGL ES Driver
-----------------------
Follow the OpenGL ES driver setup documentation (:ref:`opengl_driver`) to configure GLFW and OpenGL ES support for your platform.
Basic Setup Example
-------------------
.. code-block:: c
@@ -237,6 +208,8 @@ Setup
return 0;
}
Usage
*****
@@ -257,8 +230,9 @@ This demo creates an interactive 3D viewer with:
- Camera switching
- Visual settings adjustment
Basic glTF Viewer Creation
--------------------------
---------------------------
Here's how to create a basic glTF viewer and load a model:
@@ -276,6 +250,7 @@ Here's how to create a basic glTF viewer and load a model:
return;
}
Camera Controls
---------------
@@ -301,6 +276,7 @@ The glTF viewer provides comprehensive camera controls:
/* Recenter camera on model */
lv_gltf_recenter(gltf, model);
Animation Control
-----------------
@@ -321,6 +297,7 @@ Control model animations with these functions:
lv_gltf_model_pause_animation(model);
bool is_paused = lv_gltf_model_is_animation_paused(model);
Visual Settings
---------------
@@ -339,6 +316,100 @@ Customize the visual appearance of your 3D scene:
/* Anti-aliasing */
lv_gltf_set_antialiasing_mode(gltf, LV_GLTF_AA_DYNAMIC);
Image-Based Lighting (IBL)
---------------------------
IBL (Image-Based Lighting) uses 360° panoramic images to light and shade 3D models, creating realistic reflections and environmental effects.
Unlike traditional mathematical lighting (where light sources are calculated with approximation functions),
IBL captures the entire lighting environment in an image, producing natural-looking results with:
- **Realistic reflections** on shiny surfaces that mirror the environment
- **Ambient lighting** from all directions with proper color tinting
- **Subtle lighting effects** like under-lighting and color variation based on viewing angle
- **Visual cohesiveness** that makes models appear naturally placed in their environment
For example, using an High-Dynamic-Range (HDR) image of a forest will make your 3D model appear to be sitting in a forest.
Default Behavior
~~~~~~~~~~~~~~~~
By default, each glTF viewer automatically creates an environment using an embedded default image with a cube map resolution of 128.
This provides good visual quality for most use cases without any setup.
Custom Environments
~~~~~~~~~~~~~~~~~~~
For more control over lighting quality, to use custom HDR images, or to share environments across multiple viewers, you can create and manage environments manually:
.. code-block:: c
/* Create an IBL sampler with custom resolution */
lv_gltf_ibl_sampler_t * sampler = lv_gltf_ibl_sampler_create();
/* Set a custom cube map resolution. Higher resolution produces sharper results at a cost of longer setup time */
lv_gltf_ibl_sampler_set_cube_map_pixel_resolution(256);
/* Create environment from custom HDR/JPEG image (or NULL for default) */
lv_gltf_environment_t * env = lv_gltf_environment_create(sampler, "/path/to/environment.hdr");
/* Sampler can be deleted after environment creation */
lv_gltf_ibl_sampler_delete(sampler);
/* Apply environment to viewer */
lv_gltf_set_environment(gltf, env);
/* Optionally rotate the environment lighting */
lv_gltf_environment_set_angle(env, 45.0f);
Sharing Environments
~~~~~~~~~~~~~~~~~~~~
The same environment can be shared across multiple glTF viewers for consistent lighting and reduced memory usage:
.. code-block:: c
lv_obj_t * gltf1 = lv_gltf_create(lv_screen_active());
lv_obj_t * gltf2 = lv_gltf_create(lv_screen_active());
/* Create shared environment */
lv_gltf_ibl_sampler_t * sampler = lv_gltf_ibl_sampler_create();
lv_gltf_environment_t * env = lv_gltf_environment_create(sampler, NULL);
lv_gltf_ibl_sampler_delete(sampler);
/* Apply to multiple viewers */
/* Note that the user owns the environment and is responsible for deleting it when
all glTF objects are deleted */
lv_gltf_set_environment(gltf1, env);
lv_gltf_set_environment(gltf2, env);
Environment Images
~~~~~~~~~~~~~~~~~~
- Use equirectangular (360°) panoramic images in HDR or JPEG format
- Source images are converted to cube map format at the sampler's cube map resolution
- Higher resolution values (256-512) provide better quality but use more memory
- Lower resolution values (64-128) are more suitable for embedded systems
- Free HDR environment maps are widely available online. Choose environments that match the "look" you want (outdoor, studio, warehouse, etc.)
How It Works
~~~~~~~~~~~~
When an environment is created, the source image is processed into a cube map format (6 images representing each face of a cube).
During rendering, for each pixel of your 3D model, the renderer samples the appropriate point from this cube map data to determine lighting color and intensity.
The processing cost is paid once during environment creation.
Performance Notes
~~~~~~~~~~~~~~~~~
- Environment creation processes the source image into cube map data, which takes more time with larger resolution values
- Processing time increases with both source image resolution and cube map resolution
Multi-Model Support
-------------------
@@ -355,6 +426,7 @@ Load and manage multiple glTF models in a single viewer:
lv_gltf_model_t * primary = lv_gltf_get_primary_model(gltf);
lv_gltf_model_t * specific = lv_gltf_get_model_by_index(gltf, 1);
Model Inspection
----------------
@@ -371,6 +443,8 @@ Query model properties to understand its structure:
size_t scene_count = lv_gltf_model_get_scene_count(model);
size_t camera_count = lv_gltf_model_get_camera_count(model);
Widget Architecture
*******************
@@ -379,6 +453,7 @@ The glTF widget extends the ``lv_3dtexture`` widget, which means:
- All standard ``lv_obj`` functions work with glTF widgets (positioning, sizing, styling, etc.)
- All ``lv_3dtexture`` functions are also available for advanced 3D texture management
Animation Speed System
----------------------
@@ -389,6 +464,8 @@ Animation speeds use integer values to avoid floating-point arithmetic:
- Values greater than 1000 speed up animations (e.g., 2000 = 2.0x speed)
- Values less than 1000 slow down animations (e.g., 500 = 0.5x speed)
.. _gltf_example:
Examples
@@ -396,6 +473,8 @@ Examples
.. include:: ../../examples/libs/gltf/index.rst
.. _gltf_api:
API
+2 -2
View File
@@ -1,11 +1,11 @@
Open a GLTF from a file and make it spin forever like a platter
Open a glTF from a file and make it spin forever like a platter
---------------------------------------------------------------
.. lv_example:: libs/gltf/lv_example_gltf_1
:language: c
Open a GLTF from a file and iterate through each camera
Open a glTF from a file and iterate through each camera
-------------------------------------------------------
.. lv_example:: libs/gltf/lv_example_gltf_2
@@ -0,0 +1,92 @@
/**
* @file lv_gltf_environment.h
*
*/
#ifndef LV_GLTF_ENVIRONMENT_H
#define LV_GLTF_ENVIRONMENT_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_GLTF
#include "../../../misc/lv_types.h"
/*********************
* DEFINES
*********************/
#define LV_GLTF_DEFAULT_CUBE_MAP_RESOLUTION 128
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an IBL sampler for processing environment images
* @return pointer to the created sampler, or NULL on failure
* @note Can be safely deleted after environments are created
*/
lv_gltf_ibl_sampler_t * lv_gltf_ibl_sampler_create(void);
/**
* Set the resolution for each cubemap face
* @param pointer to a sampler
* @param resolution of each cube map face in pixels (recommended: 64-512 for embedded)
*/
void lv_gltf_ibl_sampler_set_cube_map_pixel_resolution(lv_gltf_ibl_sampler_t * sampler, uint32_t resolution);
/**
* Delete an IBL sampler
* @param sampler pointer to the sampler to delete
*/
void lv_gltf_ibl_sampler_delete(lv_gltf_ibl_sampler_t * sampler);
/**
* Create an environment from an HDR or JPEG panoramic image for IBL rendering
* @param sampler IBL sampler defining output resolution (can be deleted after this call)
* @param file_path path to equirectangular environment image, or NULL to use default embedded image
* @return pointer to the created environment, or NULL on failure
*
* @note The source image will be downsampled to the sampler's texture_size
* @note The environment can be shared across multiple glTF objects
*/
lv_gltf_environment_t * lv_gltf_environment_create(lv_gltf_ibl_sampler_t * sampler, const char * file_path);
/**
* Set the rotation angle of the environment map
* @param env pointer to the environment
* @param angle rotation angle in degrees
*/
void lv_gltf_environment_set_angle(lv_gltf_environment_t * env, float angle);
/**
* Delete an environment
* @param environment pointer to the environment to delete
*/
void lv_gltf_environment_delete(lv_gltf_environment_t * environment);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GLTF*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_GLTF_ENVIRONMENT_H*/
@@ -1,10 +1,10 @@
/**
* @file lv_gltf_ibl_sampler.h
* @file lv_gltf_environment_private.h
*
*/
#ifndef LV_GLTF_IBL_SAMPLER_H
#define LV_GLTF_IBL_SAMPLER_H
#ifndef LV_GLTF_ENVIRONMENT_PRIVATE_H
#define LV_GLTF_ENVIRONMENT_PRIVATE_H
#ifdef __cplusplus
extern "C" {
@@ -13,12 +13,12 @@ extern "C" {
/*********************
* INCLUDES
*********************/
#include "../../../../lv_conf_internal.h"
#include "../../../lv_conf_internal.h"
#if LV_USE_GLTF
#include "../../../../misc/lv_types.h"
#include "../../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
#include "../lv_gltf_view_internal.h"
#include "lv_gltf_environment.h"
#include "../../../misc/lv_types.h"
#include "../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
/*********************
* DEFINES
@@ -28,12 +28,12 @@ extern "C" {
* TYPEDEFS
**********************/
typedef struct {
uint32_t texture_size;
struct _lv_gltf_ibl_sampler {
uint32_t cube_map_resolution;
float lod_bias;
uint32_t lowest_mip_level;
uint32_t input_texture_id;
uint32_t cubemap_texture_id;
uint32_t cube_map_texture_id;
uint32_t framebuffer;
uint32_t mipmap_count;
@@ -61,7 +61,7 @@ typedef struct {
uint32_t fullscreen_vertex_buffer;
uint32_t fullscreen_tex_coord_buffer;
} lv_gltf_ibl_sampler_t;
};
typedef struct {
uint8_t * data;
@@ -77,20 +77,30 @@ typedef struct {
uint32_t height;
} lv_gltf_ibl_image_t;
struct _lv_gltf_environment {
uint32_t diffuse;
uint32_t specular;
uint32_t sheen;
uint32_t ggxLut;
uint32_t charlie_lut;
uint32_t mip_count;
float ibl_intensity_scale;
float angle;
};
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_gltf_ibl_generate_env_textures(lv_gltf_view_env_textures_t * env, const char * env_file_path,
float env_rotation);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GLTF*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_GLTF_IBL_SAMPLER_H*/
#endif /*LV_GLTF_ENVIRONMENT_PRIVATE_H*/
@@ -7,22 +7,22 @@
* INCLUDES
*********************/
#include "lv_gltf_ibl_sampler.h"
#include "lv_gltf_environment_private.h"
#if LV_USE_GLTF
#include "../../../../misc/lv_math.h"
#include "../../../../misc/lv_log.h"
#include "../../../../stdlib/lv_string.h"
#include "../../../../drivers/opengles/lv_opengles_private.h"
#include "../../../../drivers/opengles/lv_opengles_debug.h"
#include "../../../misc/lv_math.h"
#include "../../../misc/lv_log.h"
#include "../../../stdlib/lv_sprintf.h"
#include "../../../stdlib/lv_string.h"
#include "../../../drivers/opengles/lv_opengles_private.h"
#include "../../../drivers/opengles/lv_opengles_debug.h"
#include "../../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
#include "../lv_gltf_view_internal.h"
#include "../assets/lv_gltf_view_shader.h"
#include "../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
#include "../gltf_view/assets/lv_gltf_view_shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "../../stb_image/stb_image.h"
#include "../stb_image/stb_image.h"
/*********************
* DEFINES
@@ -39,7 +39,6 @@
* STATIC PROTOTYPES
**********************/
static void ibl_sampler_init(lv_gltf_ibl_sampler_t * sampler);
static void ibl_sampler_load(lv_gltf_ibl_sampler_t * sampler, const char * path);
static void ibl_sampler_filter(lv_gltf_ibl_sampler_t * sampler);
static void ibl_sampler_destroy(lv_gltf_ibl_sampler_t * sampler);
@@ -47,14 +46,14 @@ static bool ibl_gl_has_extension(const char * extension);
static void ibl_texture_from_image(lv_gltf_ibl_sampler_t * sampler, lv_gltf_ibl_texture_t * texture,
const lv_gltf_ibl_image_t * image);
static GLuint ibl_load_texture_hdr(lv_gltf_ibl_sampler_t * sampler, const lv_gltf_ibl_image_t * image);
static GLuint ibl_create_cubemap_texture(const lv_gltf_ibl_sampler_t * sampler, bool with_mipmaps);
static GLuint ibl_create_cube_map_texture(const lv_gltf_ibl_sampler_t * sampler, bool with_mipmaps);
static uint32_t ibl_create_lut_texture(const lv_gltf_ibl_sampler_t * sampler);
static void ibl_panorama_to_cubemap(lv_gltf_ibl_sampler_t * sampler);
static void ibl_apply_filter(lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, float roughness,
uint32_t target_mip_level, GLuint target_texture, uint32_t sample_count, float lod_bias);
static void ibl_cubemap_to_lambertian(lv_gltf_ibl_sampler_t * sampler);
static void ibl_cubemap_to_ggx(lv_gltf_ibl_sampler_t * sampler);
static void ibl_cubemap_to_sheen(lv_gltf_ibl_sampler_t * sampler);
static void ibl_cube_map_to_lambertian(lv_gltf_ibl_sampler_t * sampler);
static void ibl_cube_map_to_ggx(lv_gltf_ibl_sampler_t * sampler);
static void ibl_cube_map_to_sheen(lv_gltf_ibl_sampler_t * sampler);
static void ibl_sample_lut(lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, uint32_t targetTexture,
uint32_t currentTextureSize);
static void ibl_sample_ggx_lut(lv_gltf_ibl_sampler_t * sampler);
@@ -76,33 +75,16 @@ static void draw_fullscreen_quad(lv_gltf_ibl_sampler_t * sampler, GLuint program
* GLOBAL FUNCTIONS
**********************/
void lv_gltf_ibl_generate_env_textures(lv_gltf_view_env_textures_t * env, const char * path, float env_rotation)
lv_gltf_ibl_sampler_t * lv_gltf_ibl_sampler_create(void)
{
lv_gltf_ibl_sampler_t sampler;
lv_gltf_ibl_sampler_t * sampler = lv_zalloc(sizeof(*sampler));
LV_ASSERT_MALLOC(sampler)
if(!sampler) {
LV_LOG_WARN("Failed to create sampler");
return NULL;
}
ibl_sampler_init(&sampler);
ibl_sampler_load(&sampler, path);
ibl_sampler_filter(&sampler);
env->angle = env_rotation;
env->diffuse = sampler.lambertian_texture_id;
env->specular = sampler.ggx_texture_id;
env->sheen = sampler.sheen_texture_id;
env->ggxLut = sampler.ggxlut_texture_id;
env->charlie_lut = sampler.charlielut_texture_id;
env->mip_count = sampler.mipmap_levels;
env->ibl_intensity_scale = sampler.scale_value;
ibl_sampler_destroy(&sampler);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void ibl_sampler_init(lv_gltf_ibl_sampler_t * sampler)
{
lv_memset(sampler, 0, sizeof(*sampler));
sampler->texture_size = 128;
sampler->cube_map_resolution = LV_GLTF_DEFAULT_CUBE_MAP_RESOLUTION;
sampler->ggx_sample_count = 128;
sampler->lambertian_sample_count = 256;
sampler->sheen_sample_count = 32;
@@ -111,13 +93,86 @@ static void ibl_sampler_init(lv_gltf_ibl_sampler_t * sampler)
sampler->lut_resolution = 1024;
sampler->lut_sample_count = 64;
sampler->scale_value = 1.0;
lv_opengl_shader_portions_t env_shader_portions;
lv_gltf_view_shader_get_env(&env_shader_portions);
lv_opengl_shader_manager_init(&sampler->shader_manager, env_shader_portions.all, env_shader_portions.count, NULL,
NULL);
init_fullscreen_quad(sampler);
return sampler;
}
void lv_gltf_ibl_sampler_set_cube_map_pixel_resolution(lv_gltf_ibl_sampler_t * sampler, uint32_t resolution)
{
if(!sampler) {
LV_LOG_WARN("Can't set cube map resolution on a NULL sampler");
return;
}
if(resolution == 0) {
LV_LOG_WARN("Cube map resolution should be > 0");
return;
}
sampler->cube_map_resolution = resolution;
}
void lv_gltf_ibl_sampler_delete(lv_gltf_ibl_sampler_t * sampler)
{
if(!sampler) {
LV_LOG_WARN("Can't delete a NULL sampler");
return;
}
ibl_sampler_destroy(sampler);
lv_free(sampler);
}
void lv_gltf_environment_set_angle(lv_gltf_environment_t * env, float angle)
{
if(!env) {
LV_LOG_WARN("Can't set angle on a NULL environment");
return;
}
env->angle = angle;
}
lv_gltf_environment_t * lv_gltf_environment_create(lv_gltf_ibl_sampler_t * sampler, const char * file_path)
{
if(!sampler) {
LV_LOG_WARN("Can't create an environment with a NULL sampler");
return NULL;
}
lv_gltf_environment_t * env = lv_zalloc(sizeof(*env));
LV_ASSERT_MALLOC(env);
if(!env) {
LV_LOG_WARN("Failed to create environment");
return NULL;
}
ibl_sampler_load(sampler, file_path);
ibl_sampler_filter(sampler);
env->diffuse = sampler->lambertian_texture_id;
env->specular = sampler->ggx_texture_id;
env->sheen = sampler->sheen_texture_id;
env->ggxLut = sampler->ggxlut_texture_id;
env->charlie_lut = sampler->charlielut_texture_id;
env->mip_count = sampler->mipmap_levels;
env->ibl_intensity_scale = sampler->scale_value;
return env;
}
void lv_gltf_environment_delete(lv_gltf_environment_t * env)
{
const unsigned int d[3] = { env->diffuse, env->specular, env->sheen };
GL_CALL(glDeleteTextures(3, d));
lv_free(env);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void ibl_sampler_load(lv_gltf_ibl_sampler_t * sampler, const char * path)
{
// vv -- WebGL Naming
@@ -159,16 +214,16 @@ static void ibl_sampler_load(lv_gltf_ibl_sampler_t * sampler, const char * path)
GL_CALL(glGenFramebuffers(1, &sampler->framebuffer));
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
sampler->cubemap_texture_id = ibl_create_cubemap_texture(sampler, true);
sampler->lambertian_texture_id = ibl_create_cubemap_texture(sampler, false);
sampler->ggx_texture_id = ibl_create_cubemap_texture(sampler, true);
sampler->sheen_texture_id = ibl_create_cubemap_texture(sampler, true);
sampler->cube_map_texture_id = ibl_create_cube_map_texture(sampler, true);
sampler->lambertian_texture_id = ibl_create_cube_map_texture(sampler, false);
sampler->ggx_texture_id = ibl_create_cube_map_texture(sampler, true);
sampler->sheen_texture_id = ibl_create_cube_map_texture(sampler, true);
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->ggx_texture_id));
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->sheen_texture_id));
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
sampler->mipmap_levels = ibl_count_bits(sampler->texture_size) + 1 - sampler->lowest_mip_level;
sampler->mipmap_levels = ibl_count_bits(sampler->cube_map_resolution) + 1 - sampler->lowest_mip_level;
}
static void ibl_sampler_filter(lv_gltf_ibl_sampler_t * sampler)
@@ -179,13 +234,13 @@ static void ibl_sampler_filter(lv_gltf_ibl_sampler_t * sampler)
ibl_panorama_to_cubemap(sampler);
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
ibl_cubemap_to_lambertian(sampler);
ibl_cube_map_to_lambertian(sampler);
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
ibl_cubemap_to_ggx(sampler);
ibl_cube_map_to_ggx(sampler);
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
ibl_cubemap_to_sheen(sampler);
ibl_cube_map_to_sheen(sampler);
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
ibl_sample_ggx_lut(sampler);
@@ -274,14 +329,14 @@ static uint32_t ibl_load_texture_hdr(lv_gltf_ibl_sampler_t * sampler, const lv_g
return texture_id;
}
static GLuint ibl_create_cubemap_texture(const lv_gltf_ibl_sampler_t * sampler, bool with_mipmaps)
static GLuint ibl_create_cube_map_texture(const lv_gltf_ibl_sampler_t * sampler, bool with_mipmaps)
{
uint32_t targetTexture;
GL_CALL(glGenTextures(1, &targetTexture));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, targetTexture));
for(int32_t i = 0; i < 6; ++i) {
GL_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, INTERNAL_FORMAT, sampler->texture_size,
sampler->texture_size, 0, GL_RGBA, TEXTURE_TARGET_TYPE, NULL));
GL_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, INTERNAL_FORMAT, sampler->cube_map_resolution,
sampler->cube_map_resolution, 0, GL_RGBA, TEXTURE_TARGET_TYPE, NULL));
}
if(with_mipmaps) {
GL_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
@@ -312,15 +367,15 @@ static void ibl_panorama_to_cubemap(lv_gltf_ibl_sampler_t * sampler)
for(int32_t i = 0; i < 6; ++i) {
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
sampler->cubemap_texture_id, 0));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
sampler->cube_map_texture_id, 0));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cube_map_texture_id));
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
while(status != GL_FRAMEBUFFER_COMPLETE) {
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
LV_LOG_ERROR("Environnement render error not complete. Expected %d. Got %d", GL_FRAMEBUFFER_COMPLETE,
status);
}
GL_CALL(glViewport(0, 0, sampler->texture_size, sampler->texture_size));
GL_CALL(glViewport(0, 0, sampler->cube_map_resolution, sampler->cube_map_resolution));
GL_CALL(glClearColor(1.0, 0.0, 0.0, 0.0));
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
uint32_t frag_shader_hash;
@@ -352,13 +407,13 @@ static void ibl_panorama_to_cubemap(lv_gltf_ibl_sampler_t * sampler)
draw_fullscreen_quad(sampler, program_id);
}
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cube_map_texture_id));
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
}
static void ibl_apply_filter(lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, float roughness,
uint32_t target_mip_level, GLuint target_texture, uint32_t sample_count, float lod_bias)
{
uint32_t current_texture_size = sampler->texture_size >> target_mip_level;
uint32_t current_texture_size = sampler->cube_map_resolution >> target_mip_level;
for(uint32_t i = 0; i < 6; ++i) {
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
@@ -387,7 +442,7 @@ static void ibl_apply_filter(lv_gltf_ibl_sampler_t * sampler, uint32_t distribut
GL_CALL(glUseProgram(program_id));
GL_CALL(glActiveTexture(GL_TEXTURE0));
// Bind texture ID to active texture
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cube_map_texture_id));
// map shader uniform to texture unit (TEXTURE0)
uint32_t location = glGetUniformLocation(program_id, "u_cubemapTexture");
GL_CALL(glUniform1i(location, 0)); // texture unit 0
@@ -396,7 +451,7 @@ static void ibl_apply_filter(lv_gltf_ibl_sampler_t * sampler, uint32_t distribut
/* Software rendered mode looks better with this and horrible with below */
/*program->update_uniform_1i(program, "u_width", current_texture_size); */
/* Standard mode looks best with this and somewhat worse with above */
program->update_uniform_1i(program, "u_width", sampler->texture_size);
program->update_uniform_1i(program, "u_width", sampler->cube_map_resolution);
program->update_uniform_1f(program, "u_lodBias", lod_bias);
program->update_uniform_1i(program, "u_distribution", distribution);
program->update_uniform_1i(program, "u_currentFace", i);
@@ -407,11 +462,11 @@ static void ibl_apply_filter(lv_gltf_ibl_sampler_t * sampler, uint32_t distribut
draw_fullscreen_quad(sampler, program_id);
}
}
static void ibl_cubemap_to_lambertian(lv_gltf_ibl_sampler_t * sampler)
static void ibl_cube_map_to_lambertian(lv_gltf_ibl_sampler_t * sampler)
{
ibl_apply_filter(sampler, 0, 0.0, 0, sampler->lambertian_texture_id, sampler->lambertian_sample_count, 0.0);
}
static void ibl_cubemap_to_ggx(lv_gltf_ibl_sampler_t * sampler)
static void ibl_cube_map_to_ggx(lv_gltf_ibl_sampler_t * sampler)
{
LV_ASSERT(sampler->mipmap_levels != 1);
for(uint32_t current_mip_level = 0; current_mip_level <= sampler->mipmap_levels; ++current_mip_level) {
@@ -420,7 +475,7 @@ static void ibl_cubemap_to_ggx(lv_gltf_ibl_sampler_t * sampler)
0.0);
}
}
static void ibl_cubemap_to_sheen(lv_gltf_ibl_sampler_t * sampler)
static void ibl_cube_map_to_sheen(lv_gltf_ibl_sampler_t * sampler)
{
LV_ASSERT(sampler->mipmap_levels != 1);
for(uint32_t current_mip_level = 0; current_mip_level <= sampler->mipmap_levels; ++current_mip_level) {
@@ -457,7 +512,7 @@ static void ibl_sample_lut(lv_gltf_ibl_sampler_t * sampler, uint32_t distributio
// TEXTURE0 = active.
GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
// Bind texture ID to active texture
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cube_map_texture_id));
// map shader uniform to texture unit (TEXTURE0)
uint32_t location = glGetUniformLocation(program_id, "u_cubemapTexture");
GL_CALL(glUniform1i(location, 0)); // texture unit 0
+53 -43
View File
@@ -70,82 +70,92 @@ typedef lv_3dplane_t lv_3dray_t;
**********************/
/**
* Create a GLTF viewer object
* Create a glTF object
* @param parent pointer to the parent object
* @return pointer to the created GLTF viewer object
* @return pointer to the created glTF object
*/
lv_obj_t * lv_gltf_create(lv_obj_t * parent);
/**
* Load a GLTF model from a file into the viewer
* @param obj pointer to a GLTF viewer object
* @param path file path to the GLTF model to load
* @return pointer to the loaded GLTF model, or NULL on failure
* Assign an environment to a glTF object for IBL rendering
* @param obj pointer to a glTF viewer object
* @param environment pointer to the environment to use
* @note The environment can be shared across multiple glTF objects
* @note If no environment is set before attempting to load a file,
* a default one will be created for you
*/
void lv_gltf_set_environment(lv_obj_t * obj, lv_gltf_environment_t * environment);
/**
* Load a glTF model from a file into the viewer
* @param obj pointer to a glTF viewer object
* @param path file path to the glTF model to load
* @return pointer to the loaded glTF model, or NULL on failure
*/
lv_gltf_model_t * lv_gltf_load_model_from_file(lv_obj_t * obj, const char * path);
/**
* Get the number of models loaded in the GLTF viewer
* @param obj pointer to a GLTF viewer object
* Get the number of models loaded in the glTF viewer
* @param obj pointer to a glTF viewer object
* @return the total number of models in the viewer
*/
size_t lv_gltf_get_model_count(lv_obj_t * obj);
/**
* Get a specific model by its index
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param id index of the model to retrieve (0-based)
* @return pointer to the model at the specified index, or NULL if index is invalid
*/
lv_gltf_model_t * lv_gltf_get_model_by_index(lv_obj_t * obj, size_t id);
/**
* Get the primary model from the GLTF viewer
* Get the primary model from the glTF viewer
* The primary model is the first model added to the viewer and can be used
* for camera selection and other primary operations
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return pointer to the primary model, or NULL if no models are loaded
*/
lv_gltf_model_t * lv_gltf_get_primary_model(lv_obj_t * obj);
/**
* Set the yaw (horizontal rotation) of the camera
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param yaw yaw angle in degrees
*/
void lv_gltf_set_yaw(lv_obj_t * obj, float yaw);
/**
* Get the yaw (horizontal rotation) of the camera
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return yaw angle in degrees
*/
float lv_gltf_get_yaw(const lv_obj_t * obj);
/**
* Set the pitch (vertical rotation) of the camera
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param pitch pitch angle in degrees
*/
void lv_gltf_set_pitch(lv_obj_t * obj, float pitch);
/**
* Get the pitch (vertical rotation) of the camera
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return pitch angle in degrees
*/
float lv_gltf_get_pitch(const lv_obj_t * obj);
/**
* Set the camera distance from the focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value distance value
*/
void lv_gltf_set_distance(lv_obj_t * obj, float value);
/**
* Get the camera distance scale factor from the focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return distance scaling factor value
*/
float lv_gltf_get_distance(const lv_obj_t * obj);
@@ -163,14 +173,14 @@ float lv_gltf_get_world_distance(const lv_obj_t * obj);
/**
* Set the field of view
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value vertical FOV in degrees. If zero, the view will be orthographic (non-perspective)
*/
void lv_gltf_set_fov(lv_obj_t * obj, float value);
/**
* Get the field of view
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return vertical FOV in degrees
*/
float lv_gltf_get_fov(const lv_obj_t * obj);
@@ -181,49 +191,49 @@ float lv_gltf_get_fov(const lv_obj_t * obj);
/**
* Set the X coordinate of the camera focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value X coordinate
*/
void lv_gltf_set_focal_x(lv_obj_t * obj, float value);
/**
* Get the X coordinate of the camera focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return X coordinate
*/
float lv_gltf_get_focal_x(const lv_obj_t * obj);
/**
* Set the Y coordinate of the camera focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value Y coordinate
*/
void lv_gltf_set_focal_y(lv_obj_t * obj, float value);
/**
* Get the Y coordinate of the camera focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return Y coordinate
*/
float lv_gltf_get_focal_y(const lv_obj_t * obj);
/**
* Set the Z coordinate of the camera focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value Z coordinate
*/
void lv_gltf_set_focal_z(lv_obj_t * obj, float value);
/**
* Get the Z coordinate of the camera focal point
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return Z coordinate
*/
float lv_gltf_get_focal_z(const lv_obj_t * obj);
/**
* Set the focal coordinates to the center point of the model object
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param model a model attached to this viewer or NULL for the first model
*/
void lv_gltf_recenter(lv_obj_t * obj, lv_gltf_model_t * model);
@@ -234,9 +244,9 @@ void lv_gltf_recenter(lv_obj_t * obj, lv_gltf_model_t * model);
/**
* Set the active camera index
* The camera is selected from the first GLTF model added to the viewer
* The camera is selected from the first glTF model added to the viewer
*
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value camera index (0 for default camera, 1+ for scene camera index)
* @note Values higher than the scene's camera count will be clamped to the maximum available camera index
*/
@@ -244,20 +254,20 @@ void lv_gltf_set_camera(lv_obj_t * obj, uint32_t value);
/**
* Get the active camera index
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return active camera index
*/
uint32_t lv_gltf_get_camera(const lv_obj_t * obj);
/**
* Get the number of cameras in the first GLTF model added to the viewer
* Get the number of cameras in the first glTF model added to the viewer
* This count represents the valid range for the camera index parameter
* used with lv_gltf_set_camera()
*
* To get the camera count of other models, call
* lv_gltf_model_get_camera_count(model) directly with the specific model
*
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return number of available cameras
*/
uint32_t lv_gltf_get_camera_count(const lv_obj_t * obj);
@@ -269,7 +279,7 @@ uint32_t lv_gltf_get_camera_count(const lv_obj_t * obj);
* Values greater than LV_GLTF_ANIM_SPEED_NORMAL will speed-up the animation
* Values less than LV_GLTF_ANIM_SPEED_NORMAL will slow down the animation
*
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value speed-up ratio of the animation
*/
void lv_gltf_set_animation_speed(lv_obj_t * obj, uint32_t value);
@@ -279,7 +289,7 @@ void lv_gltf_set_animation_speed(lv_obj_t * obj, uint32_t value);
*
* The actual ratio is the return value / LV_GLTF_ANIM_SPEED_NORMAL
*
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
*/
uint32_t lv_gltf_get_animation_speed(const lv_obj_t * obj);
@@ -289,56 +299,56 @@ uint32_t lv_gltf_get_animation_speed(const lv_obj_t * obj);
/**
* Set the background mode
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value background mode
*/
void lv_gltf_set_background_mode(lv_obj_t * obj, lv_gltf_bg_mode_t value);
/**
* Get the background mode
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return background mode
*/
lv_gltf_bg_mode_t lv_gltf_get_background_mode(const lv_obj_t * obj);
/**
* Set the background blur amount
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value blur amount between 0 and 100
*/
void lv_gltf_set_background_blur(lv_obj_t * obj, uint32_t value);
/**
* Get the background blur amount
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return blur amount between 0 and 100
*/
uint32_t lv_gltf_get_background_blur(const lv_obj_t * obj);
/**
* Set the environmental brightness/power
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value brightness multiplier
*/
void lv_gltf_set_env_brightness(lv_obj_t * obj, uint32_t value);
/**
* Get the environmental brightness/power
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return brightness multiplier
*/
uint32_t lv_gltf_get_env_brightness(const lv_obj_t * obj);
/**
* Set the image exposure level
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value exposure level (1.0 is default)
*/
void lv_gltf_set_image_exposure(lv_obj_t * obj, float value);
/**
* Get the image exposure level
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return exposure level
*/
float lv_gltf_get_image_exposure(const lv_obj_t * obj);
@@ -349,14 +359,14 @@ float lv_gltf_get_image_exposure(const lv_obj_t * obj);
/**
* Set the anti-aliasing mode
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @param value anti-aliasing mode
*/
void lv_gltf_set_antialiasing_mode(lv_obj_t * obj, lv_gltf_aa_mode_t value);
/**
* Get the anti-aliasing mode
* @param obj pointer to a GLTF viewer object
* @param obj pointer to a glTF viewer object
* @return anti-aliasing mode
*/
lv_gltf_aa_mode_t lv_gltf_get_antialiasing_mode(const lv_obj_t * obj);
+51 -11
View File
@@ -18,7 +18,7 @@
#include "../../../core/lv_obj_class_private.h"
#include "../../../misc/lv_types.h"
#include "../../../widgets/3dtexture/lv_3dtexture.h"
#include "ibl/lv_gltf_ibl_sampler.h"
#include "../gltf_environment/lv_gltf_environment.h"
#include "assets/lv_gltf_view_shader.h"
#include <fastgltf/math.hpp>
#include <fastgltf/tools.hpp>
@@ -49,10 +49,12 @@ static void lv_gltf_event(const lv_obj_class_t * class_p, lv_event_t * e);
static void lv_gltf_view_state_init(lv_gltf_t * state);
static void lv_gltf_view_desc_init(lv_gltf_view_desc_t * state);
static void lv_gltf_parse_model(lv_gltf_t * viewer, lv_gltf_model_t * model);
static void destroy_environment(lv_gltf_view_env_textures_t * env);
static void destroy_environment(lv_gltf_environment_t * env);
static void setup_compile_and_load_bg_shader(lv_opengl_shader_manager_t * manager);
static void setup_background_environment(GLuint program, GLuint * vao, GLuint * indexBuffer, GLuint * vertexBuffer);
static lv_result_t create_default_environment(lv_gltf_t * gltf);
const lv_obj_class_t lv_gltf_class = {
&lv_3dtexture_class,
@@ -101,6 +103,14 @@ lv_gltf_model_t * lv_gltf_load_model_from_file(lv_obj_t * obj, const char * path
LV_ASSERT_NULL(obj);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * viewer = (lv_gltf_t *)obj;
if(!viewer->environment) {
lv_result_t res = create_default_environment(viewer);
if(res != LV_RESULT_OK) {
return NULL;
}
}
lv_gltf_model_t * model = lv_gltf_data_load_from_file(path, &viewer->shader_manager);
return lv_gltf_add_model(viewer, model);
}
@@ -110,9 +120,33 @@ lv_gltf_model_t * lv_gltf_load_model_from_bytes(lv_obj_t * obj, const uint8_t *
LV_ASSERT_NULL(obj);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * viewer = (lv_gltf_t *)obj;
if(!viewer->environment) {
lv_result_t res = create_default_environment(viewer);
if(res != LV_RESULT_OK) {
return NULL;
}
}
lv_gltf_model_t * model = lv_gltf_data_load_from_bytes(bytes, len, &viewer->shader_manager);
return lv_gltf_add_model(viewer, model);
}
void lv_gltf_set_environment(lv_obj_t * obj, lv_gltf_environment_t * env)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_gltf_t * gltf = (lv_gltf_t *)obj;
if(env == NULL) {
LV_LOG_WARN("Refusing to assign a NULL environment to the glTF object");
return;
}
if(gltf->environment && gltf->owns_environment) {
lv_gltf_environment_delete(gltf->environment);
gltf->environment = NULL;
}
gltf->environment = env;
gltf->owns_environment = false;
}
size_t lv_gltf_get_model_count(lv_obj_t * obj)
{
@@ -556,7 +590,6 @@ lv_result_t lv_gltf_world_to_screen(lv_obj_t * obj, const lv_3dpoint_t world_pos
static lv_gltf_model_t * lv_gltf_add_model(lv_gltf_t * viewer, lv_gltf_model_t * model)
{
if(!model) {
return NULL;
}
@@ -575,6 +608,18 @@ static lv_gltf_model_t * lv_gltf_add_model(lv_gltf_t * viewer, lv_gltf_model_t *
return model;
}
static lv_result_t create_default_environment(lv_gltf_t * gltf)
{
lv_gltf_ibl_sampler_t * sampler = lv_gltf_ibl_sampler_create();
gltf->environment = lv_gltf_environment_create(sampler, NULL);
lv_gltf_ibl_sampler_delete(sampler);
if(!gltf->environment) {
LV_LOG_WARN("Failed to create default gltf environment");
return LV_RESULT_INVALID;
}
gltf->owns_environment = true;
return LV_RESULT_OK;
}
static void lv_gltf_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
@@ -599,8 +644,6 @@ static void lv_gltf_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
lv_free(vertex_shader);
lv_free(frag_shader);
lv_gltf_ibl_generate_env_textures(&view->env_textures, NULL, 0);
lv_array_init(&view->models, LV_GLTF_INITIAL_MODEL_CAPACITY, sizeof(lv_gltf_model_t *));
LV_TRACE_OBJ_CREATE("end");
@@ -638,7 +681,9 @@ static void lv_gltf_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
for(size_t i = 0; i < n; ++i) {
lv_gltf_data_destroy(*(lv_gltf_model_t **)lv_array_at(&view->models, i));
}
destroy_environment(&view->env_textures);
if(view->environment && view->owns_environment) {
lv_gltf_environment_delete(view->environment);
}
}
static void lv_gltf_view_state_init(lv_gltf_t * view)
@@ -790,10 +835,5 @@ static void setup_background_environment(GLuint program, GLuint * vao, GLuint *
GL_CALL(glUseProgram(0));
}
static void destroy_environment(lv_gltf_view_env_textures_t * env)
{
const unsigned int d[3] = { env->diffuse, env->specular, env->sheen };
GL_CALL(glDeleteTextures(3, d));
}
#endif /*LV_USE_GLTF*/
@@ -81,16 +81,6 @@ typedef struct {
GLfloat clear_color[4];
} lv_opengl_state_t;
typedef struct {
uint32_t diffuse;
uint32_t specular;
uint32_t sheen;
uint32_t ggxLut;
uint32_t charlie_lut;
uint32_t mip_count;
float ibl_intensity_scale;
float angle;
} lv_gltf_view_env_textures_t;
#ifdef __cplusplus
}
@@ -107,14 +97,14 @@ struct _lv_gltf_t {
lv_gltf_view_desc_t desc;
lv_gltf_view_desc_t last_desc;
lv_opengl_shader_manager_t shader_manager;
lv_gltf_view_env_textures_t env_textures;
lv_gltf_environment_t * environment;
fastgltf::math::fmat4x4 view_matrix;
fastgltf::math::fmat4x4 projection_matrix;
fastgltf::math::fmat4x4 view_projection_matrix;
fastgltf::math::fvec3 camera_pos;
std::map<int32_t, std::map<fastgltf::Node *, fastgltf::math::fmat4x4>> ibm_by_skin_then_node;
bool owns_environment;
};
/**********************
+12 -11
View File
@@ -19,6 +19,7 @@
#include "../../../drivers/opengles/lv_opengles_private.h"
#include "../../../drivers/opengles/lv_opengles_debug.h"
#include "../math/lv_gltf_math.hpp"
#include "../gltf_environment/lv_gltf_environment_private.h"
#include <algorithm>
@@ -61,12 +62,12 @@ static uint32_t render_texture(uint32_t tex_unit, uint32_t tex_name, int32_t tex
GLint uv_transform);
static void draw_primitive(int32_t prim_num, lv_gltf_t * viewer, lv_gltf_model_t * gltf_data, fastgltf::Node & node,
std::size_t mesh_index, const fastgltf::math::fmat4x4 & matrix,
const lv_gltf_view_env_textures_t * env_tex, bool is_transmission_pass);
const lv_gltf_environment_t * env_tex, bool is_transmission_pass);
static void setup_primitive(int32_t prim_num, lv_gltf_t * viewer, lv_gltf_model_t * gltf_data,
fastgltf::Node & node,
std::size_t mesh_index, const fastgltf::math::fmat4x4 & matrix,
const lv_gltf_view_env_textures_t * env_tex, bool is_transmission_pass);
const lv_gltf_environment_t * env_tex, bool is_transmission_pass);
static void draw_material(lv_gltf_t * viewer, const lv_gltf_uniform_locations_t * uniforms, lv_gltf_model_t * model,
lv_gltf_primitive_t * _prim_data, size_t materialIndex, bool is_transmission_pass, GLuint program,
@@ -269,7 +270,7 @@ static GLuint lv_gltf_view_render_model(lv_gltf_t * viewer, lv_gltf_model_t * mo
const auto & node_element = node_distance_pair.second;
const auto & node = node_element.first;
draw_primitive(node_element.second, viewer, model, *node, node->meshIndex.value(),
lv_gltf_data_get_cached_transform(model, node), &viewer->env_textures, true);
lv_gltf_data_get_cached_transform(model, node), viewer->environment, true);
}
GL_CALL(glBindTexture(GL_TEXTURE_2D, vstate->opaque_render_state.texture));
@@ -302,7 +303,7 @@ static GLuint lv_gltf_view_render_model(lv_gltf_t * viewer, lv_gltf_model_t * mo
const auto & node_element = node_distance_pair.second;
const auto & node = node_element.first;
draw_primitive(node_element.second, viewer, model, *node, node->meshIndex.value(),
lv_gltf_data_get_cached_transform(model, node), &viewer->env_textures, false);
lv_gltf_data_get_cached_transform(model, node), viewer->environment, false);
}
if(opt_aa_this_frame) {
GL_CALL(glBindTexture(GL_TEXTURE_2D, vstate->render_state.texture));
@@ -328,7 +329,7 @@ static void render_materials(lv_gltf_t * viewer, lv_gltf_model_t * gltf_data, co
for(const auto & pair : kv.second) {
auto node = pair.first;
draw_primitive(pair.second, viewer, gltf_data, *node, node->meshIndex.value(),
lv_gltf_data_get_cached_transform(gltf_data, node), &viewer->env_textures, true);
lv_gltf_data_get_cached_transform(gltf_data, node), viewer->environment, true);
}
}
}
@@ -378,7 +379,7 @@ static void render_skins(lv_gltf_t * viewer, lv_gltf_model_t * model)
}
static void draw_primitive(int32_t prim_num, lv_gltf_t * viewer, lv_gltf_model_t * gltf_data, fastgltf::Node & node,
std::size_t mesh_index, const fastgltf::math::fmat4x4 & matrix,
const lv_gltf_view_env_textures_t * env_tex, bool is_transmission_pass)
const lv_gltf_environment_t * env_tex, bool is_transmission_pass)
{
lv_gltf_mesh_data_t * mesh = lv_gltf_data_get_mesh(gltf_data, mesh_index);
const auto & asset = lv_gltf_data_get_asset(gltf_data);
@@ -397,7 +398,7 @@ static void draw_primitive(int32_t prim_num, lv_gltf_t * viewer, lv_gltf_model_t
}
static void setup_primitive(int32_t prim_num, lv_gltf_t * viewer, lv_gltf_model_t * model, fastgltf::Node & node,
std::size_t mesh_index, const fastgltf::math::fmat4x4 & matrix,
const lv_gltf_view_env_textures_t * env_tex, bool is_transmission_pass)
const lv_gltf_environment_t * env_tex, bool is_transmission_pass)
{
lv_gltf_view_desc_t * view_desc = &viewer->desc;
lv_gltf_mesh_data_t * mesh = lv_gltf_data_get_mesh(model, mesh_index);
@@ -437,7 +438,7 @@ static void setup_primitive(int32_t prim_num, lv_gltf_t * viewer, lv_gltf_model_
GL_CALL(glUniform1f(uniforms->exposure, view_desc->exposure));
GL_CALL(glUniform1f(uniforms->env_intensity, view_desc->env_pow));
GL_CALL(glUniform1i(uniforms->env_mip_count, (int32_t)env_tex->mip_count));
setup_environment_rotation_matrix(viewer->env_textures.angle, program);
setup_environment_rotation_matrix(viewer->environment->angle, program);
GL_CALL(glEnable(GL_CULL_FACE));
GL_CALL(glDisable(GL_BLEND));
GL_CALL(glEnable(GL_DEPTH_TEST));
@@ -1137,16 +1138,16 @@ static void setup_draw_environment_background(lv_opengl_shader_manager_t * manag
/* Bind the texture to the specified texture unit*/
GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, viewer->env_textures.specular));
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, viewer->environment->specular));
GL_CALL(glUniform1i(glGetUniformLocation(manager->bg_program, "u_GGXEnvSampler"), 0));
GL_CALL(glUniform1i(glGetUniformLocation(manager->bg_program, "u_MipCount"), viewer->env_textures.mip_count));
GL_CALL(glUniform1i(glGetUniformLocation(manager->bg_program, "u_MipCount"), viewer->environment->mip_count));
GL_CALL(glUniform1f(glGetUniformLocation(manager->bg_program, "u_EnvBlurNormalized"), blur));
GL_CALL(glUniform1f(glGetUniformLocation(manager->bg_program, "u_EnvIntensity"), 1.0f));
GL_CALL(glUniform1f(glGetUniformLocation(manager->bg_program, "u_Exposure"), 1.0f));
setup_environment_rotation_matrix(viewer->env_textures.angle, manager->bg_program);
setup_environment_rotation_matrix(viewer->environment->angle, manager->bg_program);
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, manager->bg_index_buf));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, manager->bg_vertex_buf));
+6
View File
@@ -282,8 +282,14 @@ typedef struct _lv_gltf_t lv_gltf_t;
typedef struct _lv_gltf_model_t lv_gltf_model_t;
typedef struct _lv_gltf_environment lv_gltf_environment_t;
typedef struct _lv_gltf_ibl_sampler lv_gltf_ibl_sampler_t;
typedef struct _lv_subject_t lv_subject_t;
typedef struct _lv_observer_t lv_observer_t;
typedef struct _lv_subject_increment_dsc_t lv_subject_increment_dsc_t;
typedef struct _lv_monkey_config_t lv_monkey_config_t;