Anchor points exampleΒΆ

/**
* This example demonstrates how to use AnchorPoint to track
* Ramses scene content in 2D.
*/

struct SceneAndNodes
{
    ramses::Scene* scene;
    ramses::Node* node;
    ramses::PerspectiveCamera* mainCamera;
    ramses::OrthographicCamera* orthoCamera;
};

/**
* Helper method which creates a simple ramses scene. For more ramses
* examples, check the ramses docs at https://bmwcarit.github.io/ramses
*/
SceneAndNodes CreateSceneWithTriangles(ramses::RamsesClient& client, std::array<uint32_t, 2> displaySize);

/**
* Helper to create a simple animation for given node, see animation example for more details on how to create an animation.
*/
void CreateAnimationForNode(rlogic::LogicEngine& logicEngine, const rlogic::RamsesNodeBinding* nodeBinding);

int main()
{
    /**
    * Use simple class to create ramses framework objects which are not essential for this example.
    * For more info on those, please refer to the ramses docs: https://bmwcarit.github.io/ramses
    */
    SimpleRenderer renderer;

    /**
     * Create a simple Ramses scene with 3D mesh (a triangle) and a camera it is rendered with.
     * We will track the 3D mesh using AnchorPoint with the help of a 2D camera that will visualize
     * the tracking.
     */
    auto [scene, node3dToTrack, camera3d, cameraSimulating2d] = CreateSceneWithTriangles(*renderer.getClient(), SimpleRenderer::GetDisplaySize());

    /**
    * Anchor points require feature level 02 or higher
    */
    rlogic::LogicEngine logicEngine{ rlogic::EFeatureLevel_02 };

    /**
    * First we need to create a Ramses Logic representation of the node we will track using Ramses binding.
    */
    rlogic::RamsesNodeBinding* nodeToTrackBinding = logicEngine.createRamsesNodeBinding(*node3dToTrack);

    /**
    * Create a simple animation for the 3D mesh we are about to track, see animation example for more details on how to create an animation.
    */
    CreateAnimationForNode(logicEngine, nodeToTrackBinding);

    /**
    * Show the scene on the renderer
    */
    renderer.showScene(scene->getSceneId());

    /**
    * Create camera binding for the camera that is used for rendering the 3D mesh we want to track
    */
    rlogic::RamsesCameraBinding* camera3dBinding = logicEngine.createRamsesCameraBinding(*camera3d);

    /**
    * Finally create anchor point, we must provide not only the node we want to track but also the camera that is used to render the 3D mesh
    * associated with that node.
    */
    const rlogic::AnchorPoint* anchorPoint = logicEngine.createAnchorPoint(*nodeToTrackBinding, *camera3dBinding);

    /**
     * Simulate an application loop.
     */
    while (!renderer.isWindowClosed())
    {
        /**
        * Update the LogicEngine. This will apply changes to Ramses scene from any running animation.
        */
        logicEngine.update();

        /**
        * In this example we manually extract the 2D coordinates and apply them to the special camera viewport to visualize
        * that the tracking of the 3D mesh (triangle) works. The result will be a white box snapped to origin of the triangle.
        * Alternatively the coordinates can be linked to an another logic node (e.g. LuaScript) to be processed further, perhaps
        * end up transforming another mesh (e.g. text or 2D element).
        */
        const rlogic::vec2f coords = *anchorPoint->getOutputs()->getChild("viewportCoords")->get<rlogic::vec2f>();
        const rlogic::vec2i coords2d{ static_cast<int32_t>(std::lround(coords[0])), static_cast<int32_t>(std::lround(coords[1])) };
        cameraSimulating2d->setViewport(coords2d[0], coords2d[1], cameraSimulating2d->getViewportWidth(), cameraSimulating2d->getViewportHeight());

        /**
        * In order to commit the changes to Ramses scene caused by animations logic we need to "flush" them.
        */
        scene->flush();

        /**
        * Process window events, check if window was closed
        */
        renderer.processEvents();

        /**
        * Throttle the simulation loop by sleeping for a bit.
        */
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }