Skip to content

Blog

Release v0.8.2

Babylon.js had an issue where setting rotation or rotationQuaterion on a camera in right-handed coordinate system actually sets the camera 180 degrees flipped from what is represented in the view matrix. You can read more in the description of corresponding PR fixing the issue. In Engeenee SDK we had a workaround for this. Now when issue is fixed we’ve rolled back this workaround.

The major downside is that compatibility between different versions of Engeenee SDK and Babylon.js became slightly more complicated with the current release. If you are using a version of Engeeneee prior to 0.8.2 please use Babylon.js version 8.9.1 or lower. Starting from version 0.8.2 the minimum compatible version of Babylon.js is 8.11.0.

Babylon.js is a peer dependency of Engeenee’s @geenee/bodyrenderers-babylon, the rule of thumb when updating the SDK is to switch to the minimum compatible version of Babylon.js first (the one stated in package.json of bodyrenderers-babylon), and then gradually update the renderer if newer features or fixes are required.

Release v0.8.1

With this release we are switching to WebGL2 in all stages of processing and rendering pipelines. Previously, processing and effect shaders of the Engeenee SDK where written in WebGL1 for better compatibility with older devices and browsers. Meanwhile, inference of neural networks and most rendering engines already heavily utilize modern WebGL2 features that are available in all browsers for at least 5 years. Therefore, we’ve decided to port rest of GPGPU and image processing to the newer graphics standard that is by the way already pretty old (=.

All shaders were re-written and porting process is very straightforward and simple. If you have custom shaders utilized in ShaderProgram or ShaderPlugin, please update the code to follow WebGL2 shader syntax. We recommend this guide that describes major differences between standards. Basically, one needs to make the next simple changes to a shader code:

  • Replace attribure -> in
  • In vertex shader, replace varying -> out
  • In fragment shader, replace varying -> in
  • Replace gl_FragColor with any out vec4 variable and assign to it
  • Use texture() instead of texture2D(), textureCube(), etc
  • ShaderProgram adds #version 300 es line automatically

For fast prototyping of simple UIs in demos and examples we are using very lightweight library of UI components developed internally. Gluon library is build on top of amazing VanJS - ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework written in vanilla JavaScript and DOM. VanJS doesn’t rely on JSX or introduce any special syntax to compose UI components, therefore we don’t need any additional transpilers. For styling Gluon utilizes UnoCSS - fast and flexible atomic CSS engine.

With this release we are making Gluon library available for all users of the Engeenee SDK. Engeenee remains framework agnostic and doesn’t restrict choice of UI framework. We just think that very lightweight UI library having zero dependencies and very easy to pick up may be useful as a starting point for enthusiasts who would like to achieve the fastest performance possible, have closer to bare-metal experience and concentrate more on the most interesting parts: 3D, visuals, and interactivity.

This release includes the next minor changes and fixes:

  • Added HeadFitPlugin.setNode(), method that was missing after major refactoring.
  • All internal dependencies are updated to the latest versions.

Release v0.8.0

This is a major release with lots of API breaking changes. Engeenee SDK has been significantly refactored but math and algorithms are mostly untouched.

We’ve introduced MaskProcessPlugin - base plugin for post-processing of a segmentation mask. It applies an image processing shader on the mask texture and updates the corresponding field of tracking results. Mask processing plugins can be combined and chained in a pipeline. Order in which operation on segmentation mask are applied corresponds to the order in which mask plugins are attached to the renderer. This plugin helps to simplify API and internal implementations. The next plugins now reuse base implementation inheriting MaskProcessPlugin: MaskSmoothPlugin, MaskMorphPlugin, MaskDilationPlugin, MaskErosionPlugin, MaskBinaryPlugin, MaskStepPlugin.

We removed attaching of a scene node that will be controlled by a plugin in its constructor. Usually, plugin pipeline is assembled within Renderer’s constructor, or completely outside of the Renderer. In both cases there’s no access to the scene or no assets are loaded yet; scene initialization happens in load() method and assets are loaded asynchronously. So almost always undefined was passed as node parameter. Now attaching of a node can be done only via setNode() method of a plugin. For example, refer new HeadFitPlugin(), node can be attached later, after constructor, with setNode().

There are three big changes in naming convention for plugins.

We now use word Fit instead of Align. For example, we rename HeadTrackPlugin to HeadFitPlugin. Plugins that fit scene nodes according to tracking data were renamed:

  • HeadTrackPlugin -> HeadFitPlugin
  • FaceTrackPlugin -> FacePointPlugin
  • HandAlignPlugin -> HandFitPlugin
  • WristTrackPlugin -> WristFitPlugin
  • HandFitPlugin -> FingersFitPlugin
  • HandGeometry -> FingersGeometry

Another change regards supported armature types. We support two armatures: compatible with Ready Player Me and Mixamo, and compatible with Clo3D and Marvelous Designer. At the moment Clo3D armature is considered the main one, and all updates and improvements are implemented for this armature first. Historically, plugins for Mixamo armature were called PoseSomethingPlugin and for Clo3D armature ClothSomethingPlugin. We resolve this ambiguity and from now one will call the main Clo3D armature Pose, and the secondary legacy Mixamo armature PoseB. Later it will be possible to introduce PoseC, PoseD, etc without breaking naming convention. Armature fitting plugins were renamed the next way:

  • ClothAlignPlugin -> PoseFitPlugin
  • ClothTwinPlugin -> PoseTwinPlugin
  • ClothSkirtPlugin ->SkirtFitPlugin
  • PoseAlignPlugin -> PoseBFitPlugin
  • PoseTwinPlugin -> PoseBTwinPlugin
  • PoseSkirtPlugin -> SkirtBFitPlugin

As patching can be applied to any segmentation mask, word Body doesn’t fit anymore, so we renamed patching plugins as well:

  • BodyPatchPlugin -> PatchPlugin
  • BodypartPatchPlugin -> PatchPartPlugin

The complete list of renamed plugins:

  • ClothAlignPlugin -> PoseFitPlugin
  • ClothTwinPlugin -> PoseTwinPlugin
  • ClothSkirtPlugin ->SkirtFitPlugin
  • PoseAlignPlugin -> PoseBFitPlugin
  • PoseTwinPlugin -> PoseBTwinPlugin
  • PoseSkirtPlugin -> SkirtBFitPlugin
  • HeadTrackPlugin -> HeadFitPlugin
  • FaceTrackPlugin -> FacePointPlugin
  • HandAlignPlugin -> HandFitPlugin
  • WristTrackPlugin -> WristFitPlugin
  • HandFitPlugin -> FingersFitPlugin
  • HandGeometry -> FingersGeometry
  • BodyPatchPlugin -> PatchPlugin
  • BodypartPatchPlugin -> PatchPartPlugin

Engeenee SDK moves to the new cloud infrastructure. On the front side the only changes are URLs of our npm registry and where to get SDK tokens. Registry is now hosted on npm.geen.ee, to direct npm to our registry for @geenee/ packages add this line to your .npmrc file @geenee:registry=https://npm.geen.ee.

Access tokens are managed from new SDK Manager. Here one can create, delete, or update SDK access tokens for urls where apps are hosted. And get NPM token as well to download SDK packages.

Example of .npmrc file:

registry=https://registry.npmjs.org
@geenee:registry=https://npm.geen.ee
//registry.npmjs.org/:_authToken="registry.npmjs.org_TOKEN"
//npm.geen.ee/:_authToken="npm.geen.ee_TOKEN"

We’ve removed deprecated OccluderPlugin and PoseOutfitPlugin from three.js library. Please, use OccluderMaterial directly to transform scene meshes into occluders, this is a more flexible and universal approach to control rendering of 3D objects in a scene.

Three.js plugins are refactored to use named imports that reduces final bundle size. Additionally, we’ve revisited and optimized their code.

spineCurve parameter of PoseFitPlugin is treated more robustly and not overriden with 0.0 when other pose tuning parameter are specified and it’s left undefined.

Release v0.7.6

In this maintenance release we’ve updated all internal dependencies to the latest versions. The major internal changes are that we’ve switched to the latest Emscripten toolchain to build WASM modules and the latest Typescript bundler and transpilers for Javascript parts of the SDK.

Yet being well tested and verified as we do with all releases of the SDK, this version is not advertised as 100% stable because of much bigger number of internal changes than usual. We still recommend to try it out to provide smoother transition to the next versions, and rollback if anything goes wrong.

This release switches to the next major version 8.2 of Babylon.js. In additional to many new good features introduced in Babylon.js 8 this version fixes several things in keeping WebGL state consistent. These fixes provide safer sharing of WebGL context between Babylon rendering engine and Engeenee SDK.

The release doesn’t introduce any changes of the SDK’s API, therefore being fully backward compatible. Kindly note, that with the major release of Babylon.js engine some things became deprecated on its side. For example, in virtual try-on apps 3D asset loading APIs are used pretty frequently and loadAssetContainerAsync is deprecated in favor of LoadAssetContainerAsync.

The next diff shows how to refactor to the newer LoadAssetContainerAsync:

const gltf = await SceneLoader.LoadAssetContainerAsync(
"", "asset.glb", this.scene, undefined, ".glb");
const gltf = await LoadAssetContainerAsync(
"asset.glb", scene, { pluginExtension: ".glb" });

Release v0.7.5

The most important new feature added in this release is Hair Segmentation. We have added the new type of tracking that allows to implement virtual try-on effects like hair recoloring, patching of hairs in headwear virtual try-on, and many more. Hair Segmentation is GPGPU powered and real-time, it supports smooth visual effects on mobile devices.

The standard set of core tools to enable hair segmentation in an app:

Already available plugins implementing processings of segmentation masks are compatible with hair segmentation mask by default. Developers can use familiar building blocks to assemble pipelines of visually rich AR effects. ShaderPlugin can be used as a starting point of a custom visual effect on top of hair segmentation mask.

MaskBinaryPlugin applying binarization operation to a segmentation mask. This plugin can be used within mask processing pipeline to filter pixels based on their probability and separate foreground and background pixels by a threshold.

MaskStepPlugin is a similar but more advanced version of the plugin applying smoothstep operation between two thresholds. Compared to more agressive Heaviside step function used in simple binarization, smoothstep provides smooth transition of mask value between foreground and background regions still separating them. We recommend using MaskStepPlugin for smoother visuals.

MaskFilterPlugin performs temporal filtering of a segmentation mask that is based on minimization of entropy in probability space. It can be integrated into a mask post-processing pipeline to decrease temporal noise.

One notable new plugin designed specifically for hair segmentation mask is MaskSharpPlugin. When used in post-processing pipeline of a segmentation mask it significantly improves its accuracy. For example, in case of hair segmentation it can even highlight separate locks of hairs that were missed by a neural network. We recommend to apply a slight spacial smoothing (about 0.5) of a mask before MaskSharpPlugin. If not provided by the Processor temporal smoothing of a segmentation mask can also improve final results. While improvement of mask quality is significant MaskSharpPlugin is really fast and can be used in mobile browsers without sacrificing frames per second.

In this release we reimplemented body patching processing and corresponding plugins. Partial body patching is now not limited in radius of search for the closes body part defined by “patch” and “keep” meshes. This means that no matter how long is the distance between a pixel of a segmentation mask and the closest mesh it’ll be correctly classified as “patch” or “keep” pixel. Moreover this stage of processing is now blazingly fast and processing time doesn’t depend on a search radius. This makes usage of body patching more convenient across all virtual try-on types. Additionally, the same algorithm is applied within patching procedure itself improving it’s performance, quality, and accuracy. The same improvements and changes are applied within full body patching.

On top of that, to improve quality of image processing and overcome floating point precision limits in shaders on mobile devices we implement multi-stage refinement of results of intermediate processing stages. Additionally, memory access pattern is optimized for all GPGPU kernels across Engeenee SDK.

Hand pose detection was optimized to provide more precise and smooth tracking. We’ve implemented totally new approach for wrist detection that provides much more robust and stable results and overcomes major disadvantages of the previous algorithm. New wrist estimation borrows many principles from phalanx refinement procedure introduced in the previous release and bringing promising results. Wrist is approximated by an elliptical cylindroid with subpixel accuracy. New detector has much better performance, it’s at least twice faster, thus virtual try-on of watches and bracelets has gained significant boost in FPS. On top of that, GPGPU kernels of wrist detector were significantly optimized for real-time usage on mobile devices. Wrist detection can be enabled setting corresponding parameter. WristTrackPlugin may be utilized to align scene node with a wrist estimation.

HandAlignPlugin has been considerably reworked. Now we utilize minimization of back-projection error when fitting hand armature in detected keypoints and iteratively converge skeleton in approximated pose to keypoints at the same time preserving relative lengths and scales. We utilized similar approach when aligning a body armature. HandAlignPlugin still requires some work to be 100% ready for virtual try-on of gloves, we are planning to complete implementation within the next release cycle.

This release introduces number of improvements in alignment of armature and detected 3D pose including more natural kinematics, both forward and inverse. We improved fitting of a skeleton into detected points relaxing some hard requirements that when enforced lead to less natural deformations of a mesh. Kinematics of shoulder bones has been reworked to provide less deformations within shoulders and underarms areas. We also fixed rescaling issue near shoulders using the same approach we implemented for limbs in the previous version of the SDK.

Spine curve parameter of ClothAlignPlugin has been fixed and when not specified or set to null | undefined default 1.0 value is used. At the same time 0.0 value is now treated properly and disables curvature recovery. Behaviour of spine bones is also improved to reduce unnatural rescaling.

ImageTexture supports generation of mipmap levels via new convenient API. Mipmaps can considerably improve performance of certain image processing algorithms or visual effect shaders. Number of mipmap levels required to reach 1x1 resolution is evaluated internally. Mipmaps are generated automatically on texture update or upload. ShaderProgram provides an option to opt-in for output texture with auto-generated mipmaps that can be useful when chaining image processing stages.

New read() method of a ShaderProgram copies GPU texture data to the host memory providing access to raw pixel values. Helper TextureReader class provides functionality to get texture data on the client side and use it within image processing pipelines. The important utility provided by TextureReader is non-blocking asynchronous read of texture data using readAsync(). In scenarios where data is not needed immediately or can be accessed with a delay, usage of readAsync() can considerably improve performance as blocking reads stall the whole GPU pipeline and wait until all operations having the texture as a dependency are finished, this in turn significantly decreases performance and utilization of a GPU device. Implementation of readAsync() is thread-safe and correctly handles WebGL state recovery.

Generation of mipmaps and asynchronous read of textures allowed to reimplement BrightnessPlugin and derived LightsPlugin and make them very fast. Now they can be used in rendering pipelines without sacrificing frames per second. Additionally BrightnessPlugin was fine-tuned to react on illumination changes mush faster.

We’ve improved API of video capture setup and made it more flexible. Previously, we had two sets of capture options available. One option is to provide standard MediaStreamConstraints defining set of device capabilities and allowing complete control over selection of a video device. The second option is our simplified VideoParams that provide basic selection of a video device. The main downside was that advanced features like rotation or cropping of the input video streams were available only through VideoParams. To effectively resolve this limitation we’ve merged VideoParams and MediaStreamConstraints options. Now fine-grained specification of the device is available via opts field of VideoParams. This allows for example to request specific deviceId or even focus or white balance modes. Provided MediaStreamConstraints have higher priority than the rest or parameters of VideoParams.

SDK users can provide custom options to underlying babylon.js or three.js renderer when initializing BabylonUniRenderer or ThreeRenderer. This might be useful when more fine-grained control over rendering pipeline or canvas settings are required.

  • Documentation page of Engeenee SDK is now generated by Starlight/Astro.
  • Several fixes where made in saving state of rendering pipeline when WebGL context is shared between several clients.
  • User can provide custom options to underlying babylon.js or three.js renderer when constructing BabylonUniRenderer or ThreeRenderer.
  • Fine-tuning of temporal filter for 2D and 3D pose keypoints.
  • Optimization of memory access in GPGPU kernels with performance improvement.