SceneKit, SpriteKit, who cares?
Bonsoir,
Est-ce un effet de mon imagination ou SceneKit/SpriteKit n'a pas vraiment déclenché un vaste mouvement d'enthousiasme? Je constate une indigence assez prononcée sur les sites et forums lorsque je cherche la réponse à certaines questions...
Par exemple, les SCNNodes ont l'air d'être assez "fermés". Nulle part il n'est fait mention de créer des classes dérivées -- et d'ailleurs comment dériver?
Pour créer un SCNNode, il existe trois méthodes : node, new et initWithGeometry. J'ai donc fait quelque chose du style:
MyNode* myNode = [[MyNode node] initWithMyParameters: ...];
Soit l'équivalent d'un [[[MyNode alloc] init] initWithMyParameters...] ce qui me paraà®t boiteux. En fait, il ne semble pas y avoir d'initialiseur d'instance, seulement des méthodes de classe. Dans ces circonstances, comment dériver, ou même créer une hiérarchie, comme dans SpriteKit (qui est bien plus pratique à ce niveau-là ). Imaginons quelque chose du style:
MassNode -- StarNode
\-- PlanetNode
\-- RingNode
\-- ArtifactNode -- ShipNode
\-- MineNode
Comment faire ? Google is not my friend dans ce cas-là . Quant à la doc, mieux vaut parler d'autre chose...
Réponses
Normalement tu ne charge pas toute une scène à la main, tu part d'un fichier DAE pour ça.
Tu as regardé les samples code de cette WWDC ?
@Ali : OK je vais lire tout ça
@yoann : Parlons-en du .dae. J'ai essayé d'exporter en format COLLADA depuis deux logiciels 3D, en l'occurrence Poser 2012 et Lightwave 11.5, résultat rien n'apparait dans la fenêtre IB prévue pour ça – ok je récupère les objets, les textures, la caméra et les lumières, mais la fenêtre reste d'un beau gris maladif...
@Any : Je reste quand même assez surpris de voir deux frameworks sortis des mêmes mains présenter tant de différences structurelles. Par exemple, dans SpriteKit, chaque SKNode maintient une liaison avec la scène dans laquelle il est inséré (super pratique) et il est possible d'éliminer tous les descendants d'un node d'un seul coup (removeAllChildren). Sans parler de la dérivation qui est hyper facile de mettre en place.
Rien de tel dans SceneKit.
Je me demande s'ils n'ont pas mis dans SpriteKit toutes les bonnes idées qu'ils ont loupées dans SceneKit...
Tu sais ce n'est pas forcément les mêmes équipes qui bossent sur les deux framework. Donc pas les mêmes main.
Concernant ton problème avec le DAE, est-ce que déjà QuickLook ou Aperçu arrivent à lire ton fichier ? Tu as peut être un problème dans tes options d'exports.
Au passage, pour que tu puisse utiliser tes objets issue du fichier DAE il faut qu'ils soient nommés.
Ah j'avais loupé ça. C'est vrai que Lightwave ne nomme pas ses éléments... J'essaie ça dès que je reviens sur mon MacPro.
Autre truc étrange: la notion de caméra et de point de vue sont dissociées. L'idée de faire d'une caméra le child de quel objet, au lieu, par exemple, de pouvoir associer la caméra à un objet, c'est bizarre. Une caméra pourrait avoir une @property *target par exemple.
Et comment faire pour aligner une SCNPlane sur le point de vue, comme on peut le faire dans un programme 3D pour éviter de créer un volume? Je n'ai pas trouvé le moyen: L'exemple donné par les slides du WWDC tient de l'arnaque pure: ils alignent manuellement le plane vers une caméra fixe...
L'autre possibilité est que je m'y prends mal ou que j'ai loupé un truc, mais en fait je ne serais pas autrement surpris qu'on voie surgir un jour un github "MagicalDirector" ou quelque chose du même cru...
Dans SceneKit (si j'ai bien compris) tout est associé à un node (forme, lumière, caméra...).
Si tu veut que l'un de tes objets suivent un autre (que ce soit une caméra, une source de lumière, ou n'importe quelle forme qui pointe vers une autre), tu utilise SCNLookAtConstraint.
ça me semble assez simple comme principe. Qu'est-ce qui te pose problème ?
Oui, ça marche – si allowsCameraControl = NO et qu'on déplace le node Camera à l'aide, par exemple, des flèches de navigation. Mais si allowsCameraControl = YES, alors c'est fichu, puisque le pointOfView est dissocié de la caméra...
De ce que j'en ai compris toujours, allowsCameraControl est plus là pour des opérations simple et du debug. C'est assez basique. Ce n'est pas fait pour que être le système de déplacement d'un jeu vidéo par exemple. C'est plus pour se balader dans ta maison en 3D je crois.
Pour des opérations avancés comme pouvoir déplacer la caméra tout en suivant un objet, tu met allowsCameraControl à NO et tu fait toi même ta gestion des commandes et du mouvement, pour que ça corresponde effectivement à ce que tu cherche.
Tu as regardé la session de cette année sur faire un jeu vidéo avec SceneKit ?
La fin montre un jeu de voiture avec une caméra qui suit la voiture en mouvement. Il me semble qu'ils disent comment ils ont fait.
SceneKit et SpriteKit ont une API assez proche mais il y effectivement une difference dans la maniere d'utiliser les nodes.
les SKNode sont fait pour etre sous-classé (pour customiser le rendu et les behaviors) alors qu'il est rarement utile de sous classer un SCNNode.
Je vois 3 inconvénients dans l'approche par surcharge:
1) Comme le dit Yoann, les scene 3D sont souvent des hierarchies de nodes assez complexe, loadé à partir de fichier 3D. Donc lorsqu'on load une scene 3D, SceneKit va instancier plein de SCNNode ce qui se marie assez mal avec le fait de sous-classer (a moins de laisser le developer fournir une “factory†de node a SceneKit au loading de la scene mais ca devient compliqué et pas efficace).
2) l'archiving: quand on serialize une scene (via NSCoding/NSSecureCoding) s'il n'y a pas de classe custom alors elle peut etre reloader par n'importe qui (alors que ca crachera s'il manque une classe). Ca simplifie l'échange de scene et si un jour quelqu'un fait un scenekit scene editor il pourra éditer les scenes de tout le monde.
3) Laisser les developers customiser le rendu/behavior casse le model simplement “déclaratif†et pose en autres des problèmes de performance. Si une scene est entièrement décrite de manière descriptive (des nodes, des attributes, des contraintes etc...) alors SceneKit peut faire des optimisations comme par exemple ordonnancer le rendu des objets pour minimiser les changements d'état du GPU. Si les nodes peuvent faire importe quoi, alors scenekit devra s'assurer de reseter le GPU avant d'appeler le rendu de ces nodes, puis re-reseter une fois le rendu custom terminé (parce qu'on ne sais pas ce que peut faire un développer dans une méthode surchargé).
SceneKit laisse cependant la liberté de customiser le rendu d'un node en lui assignant un delegate.
Aussi il est possible de sous classer un SCNNode si nécessaire. Peu importe le constructeur utilisé. Par exemple:
MyNode *node = [MyNode node]; fera ce qui est attendu. (les constructeurs sont déclaré comme retournant “instancetype†ce qui veut dire que l'instance retourné sera du type spécifié).
Si le but est simplement “d'associer†du storage a un node en particulier, pas la peine de sous classer, il suffit de faire:
[myNode setValue:someValue forKey:myKey];
Apres c'est une question de gout mais je trouve que l'approche “declarative†est plus moderne et en general meilleur que l'approche par sous classe (par exemple le rendu et behavior d'AppKit utilisent beaucoup la surcharge alors qu'UIKit utilise plus l'approche declarative)
“SKNode maintient une liaison avec la scène dans laquelle il est inséréâ€
-> ca peut faire une bonne “enhancement request†pour Apple -> file a bug?
“il est possible d'éliminer tous les descendants d'un node d'un seul coup (removeAllChildren)â€
-> C'est peut etre une bonne convenience en effet. Cela dit il est aussi facile de faire sa category sur SCNNode pour ce genre de méthode (je ne crois pas qu'il y ai removeAllSubviews sur NSView).
Pour le problème de loading de fichier exporté par Poser et Lightwave il serait très intéressant de filer un bug. Est ce que ces fichiers sont ouvert par preview / quicklook ?
“résultat rien n'apparait dans la fenêtre IB prévue pour ça – ok je récupère les objets, les textures, la caméra et les lumières, mais la fenêtre reste d'un beau gris maladif...â€
-> un problème classique est le “z-range†de la camera (near et far dans le camera inspector). les éditeurs 3D n'en tiennent en general pas compte dans leur viewport donc le model est visible, mais le model exporté est en fait clippé par les near et far planes de la camera
Merci toyos2 pour ces explications fort intéressantes! Donc quelque chose comme ça:
est parfaitement légal ?
Pour préciser un peu mes besoins, je m'amuse pour l'instant à créer des systèmes solaires, un peu dans le genre de "Exoplanet", l'application iOS. Rien de plus simple à créer par code, je me sers d'une plist pour définir la hiérarchie Etoile-Planètes-Satellites et je crée mes SCNNodes à la bonne distance, je les fais pivoter en fonction de la loi de Kepler, j'ajoute une géométrie sphérique aux bonnes dimensions, j'applique la bonne texture, je peux même créer des anneaux (bon, OK, l'ombre de la planète ne se projette pas sur l'anneau mais c'est parce que seules les lampes "spot" projettent une ombre et je me vois mal équiper mon système d'un soleil "spot"...
Restent quand même des choses à régler: l'axe de rotation de la planète est toujours vertical (je ne vois pas comment définir l'obliquité) et surtout l'orbite (circulaire) est pour l'instant indiquée par un tore (ça marche mais j'aurais souhaité une épaisseur de trait constante quelle que soit la distance de la caméra...
Pour l'épaisseur du trait j'ai ajouté un commentaire sur stackoverflow: http://stackoverflow.com/questions/24760902/scenekit-how-to-draw-an-orbit-trail/24785820#24785820
Pour ce qui est de l'axe de rotation: pour se simplifier la vie avec les maths, le plus simple est souvent d'ajouter un node intermédiaire. Ca donne un node qui tourne pour faire l'orbit ou la rotation de la planete, et un parent node avec une certaine rotation pour faire tourner l'orbit ou l'axe de rotation de la planete.
A noter qu'il y a 2 model de rotation disponible pour les SCNNode: eulerAngles (euler based rotation) et rotation (vector4 axis angle). Le dernier est peut etre mieux adapté a une simulation de planète.
@toyos : Tu dois posséder un bagage mathématique que je suis loin d'avoir... Je crois n'avoir jamais croisé de calcul matriciel de ma vie. "Ou alors y a longtemps. Ou bien j'ai oublié" comme chantait l'autre.
Je pratique les nodes intermédiaires (en fait chaque objet a trois nodes selon la hiérarchie pivotPoint (child de l'attracteur) - node principal - representationNode (avec la géométrie sphérique). C'est ce dernier que j'ai essayé d'incliner, mais je récolte une rotation en fait, et non une inclinaison de l'axe de rotation...
De plus, conformément à la réalité, cette inclinaison de l'axe de rotation doit être constante, et la direction de l'axe aussi (voir schéma ci-dessous). Cela doit être réalisable, mais je ne sais pas comment...
... C'est faux. La propriété orientation n'est pas disponible sous 10.9.
Oui on nous l'a deja fais remonter (ainsi que la classe SCNParticleSystem). Ce sera fixé dans la beta4 \o/
Voilà ce que ça donnera sous Yosemite... Encore quelques réglages et j'aurais de chouettes protubérances solaires
Pour la rotation: le schema explique bien le problème merci et c'est effectivement pas hyper simple. Je pense que j'essairais de le faire en faisant tourner l'axe de rotation à la meme vitesse que la rotation autour de l'obit mais dans le sens inverse.
Ou sinon, ne pas faire tourner autour de l'orbit en faisant tourner un parentNode au centre de l'orbit, mais sans aucune hierarchie et en déplaçant le node a chaque frame selon un sin/cos (t) (les update a chaque frames sont a faire la methode "update" du SCNView delegate).
En fait c'est pas tellement un pb de 3D, ca serait aussi compliqué en 2D finalement.
@toyos2
Je profite d'un des trop rares spécialistes de Scene Kit pour poser une question supplémentaire:
J'ai une sorte de "browser" à systèmes solaires, ce qui veut dire que je crée à chaque nouveau système l'étoile et ses planètes, ce qui peut représenter un joli paquet de nodes si je décide d'adjoindre les satellites de chaque planète.
Je pense utiliser une "layer" propres à ces corps stellaires (et dans un autre la caméra). Maintenant, quand on change de système, il me faut me débarrasser des nodes inutiles. Comment faire? Je veux bien implémenter une méthode de convenance "removeAllChildren", la question est : que reviennent les nodes retirés de la hiérarchie parentale? Dois-je faire cela sous forme d'une méthode récursive:
... et surtout comment se débarrasser d'un node?
Je conçois que SceneKit soit conçu pour bien découpler la partie code de la partie artistique (d'où la grande facilité d'importer un .dae " fonctionnel, pas comme les miens). Mais même ainsi, il doit y avoir des nodes qui deviennent inutiles ou que l'on doit ajouter au .dae... imaginons un personnage qui expédie des boules de feu sur des gnomes malfaisants: une fois le gnome atteint, que devient-il, ainsi que le projectile? Les nodes doivent-ils être "recyclés" (rendus invisibles et gardés en réserve pour un emploi ultérieur " les gnomes se ressemblent tous, de toute manière)? Ou peut-on les éliminer de la hiérarchie, et surtout de la mémoire?
il suffit de retirer le node de la hierarchie ([node removeFromParentNode]). Ensuite s'il n'y a plus aucune reference (ou si plus rien ne retain le node en retain/release manuel) le node sera desaloué ainsi que tous ses childs et tous les attributes attaché.
Merci toyos2! C'est exactement ce que j'ai fait... mais je peux te dire que j'ai fait un Profile à la recherche des leaks... et effectivement, aucune fuite détectée. ^_^
Donc... je le tiens mon "removeAllChildren": même pas la peine de rajouter une catégorie à SCNNode! Et merci également pour le rappel du KeyValueCoding " à force de dériver et de flanquer des propriétés partout, j'en oublie ce protocole...
Rassuré par tout cela, j'ai suivi ton conseil (d'après ce que je crois avoir compris de la "programmation déclarative", terme que j'ai googlé sans résultat probant) " à savoir éviter de dériver. Mes SCNNodes sont tous "d'usine"... et la hiérarchie créée ainsi pourra même être stockée dans un document.
Mille mercis !
P.S. Je me trompe ou tes renseignements sont de première main? Ta photo sur Stack Overflow ressemble à s'y méprendre à certaines utilisées dans les démos de la WWDC... -_-
héhé, on ne peut rien te cacher