5
$\begingroup$

I am currently looking into glTF to use as a transfer format for my WebGL project. I already have the geometries I wish to render on my WebGL client available as preprocessed vertex and index buffers (and color buffers, but let's ignore them for now).

For example:

[       // vertex buffer
  0,0,0,
  0,1,0,
  1,0,0,
  1,1,0,
]

And to draw simple LINES:

[       // index buffer
  0,2,
  2,4,
  4,0,
  0,1,
  1,4,
]

I wonder how to create glTF files containing these buffers? Is this possible?

I want to avoid using COLLADA and COLLADA2GLTF as this would only add an additional step and might just bloat the resulting glTF files.

$\endgroup$

3 Answers 3

6
$\begingroup$

While creating a set of glTF models for a tutorial, I also intended to create THE minimal glTF file.


Update: The following referred to glTF 1.0/1.1. See below for an update of this example to glTF 2.0.


As already mentioned in the answer by 5chdn, one issue may be the material. According to the Appendix A: Default Material of the specification, an asset that does not contain a material should be rendered with a default material that simply shows the object in a uniform, 50% gray color.

Some viewers might not support this, and even if they do, there have been some minor subtleties in the spec regarding this point: In glTF 1.0, it was still necessary to define an "empty" material, because the mesh.primitive.material property was not yet optional. But this should be fixed in glTF 1.1.

So the following should indeed be THE minimal possible glTF asset (version 1.1) :

{
  "scenes" : {
    "scene0" : {
      "nodes" : [ "node0" ]
    }
  },
  "nodes" : {
    "node0" : {
      "meshes" : [ "mesh0" ]
    }
  },

  "meshes" : {
    "mesh0" : {
      "primitives" : [ {
        "attributes" : {
          "POSITION" : "positionsAccessor"
        }
      } ]
    }
  },

  "buffers" : {
    "buffer0" : {
      "uri" : "data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAA",
      "byteLength" : 36
    }
  },
  "bufferViews" : {
    "positionsBufferView" : {
      "buffer" : "buffer0",
      "byteOffset" : 0,
      "byteLength" : 36,
      "target" : 34962
    }
  },
  "accessors" : {
    "positionsAccessor" : {
      "bufferView" : "positionsBufferView",
      "byteOffset" : 0,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 1.0, 1.0, 0.0 ],
      "min" : [ 0.0, 0.0, 0.0 ]
    }
  },

  "asset" : {
    "version" : "1.1"
  }
}

It also shows a single triangle:

TriangleWithoutIndices

The version without embedded buffers is available at https://github.com/javagl/gltfTutorialModels , as well as a triangle with indices, at https://github.com/javagl/gltfTutorialModels/tree/master/Triangle


Update for glTF 2.0:


The concepts and top-level elements of glTF 2.0 are basically the same as for glTF 1.0. But there still have been some changes in the format. Most importantly (for this small example), the top-level dictionaries are now arrays. The following is the same "Triangle" model as above, updated accordingly:

{
   "scenes":[
      {
         "nodes":[ 0 ]
      }
   ],
   "nodes":[
      {
         "mesh":0
      }
   ],
   "meshes":[
      {
         "primitives":[
            {
               "attributes":{
                  "POSITION":1
               },
               "indices":0
            }
         ]
      }
   ],
   "buffers":[
      {
         "uri":"data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
         "byteLength":44
      }
   ],
   "bufferViews":[
      {
         "buffer":0,
         "byteOffset":0,
         "byteLength":6,
         "target":34963
      },
      {
         "buffer":0,
         "byteOffset":8,
         "byteLength":36,
         "target":34962
      }
   ],
   "accessors":[
      {
         "bufferView":0,
         "byteOffset":0,
         "componentType":5123,
         "count":3,
         "type":"SCALAR",
         "max":[
            2
         ],
         "min":[
            0
         ]
      },
      {
         "bufferView":1,
         "byteOffset":0,
         "componentType":5126,
         "count":3,
         "type":"VEC3",
         "max":[
            1.0,
            1.0,
            0.0
         ],
         "min":[
            0.0,
            0.0,
            0.0
         ]
      }
   ],
   "asset":{
      "version":"2.0"
   }
}

This and other glTF sample models can be found in the glTF sample models repository.

$\endgroup$
4
$\begingroup$

You can put the data into a data uri to store the data inline in base64 format.

"buffers": {
    "a-buffer-id": {
        "byteLength": 1024,
        "type": "arraybuffer",
        "uri"="data:application/octet-stream;base64,..."
    }
},

It's still a bit bloated compared to storing the data in a binary file though.

$\endgroup$
3
$\begingroup$

After spending a hard time to understand the way how the binary buffers work in the gltf files I finally managed to generate a truely minimal gltf file. It's a single yellow triangle (demo).

minimal triangle

I tried to remove everything which is not needed from the gltf. This is what is required it seems (github):

{
    "accessors": {
        "accessor0": {
            "bufferView": "bufferView0",
            "byteOffset": 0,
            "componentType": 5123,
            "count": 3,
            "type": "SCALAR"
        },
        "accessor1": {
            "bufferView": "bufferView1",
            "byteOffset": 0,
            "byteStride": 12,
            "componentType": 5126,
            "count": 3,
            "max": [
                0.5,
                0.5,
                0.5
            ],
            "min": [
                0.0,
                0.0,
                0.0
            ],
            "type": "VEC3"
        }
    },
    "asset": {
        "generator": "5chdn",
        "profile": {
            "api": "WebGL",
            "version": "1.0.3"
        },
        "version": "1.0",
        "extras": {
            "description": "minimal gltf, single triangle",
            "base64encoder": "https://jsfiddle.net/opkxy0xb/",
            "stackexchange": "https://computergraphics.stackexchange.com/q/1934/361"
        }
    },
    "bufferViews": {
        "bufferView0": {
            "buffer": "Min",
            "byteLength": 6,
            "byteOffset": 0,
            "target": 34963
        },
        "bufferView1": {
            "buffer": "Min",
            "byteLength": 36,
            "byteOffset": 6,
            "target": 34962
        }
    },
    "buffers": {
        "Min": {
            "bytelength": 42,
            "type": "arraybuffer",
            "uri": "data:application/octet-stream;base64,AAABAAIArK34PnZxmz29UhY9T6+UPXuD7z64QAI9UWuaPW/wBT3ysPA+"
        }
    },
    "materials": {
        "effect0": {
            "values": {
                "emission": [
                    0.8,
                    0.8,
                    0.0,
                    1.0
                ]
            },
            "technique": "technique0"
        }
    },
    "meshes": {
        "mesh0": {
            "name": "Triangle",
            "primitives": [
                {
                    "attributes": {
                        "POSITION": "accessor1"
                    },
                    "indices": "accessor0",
                    "material": "effect0",
                    "mode": 4
                }
            ]
        }
    },
    "nodes": {
        "node0": {
            "matrix": [
                1,
                0,
                0,
                0,
                0,
                1,
                0,
                0,
                0,
                0,
                1,
                0,
                0,
                0,
                0,
                1
            ],
            "meshes": [
                "mesh0"
            ],
            "name": "TriangleMesh"
        }
    },
    "programs": {
        "program0": {
            "attributes": [
                "a_position"
            ],
            "fragmentShader": "fragmentShader0",
            "vertexShader": "vertexShader0"
        }
    },
    "scenes": {
        "scene0": {
            "nodes": [
                "node0"
            ]
        }
    },
    "shaders": {
        "vertexShader0": {
            "type": 35633,
            "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Ow0KdW5pZm9ybSBtYXQ0IHVfbW9kZWxWaWV3TWF0cml4Ow0KdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsNCmF0dHJpYnV0ZSB2ZWMzIGFfcG9zaXRpb247DQp2b2lkIG1haW4odm9pZCkNCnsNCmdsX1Bvc2l0aW9uID0gdV9wcm9qZWN0aW9uTWF0cml4ICogdV9tb2RlbFZpZXdNYXRyaXggKiB2ZWM0KGFfcG9zaXRpb24sMS4wKTsNCn0="
        },
        "fragmentShader0": {
            "type": 35632,
            "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Ow0KdW5pZm9ybSB2ZWM0IHVfZW1pc3Npb247DQp2b2lkIG1haW4odm9pZCkNCnsNCmdsX0ZyYWdDb2xvciA9IHVfZW1pc3Npb247DQp9"
        }
    },
    "techniques": {
        "technique0": {
            "attributes": {
                "a_position": "position"
            },
            "parameters": {
                "modelViewMatrix": {
                    "semantic": "MODELVIEW",
                    "type": 35676
                },
                "projectionMatrix": {
                    "semantic": "PROJECTION",
                    "type": 35676
                },
                "emission": {
                    "type": 35666
                },
                "position": {
                    "semantic": "POSITION",
                    "type": 35665
                }
            },
            "program": "program0",
            "states": {
                "enable": [
                    2884,
                    2929
                ]
            },
            "uniforms": {
                "u_modelViewMatrix": "modelViewMatrix",
                "u_projectionMatrix": "projectionMatrix",
                "u_emission": "emission"
            }
        }
    }
}

A good starting point was the Appendix A of the gltf Specification which defines a default material and shaders. All I had to do was adding the scene description and the buffers.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.