Skip to content
This repository has been archived by the owner on Jan 14, 2022. It is now read-only.

Explicit vs implicit properties #7

Closed
cecilemuller opened this issue Feb 22, 2015 · 2 comments
Closed

Explicit vs implicit properties #7

cecilemuller opened this issue Feb 22, 2015 · 2 comments
Labels

Comments

@cecilemuller
Copy link
Member

You might wonder:

Why bother having a $ in every node and the name of properties, when you could automatically deduce where child nodes belong to based on their type? For example, it's obvious what a Box and an Appearance inside a Shape should do.

@cecilemuller
Copy link
Member Author

Even if it was already covered in multiple previous issues, for the sake of clarity this explains why JSON Scenegraph uses explicit properties (like VRML), not implicit properties (like XML).


Implicit properties

The first main issue with implicit is it requires the 3D engine to guess / keep a list of which node type goes in which property based on the types of the child and the parent.

The second main issue is it assumes that a given child node type can only match a single property of the parent: this works with non-ambigous cases like Box or Appearance in a Shape because it's obvious, but it would not work with let's say a CustomNode that has two MFNode properties accepting any type of subnodes as you wouldn't know which child nodes are for CustomExampleNode.firstProperty and which are for CustomExampleNode.secondProperty as you can see in this example, so this is not a useable solution as-is:

[
    "CustomExampleNode": [
        {
            "Shape": [
                {
                    "Box": [
                        {
                            "@size": [1, 2, 3]
                        }
                    ]
                },
                {
                    "Box": [
                        {
                            "@size": [1, 2, 3]
                        }
                    ]
                }
            ],
            "Transform": [
                {
                    "@translation": [3, 0, 0],
                    "Shape": [
                        {
                            "Box": [
                                {
                                    "@size": [1, 2, 3]
                                }
                            ]
                        }
                    ]
                }
            ],
            "DirectionalLight": [
                {
                    "@color": [1, 1, 0.5]
                }
            ]
        }
    ]
]

The XML workaround would have the child nodes specify the container field:

[
    "CustomExampleNode": [
        {
            "Shape": [
                {
                    "@containerField": "firstProperty",
                    "Box": [
                        {
                            "@containerField": "geometry",
                            "@size": [1, 2, 3]
                        }
                    ]
                },
                {
                    "@containerField": "secondProperty",
                    "Box": [
                        {
                            "@containerField": "geometry",
                            "@size": [1, 2, 3]
                        }
                    ]
                }
            ],
            "Transform": [
                {
                    "@containerField": "firstProperty",
                    "@translation": [3, 0, 0],
                    "Shape": [
                        {
                            "Box": [
                                {
                                    "@containerField": "geometry",
                                    "@size": [1, 2, 3]
                                }
                            ]
                        }
                    ]
                }
            ],
            "DirectionalLight": [
                {
                    "@containerField": "secondProperty",
                    "@color": [1, 1, 0.5]
                }
            ]
        }
    ]
]

It works, but it breaks our "Always write a node the same way given the same properties" principle because:

{
    "@containerField": "firstProperty",
    "Box": [
        {
            "@size": [1, 2, 3]
        }
    ]
}

is not the same as:

{
    "@containerField": "secondProperty",
    "Box": [
        {
            "@size": [1, 2, 3]
        }
    ]
}

despite both represent a Shape containing a Box with size [1, 2, 3].


Explicit properties

With explicit containers, a node given set of properties is always written the same way, regardless of what property contains it, and you don't have to guess which property the nodes belong to.

[
    {
        "$": "CustomExampleNode",
        "firstProperty": [
            {
                "$": "Shape"
                "geometry": {
                    "$": "Box",
                    "size": [1, 2, 3]
                }
            },
            {
                "$": "Transform",
                "translation": [3, 0, 0],
                "children": [
                    {
                        "$": "Shape"
                        "geometry": {
                            "$": "Box",
                            "size": [1, 2, 3]
                        }
                    }
                ]
            }
        ],
        "secondProperty": [
            {
                "$": "Shape"
                "geometry": {
                    "$": "Box",
                    "size": [1, 2, 3]
                }
            },
            {
                "$": "DirectionalLight",
                "color": [1, 1, 0.5]
            }
        ]
    }
]

@cecilemuller
Copy link
Member Author

Accessing deep values

Another issue with implicit is it makes it more complex to access something deep in the tree.

Implicit

In this example, reading the size of the Sphere is done using:

root[0].CustomExampleNode[0].Transform[0].Shape[0].Sphere[0]['@size'];

[
    "CustomExampleNode": [
        {
            "Shape": [
                {
                    "@containerField": "firstProperty",
                    "Box": [
                        {
                            "@containerField": "geometry",
                            "@size": [1, 2, 3]
                        }
                    ]
                },
                {
                    "@containerField": "secondProperty",
                    "Box": [
                        {
                            "@containerField": "geometry",
                            "@size": [1, 2, 3]
                        }
                    ]
                }
            ],
            "Transform": [
                {
                    "@containerField": "firstProperty",
                    "@translation": [3, 0, 0],
                    "Shape": [
                        {
                            "Sphere": [
                                {
                                    "@containerField": "geometry",
                                    "@size": [5, 5, 5]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
]

Explicit

Using explicit instead, the path is shorter:

root[0].firstProperty[1].children[0].geometry.size

[
    {
        "$": "CustomExampleNode",
        "firstProperty": [
            {
                "$": "Shape"
                "geometry": {
                    "$": "Box",
                    "size": [1, 2, 3]
                }
            },
            {
                "$": "Transform",
                "translation": [3, 0, 0],
                "children": [
                    {
                        "$": "Shape"
                        "geometry": {
                            "$": "Sphere",
                            "size": [5, 5, 5]
                        }
                    }
                ]
            }
        ],
        "secondProperty": [
            {
                "$": "Shape"
                "geometry": {
                    "$": "Box",
                    "size": [1, 2, 3]
                }
            }
        ]
    }
]

It also is the same path that VRMLscript would use to access it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

1 participant