--- /dev/null
+{\r
+ "buffers":[\r
+ {\r
+ "uri":"AnimatedMorphCubeQuantized.bin",\r
+ "byteLength":1700\r
+ }\r
+ ],\r
+ "asset":{\r
+ "version":"2.0",\r
+ "generator":"gltfpack 0.13"\r
+ },\r
+ "extensionsUsed":[\r
+ "KHR_mesh_quantization"\r
+ ],\r
+ "extensionsRequired":[\r
+ "KHR_mesh_quantization"\r
+ ],\r
+ "bufferViews":[\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":0,\r
+ "byteLength":288,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":288,\r
+ "byteLength":576,\r
+ "byteStride":8,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":864,\r
+ "byteLength":72,\r
+ "target":34963\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":936,\r
+ "byteLength":508\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":1444,\r
+ "byteLength":254\r
+ }\r
+ ],\r
+ "accessors":[\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":0,\r
+ "componentType":5120,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 5451,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 5481,\r
+ 10932,\r
+ 5481\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":96,\r
+ "componentType":5120,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":192,\r
+ "componentType":5122,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 0,\r
+ 5188,\r
+ 0\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":192,\r
+ "componentType":5120,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":384,\r
+ "componentType":5122,\r
+ "count":24,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 0,\r
+ 5451,\r
+ 0\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":2,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":36,\r
+ "type":"SCALAR"\r
+ },\r
+ {\r
+ "bufferView":3,\r
+ "byteOffset":0,\r
+ "componentType":5126,\r
+ "count":127,\r
+ "type":"SCALAR",\r
+ "min":[\r
+ 0\r
+ ],\r
+ "max":[\r
+ 4.19999981\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":4,\r
+ "byteOffset":0,\r
+ "componentType":5121,\r
+ "count":254,\r
+ "type":"SCALAR",\r
+ "normalized":true\r
+ }\r
+ ],\r
+ "materials":[\r
+ {\r
+ "name":"Material",\r
+ "pbrMetallicRoughness":{\r
+ "baseColorFactor":[\r
+ 0.603827417,\r
+ 0.603827417,\r
+ 0.603827417,\r
+ 1\r
+ ],\r
+ "metallicFactor":0,\r
+ "roughnessFactor":0.5\r
+ }\r
+ }\r
+ ],\r
+ "meshes":[\r
+ {\r
+ "primitives":[\r
+ {\r
+ "attributes":{\r
+ "NORMAL":0,\r
+ "POSITION":1\r
+ },\r
+ "mode":4,\r
+ "targets":[\r
+ {\r
+ "NORMAL":2,\r
+ "POSITION":3\r
+ },\r
+ {\r
+ "NORMAL":4,\r
+ "POSITION":5\r
+ }\r
+ ],\r
+ "indices":6,\r
+ "material":0\r
+ }\r
+ ],\r
+ "weights":[\r
+ 0,\r
+ 0\r
+ ]\r
+ }\r
+ ],\r
+ "animations":[\r
+ {\r
+ "name":"Square",\r
+ "samplers":[\r
+ {\r
+ "input":7,\r
+ "output":8\r
+ }\r
+ ],\r
+ "channels":[\r
+ {\r
+ "sampler":0,\r
+ "target":{\r
+ "node":0,\r
+ "path":"weights"\r
+ }\r
+ }\r
+ ]\r
+ }\r
+ ],\r
+ "nodes":[\r
+ {\r
+ "mesh":0,\r
+ "translation":[\r
+ -0.0100000044,\r
+ -0.0298908409,\r
+ -0.00999999978\r
+ ],\r
+ "scale":[\r
+ 3.64900689e-06,\r
+ 3.64900689e-06,\r
+ 3.64900689e-06\r
+ ]\r
+ },\r
+ {\r
+ "name":"AnimatedMorphCube",\r
+ "rotation":[\r
+ 0,\r
+ 0.707106709,\r
+ -0.707106829,\r
+ 0\r
+ ],\r
+ "scale":[\r
+ 100,\r
+ 100,\r
+ 100\r
+ ],\r
+ "children":[\r
+ 0\r
+ ]\r
+ }\r
+ ],\r
+ "scenes":[\r
+ {\r
+ "nodes":[\r
+ 1\r
+ ]\r
+ }\r
+ ],\r
+ "scene":0\r
+}\r
--- /dev/null
+{\r
+ "buffers":[\r
+ {\r
+ "uri":"AvocadoQuantized.bin",\r
+ "byteLength":12212\r
+ }\r
+ ],\r
+ "asset":{\r
+ "version":"2.0",\r
+ "generator":"gltfpack 0.13"\r
+ },\r
+ "extensionsUsed":[\r
+ "KHR_mesh_quantization",\r
+ "KHR_texture_transform"\r
+ ],\r
+ "extensionsRequired":[\r
+ "KHR_mesh_quantization"\r
+ ],\r
+ "bufferViews":[\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":0,\r
+ "byteLength":1624,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":1624,\r
+ "byteLength":1624,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":3248,\r
+ "byteLength":1624,\r
+ "byteStride":4,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":4872,\r
+ "byteLength":3248,\r
+ "byteStride":8,\r
+ "target":34962\r
+ },\r
+ {\r
+ "buffer":0,\r
+ "byteOffset":8120,\r
+ "byteLength":4092,\r
+ "target":34963\r
+ }\r
+ ],\r
+ "accessors":[\r
+ {\r
+ "bufferView":0,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":406,\r
+ "type":"VEC2"\r
+ },\r
+ {\r
+ "bufferView":1,\r
+ "byteOffset":0,\r
+ "componentType":5120,\r
+ "count":406,\r
+ "type":"VEC3",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":2,\r
+ "byteOffset":0,\r
+ "componentType":5120,\r
+ "count":406,\r
+ "type":"VEC4",\r
+ "normalized":true\r
+ },\r
+ {\r
+ "bufferView":3,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":406,\r
+ "type":"VEC3",\r
+ "min":[\r
+ 0,\r
+ 0,\r
+ 0\r
+ ],\r
+ "max":[\r
+ 11086,\r
+ 16383,\r
+ 7194\r
+ ]\r
+ },\r
+ {\r
+ "bufferView":4,\r
+ "byteOffset":0,\r
+ "componentType":5123,\r
+ "count":2046,\r
+ "type":"SCALAR"\r
+ }\r
+ ],\r
+ "images":[\r
+ {\r
+ "uri":"Avocado_baseColor.png"\r
+ },\r
+ {\r
+ "uri":"Avocado_roughnessMetallic.png"\r
+ },\r
+ {\r
+ "uri":"Avocado_normal.png"\r
+ }\r
+ ],\r
+ "textures":[\r
+ {\r
+ "source":0\r
+ },\r
+ {\r
+ "source":1\r
+ },\r
+ {\r
+ "source":2\r
+ }\r
+ ],\r
+ "materials":[\r
+ {\r
+ "name":"2256_Avocado_d",\r
+ "pbrMetallicRoughness":{\r
+ "baseColorTexture":{\r
+ "index":0,\r
+ "texCoord":0,\r
+ "extensions":{\r
+ "KHR_texture_transform":{\r
+ "offset":[\r
+ 0.00678020436,\r
+ 0.00298196077\r
+ ],\r
+ "scale":[\r
+ 0.000238270484,\r
+ 0.000242341906\r
+ ]\r
+ }\r
+ }\r
+ },\r
+ "metallicRoughnessTexture":{\r
+ "index":1,\r
+ "texCoord":0,\r
+ "extensions":{\r
+ "KHR_texture_transform":{\r
+ "offset":[\r
+ 0.00678020436,\r
+ 0.00298196077\r
+ ],\r
+ "scale":[\r
+ 0.000238270484,\r
+ 0.000242341906\r
+ ]\r
+ }\r
+ }\r
+ }\r
+ },\r
+ "normalTexture":{\r
+ "index":2,\r
+ "texCoord":0,\r
+ "extensions":{\r
+ "KHR_texture_transform":{\r
+ "offset":[\r
+ 0.00678020436,\r
+ 0.00298196077\r
+ ],\r
+ "scale":[\r
+ 0.000238270484,\r
+ 0.000242341906\r
+ ]\r
+ }\r
+ }\r
+ }\r
+ }\r
+ ],\r
+ "meshes":[\r
+ {\r
+ "primitives":[\r
+ {\r
+ "attributes":{\r
+ "TEXCOORD_0":0,\r
+ "NORMAL":1,\r
+ "TANGENT":2,\r
+ "POSITION":3\r
+ },\r
+ "mode":4,\r
+ "indices":4,\r
+ "material":0\r
+ }\r
+ ]\r
+ }\r
+ ],\r
+ "nodes":[\r
+ {\r
+ "mesh":0,\r
+ "translation":[\r
+ -0.0212809108,\r
+ -4.77385511e-05,\r
+ -0.0138090011\r
+ ],\r
+ "scale":[\r
+ 3.839089e-06,\r
+ 3.839089e-06,\r
+ 3.839089e-06\r
+ ]\r
+ }\r
+ ],\r
+ "scenes":[\r
+ {\r
+ "nodes":[\r
+ 0\r
+ ]\r
+ }\r
+ ],\r
+ "scene":0\r
+}\r
--- /dev/null
+{
+ "buffers": [
+ {
+ "uri": "CesiumMilkTruckQuantized.bin",
+ "byteLength": 93032
+ }
+ ],
+ "asset": {
+ "version": "2.0",
+ "generator": "gltfpack 0.18"
+ },
+ "extensionsUsed": [
+ "KHR_mesh_quantization",
+ "KHR_texture_transform"
+ ],
+ "extensionsRequired": [
+ "KHR_mesh_quantization"
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 31328,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 31328,
+ "byteLength": 31328,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 62656,
+ "byteLength": 12460,
+ "byteStride": 4,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 75116,
+ "byteLength": 17136,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 92252,
+ "byteLength": 156
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 92408,
+ "byteLength": 624
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 786,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 105,
+ 18,
+ 113
+ ],
+ "max": [
+ 150,
+ 129,
+ 158
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5122,
+ "count": 786,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 786,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 2304,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 6288,
+ "componentType": 5123,
+ "count": 2329,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 255,
+ 146,
+ 121
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 6288,
+ "componentType": 5122,
+ "count": 2329,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 3144,
+ "componentType": 5123,
+ "count": 2329,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 4608,
+ "componentType": 5123,
+ "count": 5232,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 24920,
+ "componentType": 5123,
+ "count": 151,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 139,
+ 0,
+ 12
+ ],
+ "max": [
+ 211,
+ 146,
+ 50
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 24920,
+ "componentType": 5122,
+ "count": 151,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 15072,
+ "componentType": 5123,
+ "count": 168,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 26128,
+ "componentType": 5123,
+ "count": 650,
+ "type": "VEC3",
+ "normalized": true,
+ "min": [
+ 137,
+ 15,
+ 10
+ ],
+ "max": [
+ 212,
+ 131,
+ 52
+ ]
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 26128,
+ "componentType": 5122,
+ "count": 650,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 15408,
+ "componentType": 5123,
+ "count": 864,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 39,
+ "type": "SCALAR",
+ "min": [
+ 0
+ ],
+ "max": [
+ 1.26666677
+ ]
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 0,
+ "componentType": 5122,
+ "count": 39,
+ "type": "VEC4",
+ "normalized": true
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 312,
+ "componentType": 5122,
+ "count": 39,
+ "type": "VEC4",
+ "normalized": true
+ }
+ ],
+ "images": [
+ {
+ "uri": "CesiumMilkTruck.jpg"
+ }
+ ],
+ "textures": [
+ {
+ "source": 0
+ },
+ {
+ "source": 0
+ }
+ ],
+ "materials": [
+ {
+ "name": "wheels",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.605093002,
+ 0.00905001163
+ ],
+ "scale": [
+ 99.8609467,
+ 251.995087
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "truck",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 1,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.00295638992,
+ 0.0156720281
+ ],
+ "scale": [
+ 229.629913,
+ 252.264313
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "glass",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0,
+ 0.0405062996,
+ 0.0212407,
+ 1
+ ],
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "window_trim",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.064000003,
+ 0.064000003,
+ 0.064000003,
+ 1
+ ],
+ "metallicFactor": 0
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "NORMAL": 1,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 0
+ }
+ ]
+ },
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 4,
+ "NORMAL": 5,
+ "TEXCOORD_0": 6
+ },
+ "indices": 7,
+ "material": 1
+ },
+ {
+ "attributes": {
+ "POSITION": 8,
+ "NORMAL": 9
+ },
+ "indices": 10,
+ "material": 2
+ },
+ {
+ "attributes": {
+ "POSITION": 11,
+ "NORMAL": 12
+ },
+ "indices": 13,
+ "material": 3
+ }
+ ]
+ }
+ ],
+ "animations": [
+ {
+ "name": "Wheels",
+ "samplers": [
+ {
+ "input": 14,
+ "output": 15
+ },
+ {
+ "input": 14,
+ "output": 16
+ }
+ ],
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 3,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 5,
+ "path": "rotation"
+ }
+ }
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "mesh": 0,
+ "translation": [
+ -2.43091011,
+ -1.39600003,
+ -2.5843699
+ ],
+ "scale": [
+ 1251.30994,
+ 1251.30994,
+ 1251.30994
+ ]
+ },
+ {
+ "mesh": 0,
+ "translation": [
+ -2.43091011,
+ -1.39600003,
+ -2.5843699
+ ],
+ "scale": [
+ 1251.30994,
+ 1251.30994,
+ 1251.30994
+ ]
+ },
+ {
+ "mesh": 1,
+ "translation": [
+ -2.43091011,
+ -1.39600003,
+ -2.5843699
+ ],
+ "scale": [
+ 1251.30994,
+ 1251.30994,
+ 1251.30994
+ ]
+ },
+ {
+ "name": "Wheels",
+ "rotation": [
+ 0,
+ 0.0884858891,
+ 0,
+ -0.996077418
+ ],
+ "children": [
+ 0
+ ]
+ },
+ {
+ "name": "Node",
+ "translation": [
+ 1.43267,
+ 0,
+ -0.427722007
+ ],
+ "children": [
+ 3
+ ]
+ },
+ {
+ "name": "Wheels.001",
+ "rotation": [
+ 0,
+ 0.0884858891,
+ 0,
+ -0.996077418
+ ],
+ "children": [
+ 1
+ ]
+ },
+ {
+ "name": "Node.001",
+ "translation": [
+ -1.35232997,
+ 0,
+ -0.427722007
+ ],
+ "children": [
+ 5
+ ]
+ },
+ {
+ "name": "Cesium_Milk_Truck",
+ "children": [
+ 4,
+ 6,
+ 2
+ ]
+ },
+ {
+ "name": "Yup2Zup",
+ "rotation": [
+ 0.49999997,
+ -0.5,
+ 0.5,
+ 0.49999997
+ ],
+ "children": [
+ 7
+ ]
+ }
+ ],
+ "scenes": [
+ {
+ "name": "Scene",
+ "nodes": [
+ 8
+ ]
+ }
+ ],
+ "scene": 0
+}
--- /dev/null
+{
+ "buffers": [
+ {
+ "uri": "MorphPrimitivesTestQuantized.bin",
+ "byteLength": 912
+ }
+ ],
+ "asset": {
+ "version": "2.0",
+ "generator": "gltfpack 0.18",
+ "extras": {
+ "title": "multiple_primitives",
+ "author": "ft-lab",
+ "license": "CC BY-4.0 (https://creativecommons.org/licenses/by/4.0/)"
+ }
+ },
+ "extensionsUsed": [
+ "KHR_mesh_quantization",
+ "KHR_texture_transform"
+ ],
+ "extensionsRequired": [
+ "KHR_mesh_quantization"
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 240,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 240,
+ "byteLength": 240,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 480,
+ "byteLength": 120,
+ "byteStride": 4,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 600,
+ "byteLength": 120,
+ "byteStride": 4,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 720,
+ "byteLength": 192,
+ "target": 34963
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5122,
+ "count": 21,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 21,
+ "type": "VEC3",
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 1,
+ 0,
+ 1
+ ]
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 21,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 0,
+ "componentType": 5120,
+ "count": 21,
+ "type": "VEC3",
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 0,
+ 0,
+ 0
+ ]
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 72,
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 168,
+ "componentType": 5123,
+ "count": 9,
+ "type": "VEC3",
+ "min": [
+ 1,
+ 0,
+ 0
+ ],
+ "max": [
+ 1,
+ 0,
+ 1
+ ]
+ },
+ {
+ "bufferView": 0,
+ "byteOffset": 168,
+ "componentType": 5122,
+ "count": 9,
+ "type": "VEC3",
+ "normalized": true
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 84,
+ "componentType": 5123,
+ "count": 9,
+ "type": "VEC2",
+ "normalized": true
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 84,
+ "componentType": 5120,
+ "count": 9,
+ "type": "VEC3",
+ "min": [
+ 0,
+ 0,
+ 0
+ ],
+ "max": [
+ 0,
+ 0,
+ 0
+ ]
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 144,
+ "componentType": 5123,
+ "count": 24,
+ "type": "SCALAR"
+ }
+ ],
+ "samplers": [
+ {
+ "minFilter": 9729
+ }
+ ],
+ "images": [
+ {
+ "uri": "uv_texture.jpg"
+ }
+ ],
+ "textures": [
+ {
+ "sampler": 0,
+ "source": 0
+ }
+ ],
+ "materials": [
+ {
+ "name": "red",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 1,
+ 0,
+ 0,
+ 1
+ ],
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0,
+ 0
+ ],
+ "scale": [
+ 65535,
+ 65535
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "green",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0,
+ 1,
+ 0,
+ 1
+ ],
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0,
+ 0
+ ],
+ "scale": [
+ 32767.5,
+ 32767.5
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 0,
+ "POSITION": 1,
+ "TEXCOORD_0": 2
+ },
+ "targets": [
+ {
+ "POSITION": 3
+ }
+ ],
+ "indices": 4,
+ "material": 0
+ },
+ {
+ "attributes": {
+ "POSITION": 5,
+ "NORMAL": 6,
+ "TEXCOORD_0": 7
+ },
+ "targets": [
+ {
+ "POSITION": 8
+ }
+ ],
+ "indices": 9,
+ "material": 1
+ }
+ ],
+ "weights": [
+ 0.5
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "mesh": 0,
+ "translation": [
+ -0.5,
+ -0.400000006,
+ -0.5
+ ],
+ "scale": [
+ 1,
+ 1,
+ 1
+ ]
+ },
+ {
+ "name": "ルートパート",
+ "children": [
+ 2
+ ]
+ },
+ {
+ "name": "mesh",
+ "children": [
+ 0
+ ]
+ }
+ ],
+ "scenes": [
+ {
+ "name": "Scene",
+ "nodes": [
+ 1
+ ]
+ }
+ ],
+ "scene": 0
+}
--- /dev/null
+{\r
+ "scene" : 0,\r
+ "scenes" : [\r
+ {\r
+ "nodes" : [ 0, 1]\r
+ }\r
+ ],\r
+ "nodes" : [\r
+ {\r
+ "mesh" : 0\r
+ },\r
+ {\r
+ "mesh" : 0,\r
+ "translation" : [ 1.0, 0.0, 0.0 ]\r
+ }\r
+ ],\r
+\r
+ "meshes" : [\r
+ {\r
+ "primitives" : [ {\r
+ "attributes" : {\r
+ "POSITION" : 1,\r
+ "NORMAL" : 2\r
+ },\r
+ "indices" : 0\r
+ } ]\r
+ }\r
+ ],\r
+\r
+ "buffers" : [\r
+ {\r
+ "uri" : "UnsupportedExtension.bin",\r
+ "byteLength" : 80\r
+ }\r
+ ],\r
+ "bufferViews" : [\r
+ {\r
+ "buffer" : 0,\r
+ "byteOffset" : 0,\r
+ "byteLength" : 6,\r
+ "target" : 34963\r
+ },\r
+ {\r
+ "buffer" : 0,\r
+ "byteOffset" : 8,\r
+ "byteLength" : 72,\r
+ "byteStride" : 12,\r
+ "target" : 34962\r
+ }\r
+ ],\r
+ "accessors" : [\r
+ {\r
+ "bufferView" : 0,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5123,\r
+ "count" : 3,\r
+ "type" : "SCALAR",\r
+ "max" : [ 2 ],\r
+ "min" : [ 0 ]\r
+ },\r
+ {\r
+ "bufferView" : 1,\r
+ "byteOffset" : 0,\r
+ "componentType" : 5126,\r
+ "count" : 3,\r
+ "type" : "VEC3",\r
+ "max" : [ 1.0, 1.0, 0.0 ],\r
+ "min" : [ 0.0, 0.0, 0.0 ]\r
+ },\r
+ {\r
+ "bufferView" : 1,\r
+ "byteOffset" : 36,\r
+ "componentType" : 5126,\r
+ "count" : 3,\r
+ "type" : "VEC3",\r
+ "max" : [ 0.0, 0.0, 1.0 ],\r
+ "min" : [ 0.0, 0.0, 1.0 ]\r
+ }\r
+ ],\r
+ "asset" : {\r
+ "version" : "2.0"\r
+ },\r
+ "extensionsUsed": [\r
+ "KHR_invalid_extension"\r
+ ],\r
+ "extensionsRequired": [\r
+ "KHR_invalid_extension"\r
+ ]\r
+}\r
{
struct Context
{
- ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type)
- {
+ ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
return TEST_RESOURCE_DIR "/";
};
} // namespace
-int UtcDaliGltfLoaderFailedToLoad(void)
+int UtcDaliGltfLoaderFailedToLoad1(void)
{
Context ctx;
END_TEST;
}
+int UtcDaliGltfLoaderFailedToLoad2(void)
+{
+ Context ctx;
+
+ try
+ {
+ DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/UnsupportedExtension.gltf", ctx.loadResult), false);
+ }
+ catch(...)
+ {
+ printf("Unsupported glTF extension required.\n");
+ }
+
+ DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
+ DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
+
+ DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
+ DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
+
+ DALI_TEST_EQUAL(0, ctx.cameras.size());
+ DALI_TEST_EQUAL(0, ctx.lights.size());
+ DALI_TEST_EQUAL(0, ctx.animations.size());
+ DALI_TEST_EQUAL(0, ctx.animationGroups.size());
+
+ END_TEST;
+}
+
int UtcDaliGltfLoaderFailedToParse(void)
{
Context ctx;
auto& materials = ctx.resources.mMaterials;
DALI_TEST_EQUAL(2u, materials.size());
const MaterialDefinition materialGroundTruth[]{
- {
- nullptr,
- MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
- MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
- MaterialDefinition::GLTF_CHANNELS | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
- 0,
- Color::WHITE,
- 1.f,
- 0.f,
- Vector4(1.000, 0.766, 0.336, 1.0),
- 1.f,
- 1.f,
- Vector3(0.2, 0.1, 0.0),
- 1.0f,
- 0.0f,
- 0.5f,
- Vector3(0, 0, 1),
- true,
- false,
- true,
- false,
- Scene3D::Material::AlphaModeType::MASK,
- true,
- true,
- true,
- {
- {
- MaterialDefinition::ALBEDO,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::NORMAL,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::OCCLUSION,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::EMISSIVE,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::SPECULAR,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- {
- MaterialDefinition::SPECULAR_COLOR,
- {
- "AnimatedCube_BaseColor.png",
- SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
- ImageDimensions(256, 256),
- SamplingMode::BOX_THEN_NEAREST,
- },
- },
- },
- nullptr
- },
+ {nullptr,
+ MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
+ MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
+ MaterialDefinition::GLTF_CHANNELS | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
+ 0,
+ Color::WHITE,
+ 1.f,
+ 0.f,
+ Vector4(1.000, 0.766, 0.336, 1.0),
+ 1.f,
+ 1.f,
+ Vector3(0.2, 0.1, 0.0),
+ 1.0f,
+ 0.0f,
+ 0.5f,
+ Vector3(0, 0, 1),
+ true,
+ false,
+ true,
+ false,
+ Scene3D::Material::AlphaModeType::MASK,
+ true,
+ true,
+ true,
+ {
+ {
+ MaterialDefinition::ALBEDO,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::NORMAL,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::OCCLUSION,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::EMISSIVE,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::SPECULAR,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ {
+ MaterialDefinition::SPECULAR_COLOR,
+ {
+ "AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+ ImageDimensions(256, 256),
+ SamplingMode::BOX_THEN_NEAREST,
+ },
+ },
+ },
+ nullptr},
{
nullptr,
MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
int UtcDaliGltfLoaderSuccess2(void)
{
- Context ctx;
+ Context ctx;
ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", ctx.loadResult);
TestApplication app;
const std::string resourcePath = TEST_RESOURCE_DIR "/";
- auto pathProvider = [resourcePath](ResourceType::Value)
- {
+ auto pathProvider = [resourcePath](ResourceType::Value) {
return resourcePath;
};
"MRendererTest",
"SimpleSparseAccessor",
"AnimatedCube",
+ /**
+ * For the Avocado glTF file and its Assets
+ * Donated by Microsoft for glTF testing
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
+ */
+ "AvocadoQuantized",
+ /**
+ * For the AnimatedMorphCube glTF file and its Assets
+ * Donated by Microsoft for glTF testing
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/AnimatedMorphCube/glTF-Quantized
+ */
+ "AnimatedMorphCubeQuantized",
+ /**
+ * For the MorphPrimitivesTest glTF file and its Assets
+ * Created by @ft-lab
+ * Licensed under the terms of the CC BY 4.0 license: https://creativecommons.org/licenses/by/4.0/
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/MorphPrimitivesTest/glTF
+ * Modified using gltfpack 0.18.
+ */
+ "MorphPrimitivesTestQuantized",
+ /**
+ * For the CesiumMilkTruck glTF file and its Assets
+ * Donated by Cesium for glTF testing
+ * Licensed under the terms of the CC BY 4.0 license: http://creativecommons.org/licenses/by/4.0/
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/CesiumMilkTruck/glTF
+ * Modified using gltfpack 0.18.
+ */
+ "CesiumMilkTruckQuantized",
})
{
Context ctx;
int UtcDaliGltfLoaderMRendererTest(void)
{
Context ctx;
- auto& resources = ctx.resources;
+ auto& resources = ctx.resources;
ctx.loader.LoadModel(TEST_RESOURCE_DIR "/MRendererTest.gltf", ctx.loadResult);
DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
int UtcDaliGltfLoaderAnimationLoadingTest(void)
{
TestApplication app;
- Context ctx;
+ Context ctx;
auto& resources = ctx.resources;
DALI_TEST_EQUAL(roots.size(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
DALI_TEST_EQUAL(roots.size(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
DALI_TEST_EQUAL(roots.size(), 1u);
Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
- ViewProjection viewProjection;
- Transforms xforms{
+ ViewProjection viewProjection;
+ Transforms xforms{
MatrixStack{},
viewProjection};
NodeDefinition::CreateParams nodeParams{
END_TEST;
}
+
+int UtcDaliGltfLoaderQuantizedMesh(void)
+{
+ Context ctx;
+
+ auto& resources = ctx.resources;
+
+ /**
+ * For the Avocado glTF file and its Assets
+ * Donated by Microsoft for glTF testing
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
+ */
+ ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AvocadoQuantized.gltf", ctx.loadResult);
+
+ auto& scene = ctx.scene;
+ DALI_TEST_EQUAL(1u, scene.GetRoots().size());
+ DALI_TEST_EQUAL(1u, scene.GetNodeCount());
+
+ auto& roots = scene.GetRoots();
+ DALI_TEST_EQUAL(roots.size(), 1u);
+
+ Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
+ ViewProjection viewProjection;
+ Transforms xforms{
+ MatrixStack{},
+ viewProjection};
+ NodeDefinition::CreateParams nodeParams{
+ resources,
+ xforms,
+ shaderManager,
+ };
+
+ Customization::Choices choices;
+
+ TestApplication app;
+
+ Actor root = Actor::New();
+ SetActorCentered(root);
+ for(auto iRoot : roots)
+ {
+ auto resourceRefs = resources.CreateRefCounter();
+ scene.CountResourceRefs(iRoot, choices, resourceRefs);
+ resources.mReferenceCounts = std::move(resourceRefs);
+ resources.CountEnvironmentReferences();
+ resources.LoadResources(ctx.pathProvider);
+ if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+ {
+ scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+ scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+ root.Add(actor);
+ }
+ }
+
+ auto& meshes = ctx.resources.mMeshes;
+ DALI_TEST_EQUAL(1u, meshes.size());
+
+ auto& md = meshes[0u].first;
+
+ DALI_TEST_EQUAL(MeshDefinition::Flags::U16_POSITION | MeshDefinition::Flags::S8_NORMAL | MeshDefinition::Flags::S8_TANGENT | MeshDefinition::Flags::U16_TEXCOORD, md.mFlags);
+
+ DALI_TEST_EQUAL(true, md.mPositions.IsDefined());
+ DALI_TEST_EQUAL(false, md.mPositions.mNormalized);
+ DALI_TEST_EQUAL(sizeof(uint16_t) * 3, md.mPositions.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mPositions.mBlob.IsDefined());
+ DALI_TEST_EQUAL(2436, md.mPositions.mBlob.mLength);
+ DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[0]);
+ DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[1]);
+ DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[2]);
+ DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMax.size());
+ DALI_TEST_EQUAL(11086.0f, md.mPositions.mBlob.mMax[0]);
+ DALI_TEST_EQUAL(16383.0f, md.mPositions.mBlob.mMax[1]);
+ DALI_TEST_EQUAL(7194.0f, md.mPositions.mBlob.mMax[2]);
+
+ DALI_TEST_EQUAL(true, md.mNormals.IsDefined());
+ DALI_TEST_EQUAL(true, md.mNormals.mNormalized);
+ DALI_TEST_EQUAL(sizeof(int8_t) * 3, md.mNormals.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mNormals.mBlob.IsDefined());
+ DALI_TEST_EQUAL(1218, md.mNormals.mBlob.mLength);
+ DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMax.size());
+
+ DALI_TEST_EQUAL(true, md.mTangents.IsDefined());
+ DALI_TEST_EQUAL(true, md.mTangents.mNormalized);
+ DALI_TEST_EQUAL(Property::VECTOR4, md.mTangentType);
+ DALI_TEST_EQUAL(sizeof(int8_t) * 4, md.mTangents.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mTangents.mBlob.IsDefined());
+ DALI_TEST_EQUAL(1624, md.mTangents.mBlob.mLength);
+ DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMax.size());
+
+ DALI_TEST_EQUAL(true, md.mTexCoords.IsDefined());
+ DALI_TEST_EQUAL(false, md.mTexCoords.mNormalized);
+ DALI_TEST_EQUAL(sizeof(uint16_t) * 2, md.mTexCoords.mBlob.mElementSizeHint);
+ DALI_TEST_EQUAL(true, md.mTexCoords.mBlob.IsDefined());
+ DALI_TEST_EQUAL(1624, md.mTexCoords.mBlob.mLength);
+ DALI_TEST_EQUAL(0u, md.mTexCoords.mBlob.mMin.size());
+ DALI_TEST_EQUAL(0u, md.mTexCoords.mBlob.mMax.size());
+
+ END_TEST;
+}
// INTERNAL INCLUDES
#include <dali-scene3d/internal/loader/json-reader.h>
#include <dali-scene3d/public-api/loader/index.h>
+#include <dali-scene3d/public-api/loader/utils.h>
#define ENUM_STRING_MAPPING(t, x) \
{ \
std::vector<Ref<Node>> mNodes;
};
+enum ExtensionFlags : uint32_t
+{
+ NONE = Dali::Scene3D::Loader::NthBit(0),
+ KHR_MESH_QUANTIZATION = Dali::Scene3D::Loader::NthBit(1), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_transform
+ KHR_TEXTURE_TRANSFORM = Dali::Scene3D::Loader::NthBit(2), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization
+ KHR_MATERIALS_IOR = Dali::Scene3D::Loader::NthBit(3), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_ior
+ KHR_MATERIALS_SPECULAR = Dali::Scene3D::Loader::NthBit(4), // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular
+
+};
+
struct Document
{
Asset mAsset;
std::vector<Animation> mAnimations;
+ std::vector<std::string_view> mExtensionsUsed;
+ std::vector<std::string_view> mExtensionsRequired;
+
+ uint32_t mExtensionFlags{0};
+
std::vector<Scene> mScenes;
Ref<Scene> mScene;
#include <dali-scene3d/internal/loader/gltf2-util.h>
// EXTERNAL INCLUDES
+#include <dali-scene3d/public-api/loader/utils.h>
+#include <dali/devel-api/scripting/scripting.h>
#include <dali/devel-api/threading/mutex.h>
#include <dali/integration-api/debug.h>
#include <limits> ///< for std::numeric_limits
{gltf2::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4)},
};
+static const Dali::Scripting::StringEnum EXTENSION_STRING_TABLE[] =
+ {
+ {"NONE", gltf2::ExtensionFlags::NONE},
+ {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
+ {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
+ {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
+ {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
+
+};
+
+static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]);
+
std::vector<gltf2::Animation> ReadAnimationArray(const json_value_s& j)
{
auto results = json::Read::Array<gltf2::Animation, json::ObjectReader<gltf2::Animation>::Read>(j);
.Register(*json::MakeProperty("animations",
ReadAnimationArray,
&gltf2::Document::mAnimations))
+ .Register(*json::MakeProperty("extensionsRequired",
+ json::Read::Array<std::string_view, json::Read::StringView>,
+ &gltf2::Document::mExtensionsRequired))
+ .Register(*json::MakeProperty("extensionsUsed",
+ json::Read::Array<std::string_view, json::Read::StringView>,
+ &gltf2::Document::mExtensionsUsed))
.Register(*json::MakeProperty("scenes",
json::Read::Array<gltf2::Scene, json::ObjectReader<gltf2::Scene>::Read>,
&gltf2::Document::mScenes))
void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
{
+ bool isQuantized = MaskMatch(document.mExtensionFlags, gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION);
+
uint32_t meshCount = 0;
context.mMeshIds.reserve(document.mMeshes.size());
for(auto& mesh : document.mMeshes)
continue;
}
- auto& accPositions = *positionIter->second;
- meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
+ auto& accPositions = *positionIter->second;
+ meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
+ meshDefinition.mPositions.mNormalized = accPositions.mNormalized;
+
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
+ meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION;
+ meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
+ meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accPositions.mComponentType == gltf2::Component::FLOAT);
+
// glTF2 support vector4 tangent for mesh.
// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
meshDefinition.mTangentType = Property::VECTOR4;
auto& accessor = meshDefinition.*(attributeMapping.mAccessor);
accessor = ConvertMeshPrimitiveAccessor(*iFind->second);
+ if(iFind->first == gltf2::Attribute::NORMAL)
+ {
+ meshDefinition.mNormals.mNormalized = iFind->second->mNormalized;
+
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || iFind->second->mComponentType == gltf2::Component::FLOAT);
+ }
+ if(iFind->first == gltf2::Attribute::TANGENT)
+ {
+ meshDefinition.mTangents.mNormalized = iFind->second->mNormalized;
+
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || iFind->second->mComponentType == gltf2::Component::FLOAT);
+ }
+ if(iFind->first == gltf2::Attribute::TEXCOORD_0 || iFind->first == gltf2::Attribute::TEXCOORD_1)
+ {
+ meshDefinition.mTexCoords.mNormalized = iFind->second->mNormalized;
+
+ if(isQuantized)
+ {
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD;
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD;
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD;
+ meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || iFind->second->mComponentType == gltf2::Component::FLOAT);
+ }
if(iFind->first == gltf2::Attribute::JOINTS_0)
{
meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
auto it = target.find(gltf2::Attribute::POSITION);
if(it != endIt)
{
- blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.deltas.mNormalized = it->second->mNormalized;
+
+ if(isQuantized)
+ {
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U16_POSITION))) || it->second->mComponentType == gltf2::Component::FLOAT);
}
it = target.find(gltf2::Attribute::NORMAL);
if(it != endIt)
{
- blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.normals.mNormalized = it->second->mNormalized;
+
+ if(isQuantized)
+ {
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))) || it->second->mComponentType == gltf2::Component::FLOAT);
}
it = target.find(gltf2::Attribute::TANGENT);
if(it != endIt)
{
- blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
+ blendShape.tangents.mNormalized = it->second->mNormalized;
+
+ if(isQuantized)
+ {
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
+ blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
+ }
+
+ DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))) || it->second->mComponentType == gltf2::Component::FLOAT);
}
if(!mesh.mWeights.empty())
void ConvertGltfToContext(gt::Document& document, Gltf2Util::ConversionContext& context, bool isMRendererModel)
{
+ for(auto& extension : document.mExtensionsRequired)
+ {
+ gltf2::ExtensionFlags flag;
+ if(Dali::Scripting::GetEnumeration<gltf2::ExtensionFlags>(extension.data(), EXTENSION_STRING_TABLE, EXTENSION_STRING_TABLE_COUNT, flag))
+ {
+ document.mExtensionFlags |= flag;
+ }
+ else
+ {
+ DALI_LOG_ERROR("Unsupported glTF extension required: %s\n", extension.data());
+ DALI_ASSERT_DEBUG(false && "Unsupported glTF extension required");
+ }
+ }
+
Gltf2Util::ConvertBuffers(document, context);
Gltf2Util::ConvertMaterials(document, context);
Gltf2Util::ConvertMeshes(document, context);
textureHeight = 1u << powHeight;
}
-void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, const std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor, BufferDefinition::Vector& buffers)
+template<typename T>
+float GetNormalizedScale()
+{
+ return 1.0f / (std::numeric_limits<T>::max());
+}
+
+template<typename T>
+void DequantizeData(std::vector<uint8_t>& buffer, float* dequantizedValues, uint32_t numValues, bool normalized)
+{
+ // see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data
+
+ T* values = reinterpret_cast<T*>(buffer.data());
+
+ for(uint32_t i = 0; i < numValues; ++i)
+ {
+ *dequantizedValues = normalized ? std::max((*values) * GetNormalizedScale<T>(), -1.0f) : *values;
+
+ values++;
+ dequantizedValues++;
+ }
+}
+
+void GetDequantizedData(std::vector<uint8_t>& buffer, uint32_t numComponents, uint32_t count, uint32_t flags, bool normalized)
+{
+ bool dequantized = false;
+
+ std::vector<uint8_t> dequantizedBuffer(count * numComponents * sizeof(float));
+ float* dequantizedValues = reinterpret_cast<float*>(dequantizedBuffer.data());
+
+ if(MaskMatch(flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S8_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S8_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S8_TEXCOORD))
+ {
+ DequantizeData<int8_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U8_TEXCOORD))
+ {
+ DequantizeData<uint8_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S16_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S16_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S16_TEXCOORD))
+ {
+ DequantizeData<int16_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U16_TEXCOORD))
+ {
+ DequantizeData<uint16_t>(buffer, dequantizedValues, numComponents * count, normalized);
+ dequantized = true;
+ }
+
+ if(dequantized)
+ {
+ buffer = std::move(dequantizedBuffer);
+ }
+}
+
+void GetDequantizedMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t flags)
+{
+ float scale = 1.0f;
+
+ if(MaskMatch(flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S8_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S8_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S8_TEXCOORD))
+ {
+ scale = GetNormalizedScale<int8_t>();
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U8_TEXCOORD))
+ {
+ scale = GetNormalizedScale<uint8_t>();
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S16_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S16_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S16_TEXCOORD))
+ {
+ scale = GetNormalizedScale<int16_t>();
+ }
+ else if(MaskMatch(flags, MeshDefinition::Flags::U16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U16_TEXCOORD))
+ {
+ scale = GetNormalizedScale<uint16_t>();
+ }
+
+ if(scale != 1.0f)
+ {
+ for(float& value : min)
+ {
+ value = std::max(value * scale, -1.0f);
+ }
+
+ for(float& value : max)
+ {
+ value = std::min(value * scale, 1.0f);
+ }
+ }
+}
+
+void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor, BufferDefinition::Vector& buffers)
{
uint32_t geometryBufferIndex = 0u;
float maxDistanceSquared = 0.f;
Vector3* geometryBufferV3 = reinterpret_cast<Vector3*>(geometryBuffer);
- for(const auto& blendShape : blendShapes)
+ for(auto& blendShape : blendShapes)
{
if(blendShape.deltas.IsDefined())
{
- DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0u) ||
- blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
- "Blend Shape position buffer length not a multiple of element size");
+ const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
+ blendShape.deltas.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
+ "Blend Shape position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
+ }
+ else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
+ blendShape.deltas.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
+ "Blend Shape position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0) ||
+ blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
+ "Blend Shape position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
- const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::vector<uint32_t> sparseIndices{};
if(ReadAccessor(blendShape.deltas, buffers[blendShape.deltas.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
{
- blendShape.deltas.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
+ GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::POSITIONS_MASK, blendShape.deltas.mNormalized);
+
+ if(blendShape.deltas.mNormalized)
+ {
+ GetDequantizedMinMax(blendShape.deltas.mBlob.mMin, blendShape.deltas.mBlob.mMax, blendShape.mFlags & MeshDefinition::POSITIONS_MASK);
+ }
+
+ blendShape.deltas.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
// Calculate the difference with the original mesh.
// Find the max distance to normalize the deltas.
if(blendShape.normals.IsDefined())
{
- DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0u) ||
- blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
- "Blend Shape normals buffer length not a multiple of element size");
+ const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+ blendShape.normals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
+ "Blend Shape normals buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
+ }
+ else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+ blendShape.normals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
+ "Blend Shape normals buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0) ||
+ blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
+ "Blend Shape normals buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
- const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::vector<uint32_t> sparseIndices;
if(ReadAccessor(blendShape.normals, buffers[blendShape.normals.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
{
- blendShape.normals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
+ GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::NORMALS_MASK, blendShape.normals.mNormalized);
+
+ if(blendShape.normals.mNormalized)
+ {
+ GetDequantizedMinMax(blendShape.normals.mBlob.mMin, blendShape.normals.mBlob.mMax, blendShape.mFlags & MeshDefinition::NORMALS_MASK);
+ }
+
+ blendShape.normals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
// Calculate the difference with the original mesh, and translate to make all values positive.
const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
if(blendShape.tangents.IsDefined())
{
- DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0u) ||
- blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
- "Blend Shape tangents buffer length not a multiple of element size");
+ const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
+
+ uint32_t numVector3;
+
+ if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+ blendShape.tangents.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
+ "Blend Shape tangents buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
+ }
+ else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+ blendShape.tangents.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
+ "Blend Shape tangents buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0) ||
+ blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
+ "Blend Shape tangents buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
- const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
std::vector<uint8_t> buffer(bufferSize);
std::vector<uint32_t> sparseIndices;
if(ReadAccessor(blendShape.tangents, buffers[blendShape.tangents.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
{
- blendShape.tangents.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
+ GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::TANGENTS_MASK, blendShape.tangents.mNormalized);
+
+ if(blendShape.tangents.mNormalized)
+ {
+ GetDequantizedMinMax(blendShape.tangents.mBlob.mMin, blendShape.tangents.mBlob.mMax, blendShape.mFlags & MeshDefinition::TANGENTS_MASK);
+ }
+
+ blendShape.tangents.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
// Calculate the difference with the original mesh, and translate to make all values positive.
const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
}
}
+ uint32_t numberOfVertices = 0u;
+
std::vector<Vector3> positions;
if(mPositions.IsDefined())
{
- DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
- mPositions.mBlob.mStride >= sizeof(Vector3)) &&
- "Position buffer length not a multiple of element size");
- const auto bufferSize = mPositions.mBlob.GetBufferSize();
+ const auto bufferSize = mPositions.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(mFlags, S8_POSITION) || MaskMatch(mFlags, U8_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
+ mPositions.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
+ "Position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
+ }
+ else if(MaskMatch(mFlags, S16_POSITION) || MaskMatch(mFlags, U16_POSITION))
+ {
+ DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
+ mPositions.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
+ "Position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
+ mPositions.mBlob.mStride >= sizeof(Vector3)) &&
+ "Position buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
+
+ numberOfVertices = numVector3;
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
}
- uint32_t numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ GetDequantizedData(buffer, 3u, numVector3, mFlags & POSITIONS_MASK, mPositions.mNormalized);
+
+ if(mPositions.mNormalized)
+ {
+ GetDequantizedMinMax(mPositions.mBlob.mMin, mPositions.mBlob.mMax, mFlags & POSITIONS_MASK);
+ }
+
if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
{
mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
auto hasNormals = mNormals.IsDefined();
if(hasNormals)
{
- DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
- mNormals.mBlob.mStride >= sizeof(Vector3)) &&
- "Normal buffer length not a multiple of element size");
- const auto bufferSize = mNormals.mBlob.GetBufferSize();
+ const auto bufferSize = mNormals.mBlob.GetBufferSize();
+ uint32_t numVector3;
+
+ if(MaskMatch(mFlags, S8_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
+ mNormals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
+ "Normal buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
+ }
+ else if(MaskMatch(mFlags, S16_NORMAL))
+ {
+ DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
+ mNormals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
+ "Normal buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
+ mNormals.mBlob.mStride >= sizeof(Vector3)) &&
+ "Normal buffer length not a multiple of element size");
+ numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
+ }
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
}
- mNormals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()));
+ GetDequantizedData(buffer, 3u, numVector3, mFlags & NORMALS_MASK, mNormals.mNormalized);
- raw.mAttribs.push_back({"aNormal", Property::VECTOR3, static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer)});
+ if(mNormals.mNormalized)
+ {
+ GetDequantizedMinMax(mNormals.mBlob.mMin, mNormals.mBlob.mMax, mFlags & NORMALS_MASK);
+ }
+
+ mNormals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
+
+ raw.mAttribs.push_back({"aNormal", Property::VECTOR3, numVector3, std::move(buffer)});
}
else if(mNormals.mBlob.mLength != 0 && isTriangles)
{
const auto hasUvs = mTexCoords.IsDefined();
if(hasUvs)
{
- DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
- mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
- "Normal buffer length not a multiple of element size");
- const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
+ const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
+
+ uint32_t uvCount;
+
+ if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, U8_TEXCOORD))
+ {
+ DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) ||
+ mTexCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) &&
+ "TexCoords buffer length not a multiple of element size");
+ uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 2));
+ }
+ else if(MaskMatch(mFlags, S16_TEXCOORD) || MaskMatch(mFlags, U16_TEXCOORD))
+ {
+ DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
+ mTexCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
+ "TexCoords buffer length not a multiple of element size");
+ uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 2));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
+ mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
+ "TexCoords buffer length not a multiple of element size");
+ uvCount = static_cast<uint32_t>(bufferSize / sizeof(Vector2));
+ }
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
}
- const auto uvCount = bufferSize / sizeof(Vector2);
+ GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, mTexCoords.mNormalized);
+
if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
{
auto uv = reinterpret_cast<Vector2*>(buffer.data());
}
}
+ if(mTexCoords.mNormalized)
+ {
+ GetDequantizedMinMax(mTexCoords.mBlob.mMin, mTexCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK);
+ }
+
mTexCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
if(mTangents.IsDefined())
{
- uint32_t propertySize = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
- DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
- mTangents.mBlob.mStride >= propertySize) &&
- "Tangents buffer length not a multiple of element size");
- const auto bufferSize = mTangents.mBlob.GetBufferSize();
+ const auto bufferSize = mTangents.mBlob.GetBufferSize();
+
+ uint32_t propertySize = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
+ uint32_t componentCount = static_cast<uint32_t>(propertySize / sizeof(float));
+
+ uint32_t numTangents;
+
+ if(MaskMatch(mFlags, S8_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int8_t) * componentCount) == 0) ||
+ mTangents.mBlob.mStride >= (sizeof(int8_t) * componentCount)) &&
+ "Tangents buffer length not a multiple of element size");
+ numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * componentCount));
+ }
+ else if(MaskMatch(mFlags, S16_TANGENT))
+ {
+ DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int16_t) * componentCount) == 0) ||
+ mTangents.mBlob.mStride >= (sizeof(int16_t) * componentCount)) &&
+ "Tangents buffer length not a multiple of element size");
+ numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * componentCount));
+ }
+ else
+ {
+ DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
+ mTangents.mBlob.mStride >= propertySize) &&
+ "Tangents buffer length not a multiple of element size");
+ numTangents = static_cast<uint32_t>(bufferSize / propertySize);
+ }
+
std::vector<uint8_t> buffer(bufferSize);
std::string path;
{
ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
}
- mTangents.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
- raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
+ GetDequantizedData(buffer, componentCount, numTangents, mFlags & TANGENTS_MASK, mTangents.mNormalized);
+
+ if(mTangents.mNormalized)
+ {
+ GetDequantizedMinMax(mTangents.mBlob.mMin, mTangents.mBlob.mMax, mFlags & TANGENTS_MASK);
+ }
+
+ mTangents.mBlob.ApplyMinMax(numTangents, reinterpret_cast<float*>(buffer.data()));
+
+ raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(numTangents), std::move(buffer)});
}
else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
{
blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
blendShapesBlob.mLength = 0u;
- for(const auto& blendShape : mBlendShapes)
- {
- for(auto i : {&blendShape.deltas, &blendShape.normals, &blendShape.tangents})
+ uint32_t totalTextureSize(0u);
+
+ auto processAccessor = [&](const Accessor& accessor, uint32_t vector3Size) {
+ if(accessor.IsDefined())
{
- if(i->IsDefined())
- {
- blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, i->mBlob.mOffset);
- blendShapesBlob.mLength += i->mBlob.mLength;
- }
+ blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, accessor.mBlob.mOffset);
+ blendShapesBlob.mLength += accessor.mBlob.mLength;
+
+ totalTextureSize += accessor.mBlob.mLength / vector3Size;
}
+ };
+
+ for(const auto& blendShape : mBlendShapes)
+ {
+ const auto positionMask = blendShape.mFlags & POSITIONS_MASK;
+ const auto normalMask = blendShape.mFlags & NORMALS_MASK;
+ const auto tangentMask = blendShape.mFlags & TANGENTS_MASK;
+
+ processAccessor(blendShape.deltas, MaskMatch(positionMask, S8_POSITION) ? sizeof(uint8_t) * 3 : (MaskMatch(positionMask, S16_POSITION) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
+ processAccessor(blendShape.normals, MaskMatch(normalMask, S8_NORMAL) ? sizeof(uint8_t) * 3 : (MaskMatch(normalMask, S16_NORMAL) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
+ processAccessor(blendShape.tangents, MaskMatch(tangentMask, S8_TANGENT) ? sizeof(uint8_t) * 3 : (MaskMatch(tangentMask, S16_TANGENT) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
}
if(HasBlendShapes())
{
- const uint32_t numberOfVertices = static_cast<uint32_t>(mPositions.mBlob.mLength / sizeof(Vector3));
-
// Calculate the size of one buffer inside the texture.
raw.mBlendShapeBufferOffset = numberOfVertices;
if(!mBlendShapeHeader.IsDefined())
{
- CalculateTextureSize(static_cast<uint32_t>(blendShapesBlob.mLength / sizeof(Vector3)), textureWidth, textureHeight);
+ CalculateTextureSize(totalTextureSize, textureWidth, textureHeight);
calculateGltf2BlendShapes = true;
}
else
INVALID = std::numeric_limits<uint32_t>::max()
};
- enum Flags : uint16_t
+ enum Flags : uint32_t
{
FLIP_UVS_VERTICAL = NthBit(0),
U32_INDICES = NthBit(1), // default is unsigned short
U8_JOINT_IDS = NthBit(4),
U16_WEIGHT = NthBit(5), // default is floats
U8_WEIGHT = NthBit(6),
+ S8_POSITION = NthBit(7), // default is floats
+ U8_POSITION = NthBit(8), // default is floats
+ S16_POSITION = NthBit(9), // default is floats
+ U16_POSITION = NthBit(10), // default is floats
+ S8_NORMAL = NthBit(11), // default is floats
+ S16_NORMAL = NthBit(12), // default is floats
+ S8_TANGENT = NthBit(13), // default is floats
+ S16_TANGENT = NthBit(14), // default is floats
+ S8_TEXCOORD = NthBit(15), // default is floats
+ U8_TEXCOORD = NthBit(16), // default is floats
+ S16_TEXCOORD = NthBit(17), // default is floats
+ U16_TEXCOORD = NthBit(18), // default is floats
+ };
+
+ enum FlagMasks : uint32_t
+ {
+ POSITIONS_MASK = 0x780,
+ NORMALS_MASK = 0x1800,
+ TANGENTS_MASK = 0x6000,
+ TEXCOORDS_MASK = 0x78000,
};
enum Attributes
Blob mBlob;
std::unique_ptr<SparseBlob> mSparse;
Index mBufferIdx = INVALID_INDEX;
+ bool mNormalized{false};
Accessor() = default;
Accessor normals;
Accessor tangents;
float weight = 0.f;
+ uint32_t mFlags = 0x0;
};
struct RawData