Amerio.Stephane Posted May 11 Posted May 11 (edited) Hello, I'm trying to spawn a node when receiving a CIGI ComponentCtrl. In my on_receive callback, I simply do this: auto node = ig->loadNode(path); node->setWorldPosition(100,100,100); // anything but 0 0 0 node->setWorldRotation(q); // same But the node is always placed at the world origin, disregarding the coordinates I gave. If I use World::loadNode() instead it works as expected. Am I doing something wrong here (2.21.0.2)? Pretty sure this used to work in previous versions. EDIT: hum no, this was also broken and I had to use some workaround. Bonus question: can you confirm I should use ig->synckerDestroy() to remove the node? Edited May 11 by Amerio.Stephane
silent Posted May 12 Posted May 12 Hi Stephane, You can try to load node with the pre-defined position and rotation via syncker->loadNode(): auto transform = Mat4(quat(vec3(0, 0, 1), 45.f), Vec3(10, 10, 10)); auto *master = ig->getSynckerMaster(); if (master) { auto node = syncker->loadNode("Box.node", ~0, transform); } else { auto node = World::loadNode("Box.node"); node->setWorldTransform(transform); } The root cause of this behavior is in the interpolation logic, you can easily check with: if (auto *syncker = ig->getSyncker()) syncker->setInterpolation(false); auto node = ig->loadNode("Box.node"); node->setWorldPosition(Vec3(10, 10, 10)); node->setWorldRotation(quat(vec3(0, 0, 1), 45.f)); In that case node will be positioned and rotated correctly. However, there is no easy way to make your initial code to work with interpolation correctly, that's why you have to use a dedicated method with overload that will apply transform correctly. Quote Bonus question: can you confirm I should use ig->synckerDestroy() to remove the node? Yes, that's correct. Also, if you are using Master::loadNode(), you need to delete it via Master::deleteNode(). Basically the synckerDestroy is just a fancy way of doing that for you: void Manager::synckerDestroy(const NodePtr &in_node) { if (!in_node) return; if (syncker_master) syncker_master->deleteNode(in_node); else deleteNode(in_node, false); } Thank you! How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN
Amerio.Stephane Posted May 12 Author Posted May 12 Understood. But, from my point of view - not knowing all in and outs - it feels like there is some API complexification that could be removed: Is there a reason why you simply not merge syncker and IG API into one and simplify the duplication ? Like, why should one use ig->loadNode() when syncker->loadNode() seems do be more complete? Same for ig->deleteNode(), and maybe others? (probably some legacy code or organic evolution , sure, but is there any _real_application_ reasons for this that I'm missing?) Just for info: this lead us to always import the Syncker plugin, whether we are running in standalone or not, just because of the API mix.
silent Posted May 13 Posted May 13 Hi Stephane, There are some use cases where you only need Syncker, not IG, which is why we keep both plugins. Some IG methods related to node synchronization use Syncker internally because that code has already been verified in production. It was also simpler to write small API wrappers around it than to duplicate the same code in multiple places. They may be completely separated in the future, but at this point, we are not planning any major changes in that area. Thank you! How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN
Recommended Posts