ADR-253: Exposing GLTF internals

More details about this document
Latest published version:
https://adr.decentraland.org/adr/ADR-253
Authors:
robftm
leanmendoza
Feedback:
GitHub decentraland/adr (pull requests, new issue, open issues)
Edit this documentation:
GitHub View commits View commits on githistory.xyz

Abstract

This document sets the extension of GLTF functionality, the adopted standard in Decentraland to load 3D scenes, by allowing access to the internal structure of GLTF/GLB models. This capability enables various functionalities, such as using pointer events for specific colliders, modifying internal nodes and materials, and fetching animation lists. By exposing these internal components, developers can create more dynamic and interactive experiences within the engine.

Context and Motivation

The existing pipeline for using 3D assets in interactive environments lacks the flexibility needed to dynamically control or modify specific elements within a GLTF model. Currently, artists and developers face limitations such as:

This feature is motivated by the need to improve both basic and advanced use cases for creators working with GLTF models:

This solution provides a deeper level of control by extending access to these internal resources. It supports a flexible workflow that integrates more seamlessly with artist pipelines and accelerates creative experimentation.

Proposed Solution

The proposed solution expands various GLTF components, enabling detailed, interactive control over model elements. Key updates include:

Usage

This specification is designed not only to provide functionality for creators but also to enable the development of advanced tools built upon it.

The primary and key elements for usage are as follows:

Fetching the Structure

When assigning a GltfContainer to an entity, and upon successful loading, the GltfLoadingState is populated with the complete GLTF scene data. This feedback can be disabled by setting internalFeedback=false within the GltfContainer (default is true).

Generating an Accurate Animation List

One common challenge in utilizing animations is ensuring the accuracy of animation names. As a result of fetching the structure, the animation list can directly be taken from the GLTF. Developers can either copy the string names or map the states through the array.

For instance, hardcoding each GLTF animation name is impractical when developing dynamic smart items within environments like the In-World Builder. Obtaining the animation list at runtime is crucial to streamlining the direct animation selection pipeline.

Accessing a Node from the Internal Tree

Once a GLTF is loaded and instantiated within the world, referencing specific nodes of the GLTF scene becomes possible. The availability of the node list enables efficient identification without the need to reference the entire tree structure.

To reference a node, add a GltfNode component as the child of the GltfContainer and await the GltfNodeState. Upon reaching the READY state, certain components are added to the entity as follows:

While all components are writable, specific considerations apply:

Using GLTF as a Mesh/Material Resource

This specification further allows the use of resources from a GLTF by setting the gltf field within Material, MeshRenderer, or MeshCollider. It is recommended to first load the GltfContainer and retrieve available meshes, materials, and textures, ensuring that these resources are loaded into memory before being used.

Specification

Implementation details

  1. GltfContainer Initialization and Loading State

  2. Adding and Using GltfNode Components

  3. Component Modification and Animation Synchronization

  4. Resource Usage

This specification provides structured access to GLTF data for interactive scene creation and manipulation, enforcing a robust, standardized protocol for GLTF integration within the engine.

Protobuf components

Here is the specific part of the modification to directly do in the Protocol.

Modify

It only shows the part is modified.

option (common.ecs_component_id) = 1017;
message PBMaterial {
    ....
    message GltfMaterial {
        string gltf_src = 1;
        string name = 2;
    }
  
    optional GltfMaterial gltf = 3;
}
option (common.ecs_component_id) = 1019;
message PBMeshCollider {
    ...
    message GltfMesh {
        string gltf_src = 1;
        string name = 2;
    }

    oneof mesh {
        ...
        GltfMesh gltf = 6;
    }
}
option (common.ecs_component_id) = 1018;
message PBMeshRenderer {
    ...
    message GltfMesh {
        string gltf_src = 1;
        string name = 2;
    }

    oneof mesh {
        ...
        GltfMesh gltf = 6;
    }
}
option (common.ecs_component_id) = 1049;
import "decentraland/sdk/components/common/loading_state.proto";
message PBGltfContainerLoadingState {
    ...
    repeated string node_paths = 2;
    repeated string mesh_names = 3;
    repeated string material_names = 4;
    repeated string skin_names = 5;
    repeated string animation_names = 6;
}
option (common.ecs_component_id) = 1049;
import "decentraland/sdk/components/common/loading_state.proto";
message PBGltfContainerLoadingState {
    ...
    repeated string node_paths = 2;
    repeated string mesh_names = 3;
    repeated string material_names = 4;
    repeated string skin_names = 5;
    repeated string animation_names = 6;
}
option (common.ecs_component_id) = 1041;
message PBGltfContainer {
    ...
    optional bool internal_feedback = 6;
}

New

option (common.ecs_component_id) = 1200;
message PBGltfNode {
    string path = 1;
}
option (common.ecs_component_id) = 1201;
message PBGltfNodeState {
    GltfNodeStateValue state = 1;
    optional string error = 2;
}
enum GltfNodeStateValue {
    GNSV_PENDING = 0;
    GNSV_FAILED = 1;
    GNSV_READY = 2;
}

RFC 2119 and RFC 8174

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

License

Copyright and related rights waived via CC0-1.0. DRAFT Draft