Fonction de distance signée (SDF)
Les champs de distance signés (SDF) permettent de décrire une géométrie 3D simple (comme des sphères, des cubes, des capsules et des plans) à l'aide d'une fonction de distance plutôt qu'à l'aide de maillages. Dans notre pile haptique, un SDF devient un champ de force que l'on peut associer à une session de périphérique : lorsque le curseur s'approche (ou pénètre) dans la forme, le système génère une force normale dont l'intensité dépend de la distance, de la portée et de l'accélération.
Cette page présente l'interface API publique ajoutée ou mise à jour par le correctif : la charge utile de l'effet SDF Haptics, les formes prises en charge, les paramètres, ainsi que des exemples de requêtes et de réponses pour la création, la mise à jour, la liste et la suppression d'effets SDF.
Modèle conceptuel
Un effet SDF est :
- A forme (par exemple,
sphere,box,capsule,plane) - Une transformation (position, rotation et échelle de l'effet dans l'espace)
- A objet paramètre (
params) qui permet de configurer la forme sélectionnée (rayons, extrémités, dimensions, normales, etc.) - Commandes de force :
force_scale— coefficient multiplicateur globalrange— épaisseur de la « bande active » à l'extérieur de la surface où les forces s'atténuent jusqu'à zéroease+reverse_easing— comment la force augmente en fonction de la distance
- Commandes de composition :
symmetry— la manière dont la distinction entre l'intérieur et l'extérieur est abordéeblend— comment les effets multiples des SDF se combinent
Vous pouvez créer plusieurs effets SDF par appareil ; chaque effet possède un id.
Effet SDF
{
"id": "string",
"transform": {
/* transform object */
},
"shape": "sphere | box | rounded_box | capsule | capsule_vertical | capped_cylinder | capped_cylinder_vertical | plane",
"params": {
/* shape parameters */
},
"force_scale": 1.0,
"range": 1.0,
"ease": "linear",
"reverse_easing": false,
"symmetry": "single | mirror | align",
"blend": "additive"
}
Référence sur le terrain
| Champ d'application | Type | Obligatoire | Signification |
|---|---|---|---|
id | chaîne de caractères | ✅ | Identifiant unique de cet effet au sein d'un appareil. |
transform | objet | ✅ | Position de l'effet dans l'espace mondial/de l'appareil. |
shape | chaîne de caractères | ✅ | La primitive SDF à évaluer. |
params | objet | ✅ | Paramètres spécifiques à la forme (voir ci-dessous). |
force_scale | nombre | ⛔ | Multiplie l'amplitude de la force finale. Valeur par défaut : 1.0. |
range | nombre | ⛔ | Distance en dehors de la surface (en mètres) où l'effet est actif. Par défaut : 1.0. |
ease | chaîne de caractères | ⛔ | Courbe d'atténuation appliquée sur [0..range]. Par défaut : linear. |
reverse_easing | booléen | ⛔ | Si cette option est activée, elle inverse le sens de l'accélération. Par défaut : false. |
symmetry | chaîne de caractères | ⛔ | Comment le paramètre « inside/outside » est géré (voir ci-dessous). Par défaut : single. |
blend | chaîne de caractères | ⛔ | Comment les effets multiples des SDF se combinent. Par défaut : additive. |
Formes et paramètres
Toutes les formes sont configurées via un seul params objet. Vous pouvez fournir uniquement les champs dont vous avez besoin pour la forme sélectionnée.
params objet
{
"r": 1.0,
"h": 0.0,
"a": [0.0, 0.0, 0.0],
"b": [0.0, 0.0, 0.0],
"n": [0.0, 1.0, 0.0]
}
Conseil : les valeurs sont interprétées dans l'effet espace local (après avoir appliqué
transform).
Formes prises en charge (actuellement)
Seules les primitives SDF suivantes sont actuellement prises en charge (voir la galerie SDF d'IQ pour plus d'informations mathématiques) :
| Forme | shape valeur | Paramètres utilisés |
|---|---|---|
| Sphère | sphere | r |
| Boîte | box | b (demi-feuilles) |
| Boîte arrondie | rounded_box | b (demi-feuilles), r (rayon de courbure) |
| Capsule (segment) | capsule | a, b, r |
| Capsule (verticale) | capsule_vertical | h, r |
| Cylindre à capuchon (segment) | capped_cylinder | a, b, r |
| Cylindre à couvercle (vertical) | capped_cylinder_vertical | h, r |
| Avion | plane | n, h |
Remarques sur les conventions
- Vecteurs sont des tableaux :
a,b,nsont en 3D ([x,y,z]). - Boîte utilisations
bsous forme de demi-intervalles (par exemple,b=[0.1,0.2,0.1]). - Avion utilisations
ncomme la norme ethdécalé le long de la normale. - Vertical utilisation des variantes
hcomme une demi-hauteur (capsule/cylindre centré sur l'origine le long de l'axe Y local).
Symétrie
symmetry détermine le comportement du champ par rapport à la surface :
single— Comportement par défaut. La distinction entre l'intérieur et l'extérieur est conservée.mirror— Utilise la distance absolue par rapport à la surface et inverse la direction lorsqu'il se trouve « derrière » celle-ci, créant ainsi un effet de miroir.align— Utilise la distance absolue sans inverser le sens (utile pour les effets du type « toujours pousser dans la même direction »).
Modulation et gamme
L'intensité de la force augmente avec la distance par rapport à la surface :
- En surface (distance =
0) : amplitude maximale (sous réserve d'un assouplissement) - À distance =
range: l'amplitude devient0(inactif)
ease définit la courbe de l'atténuation. reverse_easing inverse la courbe.
Commandes
"set_sdf": créer/mettre à jour des effets SDF localisés (tableau d'éléments)"remove_sdf": supprimer les effets par ID (tableau d'ID)
Définir / Mettre à jour l'effet SDF
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_sdf": [
{
"id": "boundary_049D",
"transform": {
"position": {
"x": 0,
"y": -0.05,
"z": -0.04
},
"rotation": {
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"scale": {
"x": 0.15,
"y": 0.1,
"z": 0.1
}
},
"shape": "sphere",
"force_scale": -2.0,
"range": 0.1,
"ease": "cubicInOut",
"reverse_easing": false,
"symmetry": "single",
"blend": "additive",
"params": {
"r": 1.0
}
}
]
}
}
]
}
Supprimer un effet SDF
{
"inverse3": [{
"device_id": "049D",
"commands": {
"remove_sdf": ["boundary_049D"]
}
}]
}
- Chaque identifiant présent dans le tableau est supprimé.
- La suppression d'un identifiant inexistant est considérée comme une opération sans effet (on peut l'appeler sans risque).
API REST
Les points de terminaison SDF respectent les mêmes conventions de routage par session/appareil que le reste de l'API haptique.
- Un appareil peut comporter plusieurs effets SDF.
- Chaque effet est identifié par son
id.- Vous pouvez gérer les effets individuellement ou en bloc pour chaque appareil.
Itinéraires
-
OBTENIR
/{device_type}/{device_id}/sdf?session_id=<sid>→ Portée de l'appareil (liste des SDF)/{device_type}/{device_id}/sdf/{hfx_id}?session_id=<sid>→ SDF simple/{device_type}/*/sdf?session_id=<sid>→ Portée de la session (tous les appareils)/{device_type}/*/sdf(nonsession_id) → toutes les sessions
-
PUBLICATION
/{device_type}/{device_id}/sdf/{hfx_id}?session_id=<sid>corps :sdf_hfx(en créer/mettre à jour un)/{device_type}/{device_id}/sdf?session_id=<sid>corps :device_sdf_dto(remplacer ou mettre à jour/ajouter plusieurs éléments pour l'appareil)
-
SUPPRIMER
/{device_type}/{device_id}/sdf?session_id=<sid>ou.../sdf/{hfx_id}?session_id=<sid>session_id=*Prise en charge de la fonction « Tout effacer ».
Les gestionnaires vérifient device_type (inverse3 (uniquement), appliquer session_id/device_id présence et retour 404 en cas d'absence de session, d'appareil ou d'effet.
Points forts en matière de comportement
- Le routage GET couvre : tout → session → périphérique → effet unique en fonction du chemin et des paramètres.
- La méthode POST impose l'utilisation d'un chemin d'accès et d'un corps de requête
idgarantit la cohérence pour les écritures à effet unique et met à jour les SDF au niveau du périphérique lors de la publication d'une liste. - La commande DELETE est idempotente et renvoie une réponse standard indiquant que l'opération s'est bien déroulée, même si rien n'a été supprimé
Exemples
Une « bulle » sphérique sur laquelle on peut appuyer
{
"id": "bubble",
"transform": {
/* place it where you want */
},
"shape": "sphere",
"params": {
"r": 0.12
},
"force_scale": 1.0,
"range": 0.08,
"ease": "linear",
"reverse_easing": false,
"symmetry": "single",
"blend": "additive"
}
Boîte arrondie « à parois souples »
{
"id": "soft_wall",
"transform": {
/* oriented wall */
},
"shape": "rounded_box",
"params": {
"b": [
0.30,
0.02,
0.30
],
"r": 0.01
},
"force_scale": 0.9,
"range": 0.06,
"ease": "cubicInOut",
"reverse_easing": false,
"symmetry": "single",
"blend": "additive"
}
Segment de capsule « rail »
{
"id": "rail",
"transform": {
/* position/rotate rail */
},
"shape": "capsule",
"params": {
"a": [
-0.15,
0.0,
0.0
],
"b": [
0.15,
0.0,
0.0
],
"r": 0.015
},
"force_scale": 0.7,
"range": 0.05,
"ease": "quadraticOut",
"reverse_easing": false,
"symmetry": "mirror",
"blend": "additive"
}
Plan « limite invisible »
{
"id": "boundary",
"transform": {
/* place plane */
},
"shape": "plane",
"params": {
"n": [
1.0,
0.0,
0.0
],
"h": 0.0
},
"force_scale": 0.8,
"range": 0.10,
"ease": "linear",
"reverse_easing": false,
"symmetry": "single",
"blend": "additive"
}