MackeyK24

GLTF Babylon Toolkit

Recommended Posts

Yo @Deltakosh and @davrous and @Sebavan .... PLEASE READ THIS :)

Hey guys... I have been working with native GLTF file format and is AWESOME... I made another Test Version Of the Toolkit the is totally based off of the Official GLTF Scene Hierarchy using GLTF Extensions and Extras to handle things like the PBR Specular extensions.

It works BEAUTIFUL ... I ported the scene exporter from a modded version GLTFSerialzation.dll and UnityGLTF.dll to support All Game Engines that read GLTF scene files (the sketch fab version is design for sketch fab viewer... they dont even give you access to the package... its made in a temp file uploaded to their server then deleted from your system)

My version also supports basic Unity Meta Data for Camera, Lights Ans Scripts.... From there you can make script components to do EVERYTHING you ever saw me do the Babylon toolkit.... But MUCH MUCH MUCH MORE SIMPLIFIED... There are ONLY 8 C# source files in the beta version toolkit now.

Without any further modifications to any babylon.js libraries you get a PERFECT scene hierarchy with all features of GLTF 2.0 Specification.

But if I make a few modifications to the Babylon GLTF Importer, I can add support for the GLTF Extras metadata section to create cameras, lights and script components... which is the HEART of the Babylon Toolkit now... Its just now we dont have to re-create the wheel by exporting sooooo much stuff as individual components into a babylon specific format... But rather use all the industry standard features of GLTF that was designed to handle WebGL 3D scenes... Like the binary images are supposed to ready to go from array buffer right to GPU without any extra processing ... and tones of other modern GL Transmission Format features.

Now this was an experiment to see if I can do it... GLTF and GLB ... Worked like a charm :)

So I also made a PlayCanvas Toolkit as a proof of concept project to see what I can do if I had control in the UNITY GLTF Exporter And the PlayCanvas GLTF Importer... And now I have EVERY feature I had for Babylon Toolkit ... in my new PlayCanvas Toolkit... Actually some things are a little better... First off PlayCanvas already has the concept of COMPONENTS and ATTACHING SCRIPTS to ENTITIES... So my PlayCanvas Version of scene manager does not have to do NO WHERE NEAR AS MUCH. Second, the physics is WAY BETTER... uses Ammo.js and... And most of all their WHOLE component model down to the design of the Online Editor is VERY similar to Unity... So all the component scripts properties go over nicely... most have the same exact property name.

Now we are in the BabylonJS forum so sorry for shamelessly promoting my new PlayCanvas Toolkit but I wanted to prove it could be done... And shit... Now I have TWO HTML5 Canvas Game Development Toolkits.... They basically do the same thing... They look exactly the same except for logo... They just use different Editor Templates and Content Script Components...

Now this would mean NO MORE .babylon scene files.

So if you want to go with GLTF and GLB as the file format for the toolkit... Let me know... I can start working in the Babylon GLTF Importer to parse the GLTF Extras section for Cameras, Lights And Script Components.... The heart of what make the Toolkit :)

 

Share this post


Link to post
Share on other sites

Well, interesting turn around ;)

So first let me fix the truth. We do support component attachment of behaviors: http://doc.babylonjs.com/features/behaviour

Regarding the GLTF Importer, we can only accept updates that are not specific but generic for everyone. If this is the case, I would be happy to merge any change :)

Share this post


Link to post
Share on other sites
On 7/9/2018 at 6:56 AM, Deltakosh said:

Well, interesting turn around ;)

So first let me fix the truth. We do support component attachment of behaviors: http://doc.babylonjs.com/features/behaviour

Regarding the GLTF Importer, we can only accept updates that are not specific but generic for everyone. If this is the case, I would be happy to merge any change :)

 

Yo @Deltakosh ... My main thing would be the changing of the Babylon Toolkit to produced industry standard GLTF / GLB scene files INSTEAD of the class .babylon JSON ONLY scene file.  Now as for the GLTF ... I can handle that in a custom GLTF Loader.

But the new toolkit simply encode standard unity metadata into the GLTF Extras section... NO SPECIAL CODE OR COMPONENTS FROM ME (except an option Default Scene Controller to really help set default scene options). That makes it for EVERYBODY use... Not just Babylon either... But ANY GAME ENGINE that uses GLTF can parse the Standard Unity Meta Data for what is a Light or Camera or Script or WHATEVER supported components that are attached to an entity.

That now give ANY GAME ALL THE INFO THEY NEED to completely re implement that component in their engine. That is how I made the toolkit it self. if I just change to encoding EVERYTHING through my new GLTF Export pipeline... EVERYTHING INCLUDING SCRIPTS get packaged up as an industry standard GLTF or GLB scene that has a the standard Unity MetaData encoded to the GLTF Extras. Now Any Vendor for Game can CHOOSE to support the extra metadata the same way the choose to support ANY GLTF Extension And Extras... By parsing the GLSTF JSON.

Man... we can make TOTALY SELF CONTAINED games/scene within GLB packages inluding the actually script need to back the components attached to game game objects in the scene. 

That is FREAKING SWEET... And ANY ENGINE can now use that metadata... 

Here is an example scene with Lights, Cameras, Meshes, Materials, Sounds and Scripts... Everything any game engine needs to "IMPLEMENT" those EXTRAS components... other than the regular geometry

 

  "nodes": [
    {
      "translation": [
        0.0,
        1.0,
        10.0
      ],
      "name": "Main Camera",
      "extras": {
        "metadata": {
          "alias": "entity",
          "id": "bad6abaf-7a53-4361-8408-be8d33637833",
          "tag": "MainCamera",
          "name": "Main Camera",
          "prefab": false,
          "layer": 0,
          "layername": "Default",
          "components": [
            {
              "alias": "camera",
              "clearflags": {
                "Key": 0,
                "Value": "Skybox"
              },
              "backgroundcolor": {
                "r": 0.192156866,
                "g": 0.3019608,
                "b": 0.4745098,
                "a": 1.0
              },
              "normalizedviewportrect": {
                "x": 0.0,
                "y": 0.0,
                "position": {
                  "x": 0.0,
                  "y": 0.0
                },
                "center": {
                  "x": 0.5,
                  "y": 0.5
                },
                "min": {
                  "x": 0.0,
                  "y": 0.0
                },
                "max": {
                  "x": 1.0,
                  "y": 1.0
                },
                "width": 1.0,
                "height": 1.0,
                "size": {
                  "x": 1.0,
                  "y": 1.0
                },
                "xMin": 0.0,
                "yMin": 0.0,
                "xMax": 1.0,
                "yMax": 1.0,
                "left": 0.0,
                "right": 1.0,
                "top": 0.0,
                "bottom": 1.0
              },
              "x": 0.0,
              "y": 0.0,
              "width": 1.0,
              "height": 1.0,
              "nearclipplane": 0.3,
              "farclipplane": 1000.0,
              "fieldofview": 60.0,
              "orthographic": false,
              "orthographicsize": 5.0,
              "depth": -1.0,
              "cullingmask": -1,
              "renderingpath": {
                "Key": 0,
                "Value": "Use Graphics Settings"
              },
              "targettexture": null,
              "targetdisplay": 0,
              "targeteye": 3,
              "hdr": true,
              "allowmsaa": true,
              "allowdynamicresolution": false,
              "forceintort": true,
              "occlusionculling": true,
              "stereoconvergence": 10.0,
              "stereoseparation": 0.022,
              "maincamera": true
            },
            {
              "alias": "audiolistener"
            }
          ]
        }
      }
    },
    {
      "rotation": [
        0.408217877,
        -0.234569684,
        0.109381631,
        0.8754261
      ],
      "scale": [
        1.0,
        1.0,
        0.99999994
      ],
      "translation": [
        0.0,
        3.0,
        0.0
      ],
      "name": "Directional Light",
      "extras": {
        "metadata": {
          "alias": "entity",
          "id": "1700f16a-8944-4574-94b6-ba3e00faa4eb",
          "tag": "Untagged",
          "name": "Directional Light",
          "prefab": false,
          "layer": 0,
          "layername": "Default",
          "components": [
            {
              "alias": "light",
              "type": {
                "Key": 1,
                "Value": "Directional"
              },
              "color": {
                "r": 1.0,
                "g": 0.956862748,
                "b": 0.8392157,
                "a": 1.0
              },
              "intensity": 1.0,
              "range": 10.0,
              "spotangle": 30.0,
              "cookiesize": 10.0,
              "type_aux": {
                "Key": 2,
                "Value": "Soft Shadows"
              },
              "resolution": {
                "Key": 0,
                "Value": "Use Quality Settings"
              },
              "customresolution": -1,
              "strength": 1.0,
              "bias": 0.05,
              "normalbias": 0.4,
              "nearplane": 0.2,
              "cookie": null,
              "drawhalo": false,
              "probeocclusionlightindex": 0,
              "occlusionmaskchannel": 0,
              "lightmapbaketype": {
                "Key": 0,
                "Value": "Mixed"
              },
              "mixedlightingmode": {
                "Key": 1,
                "Value": "Subtractive"
              },
              "isbaked": true,
              "flare": null,
              "rendermode": {
                "Key": 0,
                "Value": "Auto"
              },
              "cullingmask": -1,
              "lightmapping": {
                "Key": 0,
                "Value": "Mixed"
              },
              "areasize": {
                "x": 1.0,
                "y": 1.0
              },
              "x": 1.0,
              "y": 1.0,
              "bounceintensity": 1.0,
              "colortemperature": 6570.0,
              "usecolortemperature": false,
              "shadowradius": 0.0,
              "shadowangle": 0.0
            }
          ]
        }
      }
    },
    {
      "children": [
        3
      ],
      "mesh": 0,
      "rotation": [
        0.7071068,
        0.0,
        0.0,
        0.7071068
      ],
      "scale": [
        1.0,
        1.00000024,
        1.00000024
      ],
      "name": "Cube",
      "extras": {
        "metadata": {
          "alias": "entity",
          "id": "8f6d3e11-a7a5-4476-97c5-0984613977cd",
          "tag": "Untagged",
          "name": "Cube",
          "prefab": false,
          "layer": 0,
          "layername": "Default",
          "components": [
            {
              "alias": "boxcollider",
              "material": null,
              "istrigger": false,
              "size": {
                "x": 1.0,
                "y": 1.0,
                "z": 1.0
              },
              "x": 1.0,
              "y": 1.0,
              "z": 1.0,
              "center": {
                "x": 0.0,
                "y": 0.0,
                "z": 0.0
              },
              "x_aux": 0.0,
              "y_aux": 0.0,
              "z_aux": 0.0
            },
            {
              "alias": "script",
              "klass": "DemoRotator",
              "helloWorld": "Hello World"
            },
            {
              "alias": "meshcollider",
              "material": null,
              "istrigger": false,
              "convex": false,
              "cookingoptions": 14,
              "skinwidth": 0.01
            }
          ]
        }
      }
    },
    {
      "children": [
        4
      ],
      "mesh": 1,
      "name": "Capsule",
      "extras": {
        "metadata": {
          "alias": "entity",
          "id": "07f6a97f-a477-49f9-aed6-cbc133d9fbdd",
          "tag": "Untagged",
          "name": "Capsule",
          "prefab": false,
          "layer": 0,
          "layername": "Default",
          "components": [
            {
              "alias": "capsulecollider",
              "material": null,
              "istrigger": false,
              "radius": 0.5,
              "height": 2.0,
              "direction": {
                "Key": 1,
                "Value": "Y-Axis"
              },
              "center": {
                "x": 0.0,
                "y": 0.0,
                "z": 0.0
              },
              "x": 0.0,
              "y": 0.0,
              "z": 0.0
            }
          ]
        }
      }
    },
    {
      "mesh": 2,
      "scale": [
        1.25,
        1.25,
        1.25
      ],
      "name": "Sphere",
      "extras": {
        "metadata": {
          "alias": "entity",
          "id": "91810ebc-7de7-4f03-b1b5-bd482bf1091c",
          "tag": "Untagged",
          "name": "Sphere",
          "prefab": false,
          "layer": 0,
          "layername": "Default",
          "components": [
            {
              "alias": "spherecollider",
              "material": {
                "dynamicFriction": 0.6,
                "staticFriction": 0.6,
                "bounciness": 0.0,
                "bouncyness": 0.0,
                "frictionDirection2": {
                  "x": 0.0,
                  "y": 0.0,
                  "z": 0.0
                },
                "dynamicFriction2": 0.0,
                "staticFriction2": 0.0,
                "frictionCombine": 0,
                "bounceCombine": 0,
                "frictionDirection": {
                  "x": 0.0,
                  "y": 0.0,
                  "z": 0.0
                },
                "name": "Tester (Instance) (Instance) (Instance)",
                "hideFlags": 0
              },
              "istrigger": false,
              "radius": 0.5,
              "center": {
                "x": 0.0,
                "y": 0.0,
                "z": 0.0
              },
              "x": 0.0,
              "y": 0.0,
              "z": 0.0
            },
            {
              "alias": "rigidbody",
              "mass": 1.0,
              "drag": 0.0,
              "angulardrag": 0.05,
              "usegravity": true,
              "iskinematic": false,
              "interpolate": {
                "Key": 0,
                "Value": "None"
              },
              "collisiondetection": {
                "Key": 0,
                "Value": "Discrete"
              },
              "staticfriction": 0.6,
              "dynamicfriction": 0.6,
              "restitution": 0.0
            },
            {
              "alias": "audiosource",
              "outputaudiomixergroup": null,
              "audioclip": {
                "length": 13.2413607,
                "samples": 583944,
                "channels": 2,
                "frequency": 44100,
                "isReadyToPlay": true,
                "loadType": 0,
                "preloadAudioData": true,
                "ambisonic": false,
                "loadState": 2,
                "loadInBackground": false,
                "name": "Music",
                "hideFlags": 8
              },
              "playonawake": true,
              "volume": 1.0,
              "pitch": 1.0,
              "loop": false,
              "mute": false,
              "spatialize": false,
              "spatializeposteffects": false,
              "priority": 128,
              "dopplerlevel": 1.0,
              "mindistance": 1.0,
              "maxdistance": 500.0,
              "pan2d": 0.0,
              "rolloffmode": {
                "Key": 0,
                "Value": "Logarithmic Rolloff"
              },
              "bypasseffects": false,
              "bypasslistenereffects": false,
              "bypassreverbzones": false,
              "rolloffcustomcurve": {
                "keys": [
                  {
                    "time": 0.0,
                    "value": 1.0,
                    "inTangent": 0.0,
                    "outTangent": 0.0,
                    "inWeight": 0.333333343,
                    "outWeight": 0.333333343,
                    "weightedMode": 0,
                    "tangentMode": 0
                  },
                  {
                    "time": 1.0,
                    "value": 0.0,
                    "inTangent": 0.0,
                    "outTangent": 0.0,
                    "inWeight": 0.333333343,
                    "outWeight": 0.333333343,
                    "weightedMode": 0,
                    "tangentMode": 0
                  }
                ],
                "length": 2,
                "preWrapMode": 8,
                "postWrapMode": 8
              },
              "panlevelcustomcurve": {
                "keys": [
                  {
                    "time": 0.0,
                    "value": 0.0,
                    "inTangent": 0.0,
                    "outTangent": 0.0,
                    "inWeight": 0.333333343,
                    "outWeight": 0.333333343,
                    "weightedMode": 0,
                    "tangentMode": 0
                  }
                ],
                "length": 1,
                "preWrapMode": 8,
                "postWrapMode": 8
              },
              "spreadcustomcurve": {
                "keys": [
                  {
                    "time": 0.0,
                    "value": 0.0,
                    "inTangent": 0.0,
                    "outTangent": 0.0,
                    "inWeight": 0.333333343,
                    "outWeight": 0.333333343,
                    "weightedMode": 0,
                    "tangentMode": 0
                  }
                ],
                "length": 1,
                "preWrapMode": 8,
                "postWrapMode": 8
              },
              "reverbzonemixcustomcurve": {
                "keys": [
                  {
                    "time": 0.0,
                    "value": 1.0,
                    "inTangent": 0.0,
                    "outTangent": 0.0,
                    "inWeight": 0.333333343,
                    "outWeight": 0.333333343,
                    "weightedMode": 0,
                    "tangentMode": 0
                  }
                ],
                "length": 1,
                "preWrapMode": 8,
                "postWrapMode": 8
              },
              "audioimageid": 2
            }
          ]
        }
      }
    },
    {
      "name": "GameObject",
      "extras": {
        "metadata": {
          "alias": "entity",
          "id": "e9088d57-8950-490c-9e9e-10752a1b8c36",
          "tag": "Untagged",
          "name": "GameObject",
          "prefab": false,
          "layer": 0,
          "layername": "Default",
          "components": null
        }
      }
    }
  ],
  "samplers": [
    {
      "minFilter": 9729
    }
  ],
  "scene": 0,
  "scenes": [
    {
      "nodes": [
        0,
        1,
        2,
        5
      ],
      "name": "Tester",
      "extras": {
        "metadata": {
          "alias": "scene",
          "controller": null,
          "ambientlightintensity": 1.0,
          "ambientlightdirection": {
            "x": 0.0,
            "y": 1.0,
            "z": 0.0
          },
          "ambientspecularcolor": {
            "r": 0.0,
            "g": 0.0,
            "b": 0.0,
            "a": 1.0
          },
          "ambientgroundcolor": {
            "r": 0.0,
            "g": 0.0,
            "b": 0.0,
            "a": 1.0
          },
          "ambientskycolor": {
            "r": 0.0,
            "g": 0.0,
            "b": 0.0,
            "a": 1.0
          },
          "fogmode": 0,
          "fogtype": "None",
          "fogdensity": 0.01,
          "fogcolor": {
            "r": 0.5,
            "g": 0.5,
            "b": 0.5,
            "a": 1.0
          },
          "fogstart": 0.0,
          "fogend": 300.0
        }
      }
    }
  ],

 

And here is an example GLTF Importer I made for PlayCanvas (Just to prove I can do it)

 

/**
 * PlayCanvas Toolkit Bundle - Version 1.4.3 
 * ==============================================================================
 * PlayCanvas helper tools
 * @class CanvasTools
 */
class CanvasTools {
    public static TranslateScene(app:pc.Application, resources:any):void {
        //console.log("===> Translating Scene: GLTF");
    }
    public static TranslateNode(entity:pc.Entity, data:any, resources:any):void {
        //console.log("===> Translating Node: " + entity.getName());
        if (data.hasOwnProperty("extras") && data.extras.hasOwnProperty("metadata")) {
            entity.metadata = data.extras.metadata;
            if (entity.metadata.hasOwnProperty("components")) {
                const components:any[] = entity.metadata.components;
                if (components != null && components.length > 0) {
                    let scripts:any[] = [];
                    components.forEach((component:any) => {
                        switch (component.alias) {
                            case "script":
                                scripts.push(component);
                                break;
                            case "camera":
                                CanvasTools.ParseCameraNode(entity, data, resources, component);
                                break;
                            case "light":
                                CanvasTools.ParseLightNode(entity, data, resources, component);
                                break;
                        }
                    });
                    if (scripts.length > 0) {
                        scripts.forEach((script) => { CanvasTools.ParseScriptNode(entity, data, resources, script); });
                    }
                }
            }
        }
    }
    public static GetColorFromFloats(floats:number[]):pc.Color {
        let result:pc.Color = new pc.Color(0,0,0,1);
        if (floats != null) {
            if (floats.length >= 4) {
                result.r = floats[0];
                result.g = floats[1];
                result.b = floats[2];
                result.a = floats[3];
            } else if (floats.length == 3) {
                result.r = floats[0];
                result.g = floats[1];
                result.b = floats[2];
            }
        }
        return result;
    }
    // ..
    // Parse Node Entity Functions
    // ..
    private static ParseScriptNode(entity:pc.Entity, data:any, resources:any, component:any):void {
        let scriptOptions:any = {};
        if (entity.script == null) {
            entity.addComponent("script", scriptOptions);
        }
        if (entity.script != null) {
            let args = { enabled: component.enabled, attributes:{} };
            entity.script.create(component.klass, args)
        } else {
            console.warn("Failed to add script component for entity: " + entity.getName());
        }
    }
    private static ParseCameraNode(entity:pc.Entity, data:any, resources:any, component:any):void {
        let cameraOptions:any = {};
        cameraOptions.clearColor = CanvasTools.GetColorFromFloats(component.clearColor);
        if (component.projection === 0) {
            cameraOptions.type = pc.PROJECTION_PERSPECTIVE;
            cameraOptions.aspectRatio = component.aspectRatio;
            cameraOptions.nearClip = component.nearClip;
            cameraOptions.farClip = component.farClip;
            cameraOptions.fov = component.fov;
        } else if (component.projection === 1) {
            cameraOptions.type = pc.PROJECTION_ORTHOGRAPHIC;
            //cameraOptions.aspectRatio = orthographic.xmag / orthographic.ymag;
            //cameraOptions.orthoHeight = orthographic.ymag * 0.5;
            cameraOptions.nearClip = component.nearClip;
            cameraOptions.farClip = component.farClip;
        }
        if (entity.camera == null) {
            entity.addComponent("camera", cameraOptions);
        }
        if (entity.camera != null) {
            // TODO: Set Additional Camera Properties
        } else {
            console.warn("Failed to add camera component for entity: " + entity.getName());
        }
    }
    private static ParseLightNode(entity:pc.Entity, data:any, resources:any, component:any):void {
        let lightOptions:any = component;
        lightOptions.color = CanvasTools.GetColorFromFloats(lightOptions.color);
        if (entity.light == null) {
            entity.addComponent("light", lightOptions);
        }
        if (entity.light != null) {
            // TODO: Set Additional Light Properties
        } else {
            console.warn("Failed to add light component for entity: " + entity.getName());
        }
    }
}

 

It looks so sweet... Even in the GLTF Previewer of VSCode that use BabylonJS... I can just Alf-G the GLTF file in VSCode and is automatically comes up the BabylonJS.  If that Babylon's instance had my new parsing stuff... it could not only show that STATIC scene which is all you get now... But actually create lights, cameras, scripts components and the WHOLE nine yards to make ANY GLTF or GLB scene loaded in BabylonJS completely self contained. With is little or as much interactively you want to export... you make and run a ENTIRE Games with all its assets and everything works with NO MANUAL interactions to INIT or drive the scene... Shit you then DRAG and DROP complete games on to any BabylonJS enabled Viewer... Providing we support that Unity Metadata in BabylonJS...

How can that not be for everybody :)

 

 

 

Share this post


Link to post
Share on other sites
On 7/11/2018 at 6:01 AM, Deltakosh said:

Regarding the UnityMetadata in gltf loader, this cannot be done by default but we could easily expose the metadata after loading the gltf and then you can plug ther

That’s Koop, just let me know how

 

Share this post


Link to post
Share on other sites

Yo @Deltakosh and @bghgary please let me know about HOOKING into the GLTFLoader... For now i will just grab a copy of the loader and make a Custom Loader based off that... Worse case scenario... i can make my own Custom Loader for GLTF/GLB files as a part of my SceneManager... If you want to use the Unity Extra Meta Data...

You could always do something like:

BABYLON.SceneManager.EnableExtras();

And that will Register My Custom Scene Loader Plugin for .gltf and .glb files ... Worse case... If i cant get the RIGHT HOOKS ... So i dont have to go back in a iterate over scene items... I would rather do it at NODE instantiation within the GLTF Import Parsing.

Anyways... Take a look at my GLTF Extra Unity Meta Data Extension Draft  

Looking good so far ... My next generation Babylon Toolkit will be much easier to use for everyone...

I will try to make with NO SPECIAL COMPONENTS ... Just using the built-in supported Unity Engine Components :)

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.