MeshNodeBinding exampleΒΆ

/**
* This example demonstrates how to use RamsesMeshNodeBinding in a simple scene.
*/

struct SceneAndMesh
{
    ramses::Scene* scene;
    ramses::MeshNode* mesh;
};

/**
* Helper method which creates a simple ramses scene. For more ramses
* examples, check the ramses docs at https://bmwcarit.github.io/ramses
*/
SceneAndMesh CreateSceneWithTriangles(ramses::RamsesClient& client);

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 a simple mesh.
     * We will then apply vertex skinning on this mesh.
     */
    auto [scene, meshNode] = CreateSceneWithTriangles(*renderer.getClient());

    /**
    * Skin binding requires feature level 05 or higher.
    */
    rlogic::LogicEngine logicEngine{ rlogic::EFeatureLevel_05 };

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

    /**
    * Create control script which will output values meaningful for some of the RamsesMeshNodeBinding inputs.
    * This script takes in time ticker and adjusts mesh parameters so that it cycles through up to 3 instances
    * of it also cycles through subsets of vertices to be used to render it.
    */
    rlogic::LuaConfig scriptConfig;
    scriptConfig.addStandardModuleDependency(rlogic::EStandardModule::Math);
    rlogic::LuaScript* controlScript = logicEngine.createLuaScript(R"(
        function interface(IN,OUT)
            IN.ticker = Type:Int64()
            OUT.vertexOffset = Type:Int32()
            OUT.indexCount = Type:Int32()
            OUT.instanceCount = Type:Int32()
        end

        function run(IN,OUT)
            local tickerMs = IN.ticker / 1000
            OUT.vertexOffset = 4 - (math.floor(tickerMs / 333.333333) % 3) * 2
            OUT.indexCount = 8 - OUT.vertexOffset
            OUT.instanceCount = math.floor(tickerMs / 1000) % 3 + 1
        end
    )", scriptConfig);

    /**
    * As mentioned above the control script requires time ticker, here we create it and link it to the script.
    */
    rlogic::TimerNode* timer = logicEngine.createTimerNode();
    logicEngine.link(
        *timer->getOutputs()->getChild("ticker_us"),
        *controlScript->getInputs()->getChild("ticker"));

    /**
    * Finally we create the RamsesMeshNodeBinding which binds to our mesh.
    * Each control script output is linked to the corresponding RamsesMeshNodeBinding's input.
    */
    const auto meshNodeBinding = logicEngine.createRamsesMeshNodeBinding(*meshNode, "meshNodeBinding");
    logicEngine.link(
        *controlScript->getOutputs()->getChild("vertexOffset"),
        *meshNodeBinding->getInputs()->getChild("vertexOffset"));
    logicEngine.link(
        *controlScript->getOutputs()->getChild("indexCount"),
        *meshNodeBinding->getInputs()->getChild("indexCount"));
    logicEngine.link(
        *controlScript->getOutputs()->getChild("instanceCount"),
        *meshNodeBinding->getInputs()->getChild("instanceCount"));
    /**
     * Note that we do not link all the RamsesMeshNodeBinding input properties (e.g. 'indexOffset' is not used here),
     * meaning it will be initialized by Ramses and not modified in any way by Ramses logic.
     */

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

        /**
        * In order to commit the changes to Ramses scene 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));
    }