xeokit / xeokit-sdk

Open source JavaScript SDK for viewing high-detail, full-precision 3D BIM and AEC models in the Web browser.
https://xeokit.io
Other
714 stars 286 forks source link

[QUESTION] Is it possible to rotate an entity in an XKT model within the Viewer? #1193

Open AXONE-IO opened 11 months ago

AXONE-IO commented 11 months ago

I want to animate some Entity in my xkt model. Is there a way of assigning a rotation to a single entity in a model ?

xeolabs commented 10 months ago

Hi,

For XKT, we are limited to being able to translate and rotate the entire model, or just translate the individual objects along the coordinate axis (useful for exploding parts views). Explanation below:

We have two ways to represent model in xeokit:

  1. the SceneModel class, which is a container of geometries, meshes, materials and entities, that only allows you to rotate and translate the whole SceneModel, and to translate the individual entities along the coordinate axis
  2. the "scene graph", which is a structure of Node, Mesh, Material and Geometry classes, where Meshes are the entities, which allows us to rotate, translate and scale each entity independently.

We use (1) for big models. Transformation is limited in (1) in order to optimize it for minimal memory usage, and make it render as fast as possible.

We use (2) for 3D helper objects, like NavCube, section plane controls etc, which only use a small number of these components, and for which it's efficient to then support full transformations.

(1) is much more efficient than (2), which should only be used for simple 3D objects/models.

Here are our collection of usage examples for (2):

https://xeokit.github.io/xeokit-sdk/examples/scenegraph/

And a live demo of (2):

https://xeokit.github.io/xeokit-sdk/examples/scenegraph/#sceneGraph

Screencast from 26.10.2023 12:00:21.webm

Source code for that live demo - note that Node classes are branch nodes in the scene graph, with Mesh classes at the leaves. Meshes can share materials and geometries between them.

    import {Viewer, Mesh, Node, PhongMaterial, buildBoxGeometry, ReadableGeometry} from "../../dist/xeokit-sdk.min.es.js";

    //------------------------------------------------------------------------------------------------------------------
    // Create a Viewer and arrange the camera
    //------------------------------------------------------------------------------------------------------------------

    const viewer = new Viewer({
        canvasId: "myCanvas",
        transparent: true
    });

    viewer.scene.camera.eye = [-21.80, 4.01, 6.56];
    viewer.scene.camera.look = [0, -5.75, 0];
    viewer.scene.camera.up = [0.37, 0.91, -0.11];

    //------------------------------------------------------------------------------------------------------------------
    // Build a simple scene graph representing a table with four legs
    //------------------------------------------------------------------------------------------------------------------

    const boxGeometry = new ReadableGeometry(viewer.scene, buildBoxGeometry({
        xSize: 1,
        ySize: 1,
        zSize: 1
    }));

    new Node(viewer.scene, {
        id: "table",
        isModel: true, // <--------------------- Node represents a model
        rotation: [0, 50, 0],
        position: [0, 0, 0],
        scale: [1, 1, 1],

        children: [

            new Mesh(viewer.scene, { // Red table leg
                id: "redLeg",
                isObject: true, // <---------- Node represents an object
                position: [-4, -6, -4],
                scale: [1, 3, 1],
                rotation: [0, 0, 0],
                geometry: boxGeometry,
                material: new PhongMaterial(viewer.scene, {
                    diffuse: [1, 0.3, 0.3]
                })
            }),

            new Mesh(viewer.scene, { // Green table leg
                id: "greenLeg",
                isObject: true, // <---------- Node represents an object
                position: [4, -6, -4],
                scale: [1, 3, 1],
                rotation: [0, 0, 0],
                geometry: boxGeometry,
                material: new PhongMaterial(viewer.scene, {
                    diffuse: [0.3, 1.0, 0.3]
                })
            }),

            new Mesh(viewer.scene, {// Blue table leg
                id: "blueLeg",
                isObject: true, // <---------- Node represents an object
                position: [4, -6, 4],
                scale: [1, 3, 1],
                rotation: [0, 0, 0],
                geometry: boxGeometry,
                material: new PhongMaterial(viewer.scene, {
                    diffuse: [0.3, 0.3, 1.0]
                })
            }),

            new Mesh(viewer.scene, {  // Yellow table leg
                id: "yellowLeg",
                isObject: true, // <---------- Node represents an object
                position: [-4, -6, 4],
                scale: [1, 3, 1],
                rotation: [0, 0, 0],
                geometry: boxGeometry,
                material: new PhongMaterial(viewer.scene, {
                    diffuse: [1.0, 1.0, 0.0]
                })
            }),

            new Mesh(viewer.scene, { // Purple table top
                id: "tableTop",
                isObject: true, // <---------- Node represents an object
                position: [0, -3, 0],
                scale: [6, 0.5, 6],
                rotation: [0, 0, 0],
                geometry: boxGeometry,
                material: new PhongMaterial(viewer.scene, {
                    diffuse: [1.0, 0.3, 1.0]
                })
            })
        ]
    });

    //------------------------------------------------------------------------------------------------------------------
    // Find scene graph nodes by their model and object IDs
    //------------------------------------------------------------------------------------------------------------------

    // Get the whole table model
    var table = viewer.scene.models["table"];

    table.edges = true;

    // Get some leg objects
    var redLeg = viewer.scene.objects["redLeg"];
    var greenLeg = viewer.scene.objects["greenLeg"];
    var blueLeg = viewer.scene.objects["blueLeg"];

    //------------------------------------------------------------------------------------------------------------------
    // Periodically update transforms on our scene nodes
    //------------------------------------------------------------------------------------------------------------------

    viewer.scene.on("tick", function () {

        // Rotate legs
        redLeg.rotateY(0.5);
        greenLeg.rotateY(0.5);
        blueLeg.rotateY(0.5);

        // Rotate table
        table.rotateY(0.5);
        table.rotateX(0.3);
    });
AXONE-IO commented 10 months ago

To put this in context, we're using the viewer to visualize industrial 3d models. Being able to apply rotations would make it possible to animate, bring to life the model and even reproduce the state of the machines like a digital twin.

Thank you for your explanations.