Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Movable SceneModel Objects #1229

Merged
merged 14 commits into from
Nov 20, 2023

Conversation

xeolabs
Copy link
Member

@xeolabs xeolabs commented Nov 14, 2023

New Classes

This PR extends xeokit's high-performance SceneModel model representation with dynamic transform hierarchies.

SceneModelMesh

  • Binds a geometry and transform to a single SceneModelEntity
  • A SceneModelEntity can have multiple SceneModelMeshes
  • Created by SceneModel#createMesh
  • Stored in SceneModel#meshes
  • Referenced by SceneModelEntity#meshes

SceneModelTransform

  • Dynamic transform that can be animated
  • Can be connected into hierarchies
  • Created by SceneModel#createTransform
  • Stored in SceneModel#transforms
  • Referenced by SceneModelMesh#transform

Caveats

Precision Limts

When a SceneModelMesh has an origin, then the translation of its SceneModelTransform will be relative to that origin. For coordinate accuracy, the translation distance must be less than the maximum magnitude expressible by a single-precision floating-point number. If the translation is too large, then rounding jitter may result when rendering.

Use SceneModel.position if you need to move a SceneModel long distances within xeokit's World coordinate system. That property can handle double-precision magnitudes.

Usage

The following example shows how to create a SceneModel that allows us to dynamically animate the position, size and orientation of its objects.

Instead of defining a translation, scale and rotation of each mesh, we define these on SceneModelTransform components, which are connected to the meshes. We'll also organize our SceneModelTransform components into a hierarchy.

//------------------------------------------------------------------------------------------------------------------
// Build a SceneModel representing a table with four legs, 
// using geometry instancing and transforms
//------------------------------------------------------------------------------------------------------------------

const sceneModel = new SceneModel(viewer.scene, {
    id: "table",
    isModel: true, // <--------------------- Represents a model, registers SceneModel by ID on viewer.scene.models
    position: [0, 0, 0],
    scale: [1, 1, 1],
    rotation: [0, 0, 0],
    edges: true,
    dtxEnabled: true
});

//--------------------------------------------------------
// Create a reusable geometry within the SceneModel
// We'll instance this geometry by five meshes
//--------------------------------------------------------

sceneModel.createGeometry({

    id: "boxGeometry",

    // The primitive type - allowed values are "points", "lines" and "triangles".
    // See the OpenGL/WebGL specification docs for how the coordinate arrays are supposed to be laid out.
    primitive: "triangles",

    // The vertices - eight for our cube, each
    // one spanning three array elements for X,Y and Z
    positions: [
        1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // v0-v1-v2-v3 front
        1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // v0-v3-v4-v1 right
        1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // v0-v1-v6-v1 top
        -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // v1-v6-v7-v2 left
        -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, // v7-v4-v3-v2 bottom
        1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 // v4-v7-v6-v1 back
    ],

    // Indices - these organise the positions and and normals
    // into geometric primitives in accordance with the "primitive" parameter,
    // in this case a set of three indices for each triangle.
    //
    // Note that each triangle is specified in counter-clockwise winding order.
    //
    indices: [
        0, 1, 2, 0, 2, 3, // front
        4, 5, 6, 4, 6, 7, // right
        8, 9, 10, 8, 10, 11, // top
        12, 13, 14, 12, 14, 15, // left
        16, 17, 18, 16, 18, 19, // bottom
        20, 21, 22, 20, 22, 23
    ]
});

sceneModel.createTransform({
    id: "tableTransform",
    position: [-100,0, 100],
    scale: [1, 1, 1],
    rotation: [0, 45, 0]
});

//--------------------------------------------------------
// Red table leg object
//--------------------------------------------------------

sceneModel.createTransform({
    id: "redLegTransform",
    parentTransformId: "tableTransform",
    position: [-4, -6, -4],
    scale: [1, 3, 1],
    rotation: [0, 0, 0]
});

sceneModel.createMesh({
    id: "redLegMesh",
    geometryId: "boxGeometry",
    transformId: "redLegTransform",
    color: [1, 0.3, 0.3]
});

sceneModel.createEntity({
    id: "redLeg",
    meshIds: ["redLegMesh"],
    isObject: true // <----------------- Represents an object, registers Entity by ID on viewer.scene.objects
});

//--------------------------------------------------------
// Green table leg object
//--------------------------------------------------------

sceneModel.createTransform({
    id: "greenLegTransform",
    parentTransformId: "tableTransform",
    position: [4, -6, -4],
    scale: [1, 3, 1],
    rotation: [0, 0, 0]
});

sceneModel.createMesh({
    id: "greenLegMesh",
    parentTransformId: "tableTransform",
    geometryId: "boxGeometry",
    transformId: "greenLegTransform",
    color: [0.3, 1.0, 0.3]
});

sceneModel.createEntity({
    id: "greenLeg",
    meshIds: ["greenLegMesh"],
    isObject: true // <----------------- Represents an object, registers Entity by ID on viewer.scene.objects
});

//--------------------------------------------------------
// Blue table leg
//--------------------------------------------------------

sceneModel.createTransform({
    id: "blueLegTransform",
    parentTransformId: "tableTransform",
    position: [4, -6, 4],
    scale: [1, 3, 1],
    rotation: [0, 0, 0]
});

sceneModel.createMesh({
    id: "blueLegMesh",
    geometryId: "boxGeometry",
    transformId: "blueLegTransform",
    color: [0.3, 0.3, 1.0]
});

sceneModel.createEntity({
    id: "blueLeg",
    meshIds: ["blueLegMesh"],
    isObject: true // <----------------- Represents an object, registers Entity by ID on viewer.scene.objects
});

//--------------------------------------------------------
// Yellow table leg
//--------------------------------------------------------

sceneModel.createTransform({
    id: "yellowLegTransform",
    parentTransformId: "tableTransform",
    position: [-4, -6, 4],
    scale: [1, 3, 1],
    rotation: [0, 0, 0],
});

sceneModel.createMesh({
    id: "yellowLegMesh",
    geometryId: "boxGeometry",
    transformId: "yellowLegTransform",
    color: [1.0, 1.0, 0.0]
});

sceneModel.createEntity({
    id: "yellowLeg",
    parentTransformId: "tableTransform",
    meshIds: ["yellowLegMesh"],
    isObject: true // <----------------- Represents an object, registers Entity by ID on viewer.scene.objects
});

//--------------------------------------------------------
// Purple table top
//--------------------------------------------------------

sceneModel.createTransform({
    id: "tableTopTransform",
    parentTransformId: "tableTransform",
    position: [0, -3, 0],
    scale: [6, 0.5, 6],
    rotation: [0, 0, 0]
});

sceneModel.createMesh({
    id: "purpleTableTopMesh",
    geometryId: "boxGeometry",
    transformId: "tableTopTransform",
    color: [1.0, 0.3, 1.0]
});

sceneModel.createEntity({
    id: "purpleTableTop",
    meshIds: ["purpleTableTopMesh"],
    isObject: true // <----------------- Represents an object, registers Entity by ID on viewer.scene.objects
});

//--------------------------------------------------------
// Finalize this SceneModel.
//
// Internally, this builds any geometry batches or instanced
// arrays that are currently under construction.
//--------------------------------------------------------

sceneModel.finalize();


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


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

//------------------------------------------------------------------------------------------------------------------
// Animate some transforms
//------------------------------------------------------------------------------------------------------------------

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

    // Rotate legs
    sceneModel.transforms["yellowLegTransform"].rotateY(0.5);
    sceneModel.transforms["redLegTransform"].rotateY(1.55);
    sceneModel.transforms["blueLegTransform"].rotateY(2.25);

    sceneModel.transforms["greenLegTransform"].rotateY(1);

    sceneModel.transforms["greenLegTransform"].translateX(0.05);
    sceneModel.transforms["redLegTransform"].translateX(-0.05);
    sceneModel.transforms["blueLegTransform"].translateZ(0.05);
    sceneModel.transforms["yellowLegTransform"].translateZ(0.05);
});

@ghost
Copy link

ghost commented Nov 14, 2023

👇 Click on the image for a new way to code review

Review these changes using an interactive CodeSee Map

Legend

CodeSee Map legend

@xeolabs xeolabs changed the title Examples Movable SceneModel Objects Nov 14, 2023
@xeolabs xeolabs added this to the 2.4.2 milestone Nov 14, 2023
@xeolabs xeolabs added the enhancement New feature or request label Nov 14, 2023
@xeolabs xeolabs self-assigned this Nov 14, 2023
@xeolabs xeolabs merged commit ccd8867 into master Nov 20, 2023
2 checks passed
@xeolabs xeolabs changed the title Movable SceneModel Objects [Feature] Movable SceneModel Objects Nov 20, 2023
@xeolabs xeolabs changed the title [Feature] Movable SceneModel Objects Feature: Movable SceneModel Objects Nov 20, 2023
@xeolabs xeolabs changed the title Feature: Movable SceneModel Objects FEATURE: Movable SceneModel Objects Nov 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants