From dde3fe9c52036b37bcce256226c05e26328d3020 Mon Sep 17 00:00:00 2001 From: Fabio de Albuquerque Dela Antonio Date: Sun, 8 May 2022 02:11:37 +0100 Subject: [PATCH 1/6] Calibration JSON Schema --- README.md | 39 ++- examples/calibration_parser.html | 51 ++++ package-lock.json | 421 ++++++++++++++++++++++++++++++- package.json | 7 +- schemas/calibration-schema.json | 91 +++++++ src/mrc.js | 32 +++ src/validate-schema.js | 1 + 7 files changed, 631 insertions(+), 11 deletions(-) create mode 100644 examples/calibration_parser.html create mode 100644 schemas/calibration-schema.json create mode 100644 src/validate-schema.js diff --git a/README.md b/README.md index aa5a9fb..fbd3eac 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ Keep in mind that this is still just a prototype and that I'm not a frontend dev ## TO-DOs - Create a calibration page to allow users to calibrate the position and orientation of their camera, and to configure their chroma key (green screen). - - - Allow the Mixed Reality Capture session to be initialized with a JSON file with a saved calibration. ## How to test the example @@ -87,3 +85,40 @@ renderer.render( scene, camera ); mixedRealityCapture.render( renderer.xr, scene ); ``` + +Alternatively, you can instantiate the calibration with a JSON provided by the user: + +```javascript + +// ... + +const json = ` +{ + "schemaVersion": 1, + "camera": { + "width": 1280, + "height": 720, + "fov": 38, + "position": [0, 1.5, 0], + "orientation": [0, 0, 0, 1] + }, + "chromaKey": { + "color": [0, 1, 0], + "similarity": 0.25, + "smoothness": 0 + }, + "delay": 4 +} +`; + +const calibrationData = JSON.parse( json ); + +const calibration = MRC.Calibration.fromData( calibrationData ); + +// ... + +mixedRealityCapture = new MRC.MixedRealityCapture( calibration ); + +// ... + +``` diff --git a/examples/calibration_parser.html b/examples/calibration_parser.html new file mode 100644 index 0000000..b8455be --- /dev/null +++ b/examples/calibration_parser.html @@ -0,0 +1,51 @@ + + + + + Calibration parser + + + + + + + + + + + diff --git a/package-lock.json b/package-lock.json index e437975..ffdfe7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,435 @@ { "name": "reality-mixer", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "reality-mixer", - "version": "1.0.0", + "version": "1.1.0", "license": "MIT", "dependencies": { "three": "^0.140.0" + }, + "devDependencies": { + "ajv-cli": "git@github.com:willfarrell/ajv-cli.git#15c4f0153e25da2737d673f0c027e3ab0f5b1ec8" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-cli": { + "version": "5.0.0", + "resolved": "git+ssh://git@github.com/willfarrell/ajv-cli.git#15c4f0153e25da2737d673f0c027e3ab0f5b1ec8", + "integrity": "sha512-wbvOdDG+J6thaGIE13mGG8q9p5pIkhU7yGj1uY3dGlkxAXnUaN3zb/QYzv3hkPajM+TuvA3EZx+1ZWuWnn+ESA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0", + "fast-json-patch": "^2.0.0", + "glob": "^7.1.0", + "js-yaml": "^3.14.0", + "json-schema-migrate": "^2.0.0", + "json5": "^2.1.3", + "minimist": "^1.2.0" + }, + "bin": { + "ajv": "dist/index.js" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-patch": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^2.0.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fast-json-patch/node_modules/fast-deep-equal": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-migrate": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/three": { "version": "0.140.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.140.0.tgz", - "integrity": "sha512-jcHjbnYspPLDdsDQChmzyAoZ5KhJbgFk6pNGlAIc9fQMvsfPGjF5H9glrngqvb2CR/qXcClMyp5PYdF996lldA==" + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" } }, "dependencies": { + "ajv": { + "version": "8.11.0", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-cli": { + "version": "git+ssh://git@github.com/willfarrell/ajv-cli.git#15c4f0153e25da2737d673f0c027e3ab0f5b1ec8", + "integrity": "sha512-wbvOdDG+J6thaGIE13mGG8q9p5pIkhU7yGj1uY3dGlkxAXnUaN3zb/QYzv3hkPajM+TuvA3EZx+1ZWuWnn+ESA==", + "dev": true, + "from": "ajv-cli@git@github.com:willfarrell/ajv-cli.git#15c4f0153e25da2737d673f0c027e3ab0f5b1ec8", + "requires": { + "ajv": "^8.0.0", + "fast-json-patch": "^2.0.0", + "glob": "^7.1.0", + "js-yaml": "^3.14.0", + "json-schema-migrate": "^2.0.0", + "json5": "^2.1.3", + "minimist": "^1.2.0" + } + }, + "argparse": { + "version": "1.0.10", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "dev": true + }, + "fast-json-patch": { + "version": "2.2.1", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1" + }, + "dependencies": { + "fast-deep-equal": { + "version": "2.0.1", + "dev": true + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "dev": true + }, + "glob": { + "version": "7.2.0", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-migrate": { + "version": "2.0.0", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "dev": true + }, + "json5": { + "version": "2.2.1", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "dev": true + }, + "once": { + "version": "1.4.0", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "dev": true + }, "three": { - "version": "0.140.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.140.0.tgz", - "integrity": "sha512-jcHjbnYspPLDdsDQChmzyAoZ5KhJbgFk6pNGlAIc9fQMvsfPGjF5H9glrngqvb2CR/qXcClMyp5PYdF996lldA==" + "version": "0.140.0" + }, + "uri-js": { + "version": "4.4.1", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "wrappy": { + "version": "1.0.2", + "dev": true } } } diff --git a/package.json b/package.json index 1b53390..9a90aa2 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "reality-mixer", - "version": "1.0.0", + "version": "1.1.0", "description": "Mixed Reality Capture for WebXR and Three.js", "type": "module", "main": "src/mrc.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "compile-schema": "ajv compile -s schemas/calibration-schema.json -o src/validate-schema.js --code-esm" }, "repository": { "type": "git", @@ -29,5 +29,8 @@ "homepage": "https://github.com/fabio914/reality-mixer-js#readme", "dependencies": { "three": "^0.140.0" + }, + "devDependencies": { + "ajv-cli": "git@github.com:willfarrell/ajv-cli.git#15c4f0153e25da2737d673f0c027e3ab0f5b1ec8" } } diff --git a/schemas/calibration-schema.json b/schemas/calibration-schema.json new file mode 100644 index 0000000..cc52661 --- /dev/null +++ b/schemas/calibration-schema.json @@ -0,0 +1,91 @@ +{ + "type": "object", + "properties": { + "schemaVersion": { + "type": "integer", + "minimum": 1, + "maximum": 1 + }, + "camera": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "minimum": 1 + }, + "height": { + "type": "integer", + "minimum": 1 + }, + "fov": { + "type": "number", + "minimum": 1 + }, + "position": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number" + } + }, + "orientation": { + "type": "array", + "minItems": 4, + "maxItems": 4, + "items": { + "type": "number" + } + } + }, + "required": [ + "width", + "height", + "fov", + "position", + "orientation" + ] + }, + "chromaKey": { + "type": "object", + "properties": { + "color": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "similarity": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "smoothness": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "required": [ + "color", + "similarity", + "smoothness" + ] + }, + "delay": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "schemaVersion", + "camera", + "chromaKey", + "delay" + ], + "additionalProperties": false +} diff --git a/src/mrc.js b/src/mrc.js index 9001a7f..7c41f1c 100644 --- a/src/mrc.js +++ b/src/mrc.js @@ -1,4 +1,5 @@ import * as THREE from 'three'; +import validate from './validate-schema.js'; class CameraCalibration { width; @@ -52,6 +53,37 @@ class Calibration { this.chromaKey = chromaKey; this.delayInFrames = Math.max(0, delayInFrames); } + + static fromData(data) { + // We're not checking if the orientation is a valid unit quaternion + + if (!validate(data)) { + console.log(validate.errors); + return null; + } + + const cameraCalibration = new CameraCalibration( + data.camera.width, + data.camera.height, + data.camera.fov, + data.camera.position, + data.camera.orientation + ) + + const chromaKey = new ChromaKey( + data.chromaKey.color, + data.chromaKey.similarity, + data.chromaKey.smoothness + ) + + const calibration = new Calibration( + cameraCalibration, + chromaKey, + data.delay + ) + + return calibration; + } } class MixedRealityCapture { diff --git a/src/validate-schema.js b/src/validate-schema.js new file mode 100644 index 0000000..323630c --- /dev/null +++ b/src/validate-schema.js @@ -0,0 +1 @@ +"use strict";export const validate = validate20;export default validate20;const schema22 = {"type":"object","properties":{"schemaVersion":{"type":"integer","minimum":1,"maximum":1},"camera":{"type":"object","properties":{"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"fov":{"type":"number","minimum":1},"position":{"type":"array","minItems":3,"maxItems":3,"items":{"type":"number"}},"orientation":{"type":"array","minItems":4,"maxItems":4,"items":{"type":"number"}}},"required":["width","height","fov","position","orientation"]},"chromaKey":{"type":"object","properties":{"color":{"type":"array","minItems":3,"maxItems":3,"items":{"type":"number","minimum":0,"maximum":1}},"similarity":{"type":"number","minimum":0,"maximum":1},"smoothness":{"type":"number","minimum":0,"maximum":1}},"required":["color","similarity","smoothness"]},"delay":{"type":"integer","minimum":0}},"required":["schemaVersion","camera","chromaKey","delay"],"additionalProperties":false};function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(errors === 0){if(data && typeof data == "object" && !Array.isArray(data)){let missing0;if(((((data.schemaVersion === undefined) && (missing0 = "schemaVersion")) || ((data.camera === undefined) && (missing0 = "camera"))) || ((data.chromaKey === undefined) && (missing0 = "chromaKey"))) || ((data.delay === undefined) && (missing0 = "delay"))){validate20.errors = [{instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: missing0},message:"must have required property '"+missing0+"'"}];return false;}else {const _errs1 = errors;for(const key0 in data){if(!((((key0 === "schemaVersion") || (key0 === "camera")) || (key0 === "chromaKey")) || (key0 === "delay"))){validate20.errors = [{instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"}];return false;break;}}if(_errs1 === errors){if(data.schemaVersion !== undefined){let data0 = data.schemaVersion;const _errs2 = errors;if(!(((typeof data0 == "number") && (!(data0 % 1) && !isNaN(data0))) && (isFinite(data0)))){validate20.errors = [{instancePath:instancePath+"/schemaVersion",schemaPath:"#/properties/schemaVersion/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];return false;}if(errors === _errs2){if((typeof data0 == "number") && (isFinite(data0))){if(data0 > 1 || isNaN(data0)){validate20.errors = [{instancePath:instancePath+"/schemaVersion",schemaPath:"#/properties/schemaVersion/maximum",keyword:"maximum",params:{comparison: "<=", limit: 1},message:"must be <= 1"}];return false;}else {if(data0 < 1 || isNaN(data0)){validate20.errors = [{instancePath:instancePath+"/schemaVersion",schemaPath:"#/properties/schemaVersion/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"}];return false;}}}}var valid0 = _errs2 === errors;}else {var valid0 = true;}if(valid0){if(data.camera !== undefined){let data1 = data.camera;const _errs4 = errors;if(errors === _errs4){if(data1 && typeof data1 == "object" && !Array.isArray(data1)){let missing1;if((((((data1.width === undefined) && (missing1 = "width")) || ((data1.height === undefined) && (missing1 = "height"))) || ((data1.fov === undefined) && (missing1 = "fov"))) || ((data1.position === undefined) && (missing1 = "position"))) || ((data1.orientation === undefined) && (missing1 = "orientation"))){validate20.errors = [{instancePath:instancePath+"/camera",schemaPath:"#/properties/camera/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];return false;}else {if(data1.width !== undefined){let data2 = data1.width;const _errs6 = errors;if(!(((typeof data2 == "number") && (!(data2 % 1) && !isNaN(data2))) && (isFinite(data2)))){validate20.errors = [{instancePath:instancePath+"/camera/width",schemaPath:"#/properties/camera/properties/width/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];return false;}if(errors === _errs6){if((typeof data2 == "number") && (isFinite(data2))){if(data2 < 1 || isNaN(data2)){validate20.errors = [{instancePath:instancePath+"/camera/width",schemaPath:"#/properties/camera/properties/width/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"}];return false;}}}var valid1 = _errs6 === errors;}else {var valid1 = true;}if(valid1){if(data1.height !== undefined){let data3 = data1.height;const _errs8 = errors;if(!(((typeof data3 == "number") && (!(data3 % 1) && !isNaN(data3))) && (isFinite(data3)))){validate20.errors = [{instancePath:instancePath+"/camera/height",schemaPath:"#/properties/camera/properties/height/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];return false;}if(errors === _errs8){if((typeof data3 == "number") && (isFinite(data3))){if(data3 < 1 || isNaN(data3)){validate20.errors = [{instancePath:instancePath+"/camera/height",schemaPath:"#/properties/camera/properties/height/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"}];return false;}}}var valid1 = _errs8 === errors;}else {var valid1 = true;}if(valid1){if(data1.fov !== undefined){let data4 = data1.fov;const _errs10 = errors;if(errors === _errs10){if((typeof data4 == "number") && (isFinite(data4))){if(data4 < 1 || isNaN(data4)){validate20.errors = [{instancePath:instancePath+"/camera/fov",schemaPath:"#/properties/camera/properties/fov/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"}];return false;}}else {validate20.errors = [{instancePath:instancePath+"/camera/fov",schemaPath:"#/properties/camera/properties/fov/type",keyword:"type",params:{type: "number"},message:"must be number"}];return false;}}var valid1 = _errs10 === errors;}else {var valid1 = true;}if(valid1){if(data1.position !== undefined){let data5 = data1.position;const _errs12 = errors;if(errors === _errs12){if(Array.isArray(data5)){if(data5.length > 3){validate20.errors = [{instancePath:instancePath+"/camera/position",schemaPath:"#/properties/camera/properties/position/maxItems",keyword:"maxItems",params:{limit: 3},message:"must NOT have more than 3 items"}];return false;}else {if(data5.length < 3){validate20.errors = [{instancePath:instancePath+"/camera/position",schemaPath:"#/properties/camera/properties/position/minItems",keyword:"minItems",params:{limit: 3},message:"must NOT have fewer than 3 items"}];return false;}else {var valid2 = true;const len0 = data5.length;for(let i0=0; i0 4){validate20.errors = [{instancePath:instancePath+"/camera/orientation",schemaPath:"#/properties/camera/properties/orientation/maxItems",keyword:"maxItems",params:{limit: 4},message:"must NOT have more than 4 items"}];return false;}else {if(data7.length < 4){validate20.errors = [{instancePath:instancePath+"/camera/orientation",schemaPath:"#/properties/camera/properties/orientation/minItems",keyword:"minItems",params:{limit: 4},message:"must NOT have fewer than 4 items"}];return false;}else {var valid3 = true;const len1 = data7.length;for(let i1=0; i1 3){validate20.errors = [{instancePath:instancePath+"/chromaKey/color",schemaPath:"#/properties/chromaKey/properties/color/maxItems",keyword:"maxItems",params:{limit: 3},message:"must NOT have more than 3 items"}];return false;}else {if(data10.length < 3){validate20.errors = [{instancePath:instancePath+"/chromaKey/color",schemaPath:"#/properties/chromaKey/properties/color/minItems",keyword:"minItems",params:{limit: 3},message:"must NOT have fewer than 3 items"}];return false;}else {var valid5 = true;const len2 = data10.length;for(let i2=0; i2 1 || isNaN(data11)){validate20.errors = [{instancePath:instancePath+"/chromaKey/color/" + i2,schemaPath:"#/properties/chromaKey/properties/color/items/maximum",keyword:"maximum",params:{comparison: "<=", limit: 1},message:"must be <= 1"}];return false;}else {if(data11 < 0 || isNaN(data11)){validate20.errors = [{instancePath:instancePath+"/chromaKey/color/" + i2,schemaPath:"#/properties/chromaKey/properties/color/items/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"}];return false;}}}else {validate20.errors = [{instancePath:instancePath+"/chromaKey/color/" + i2,schemaPath:"#/properties/chromaKey/properties/color/items/type",keyword:"type",params:{type: "number"},message:"must be number"}];return false;}}var valid5 = _errs24 === errors;if(!valid5){break;}}}}}else {validate20.errors = [{instancePath:instancePath+"/chromaKey/color",schemaPath:"#/properties/chromaKey/properties/color/type",keyword:"type",params:{type: "array"},message:"must be array"}];return false;}}var valid4 = _errs22 === errors;}else {var valid4 = true;}if(valid4){if(data9.similarity !== undefined){let data12 = data9.similarity;const _errs26 = errors;if(errors === _errs26){if((typeof data12 == "number") && (isFinite(data12))){if(data12 > 1 || isNaN(data12)){validate20.errors = [{instancePath:instancePath+"/chromaKey/similarity",schemaPath:"#/properties/chromaKey/properties/similarity/maximum",keyword:"maximum",params:{comparison: "<=", limit: 1},message:"must be <= 1"}];return false;}else {if(data12 < 0 || isNaN(data12)){validate20.errors = [{instancePath:instancePath+"/chromaKey/similarity",schemaPath:"#/properties/chromaKey/properties/similarity/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"}];return false;}}}else {validate20.errors = [{instancePath:instancePath+"/chromaKey/similarity",schemaPath:"#/properties/chromaKey/properties/similarity/type",keyword:"type",params:{type: "number"},message:"must be number"}];return false;}}var valid4 = _errs26 === errors;}else {var valid4 = true;}if(valid4){if(data9.smoothness !== undefined){let data13 = data9.smoothness;const _errs28 = errors;if(errors === _errs28){if((typeof data13 == "number") && (isFinite(data13))){if(data13 > 1 || isNaN(data13)){validate20.errors = [{instancePath:instancePath+"/chromaKey/smoothness",schemaPath:"#/properties/chromaKey/properties/smoothness/maximum",keyword:"maximum",params:{comparison: "<=", limit: 1},message:"must be <= 1"}];return false;}else {if(data13 < 0 || isNaN(data13)){validate20.errors = [{instancePath:instancePath+"/chromaKey/smoothness",schemaPath:"#/properties/chromaKey/properties/smoothness/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"}];return false;}}}else {validate20.errors = [{instancePath:instancePath+"/chromaKey/smoothness",schemaPath:"#/properties/chromaKey/properties/smoothness/type",keyword:"type",params:{type: "number"},message:"must be number"}];return false;}}var valid4 = _errs28 === errors;}else {var valid4 = true;}}}}}else {validate20.errors = [{instancePath:instancePath+"/chromaKey",schemaPath:"#/properties/chromaKey/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}var valid0 = _errs20 === errors;}else {var valid0 = true;}if(valid0){if(data.delay !== undefined){let data14 = data.delay;const _errs30 = errors;if(!(((typeof data14 == "number") && (!(data14 % 1) && !isNaN(data14))) && (isFinite(data14)))){validate20.errors = [{instancePath:instancePath+"/delay",schemaPath:"#/properties/delay/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];return false;}if(errors === _errs30){if((typeof data14 == "number") && (isFinite(data14))){if(data14 < 0 || isNaN(data14)){validate20.errors = [{instancePath:instancePath+"/delay",schemaPath:"#/properties/delay/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"}];return false;}}}var valid0 = _errs30 === errors;}else {var valid0 = true;}}}}}}}else {validate20.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}validate20.errors = vErrors;return errors === 0;} \ No newline at end of file From b6bdae7f054ad787afc0b595050d3e16b0a2af69 Mon Sep 17 00:00:00 2001 From: Fabio de Albuquerque Dela Antonio Date: Tue, 10 May 2022 01:16:10 +0100 Subject: [PATCH 2/6] Improving example --- examples/calibration_parser.html | 88 ++++++++++++++++++++++++-------- src/mrc.js | 5 +- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/examples/calibration_parser.html b/examples/calibration_parser.html index b8455be..8581ad2 100644 --- a/examples/calibration_parser.html +++ b/examples/calibration_parser.html @@ -5,10 +5,58 @@ Calibration parser + + + diff --git a/src/mrc.js b/src/mrc.js index 7c41f1c..aa0976c 100644 --- a/src/mrc.js +++ b/src/mrc.js @@ -58,9 +58,8 @@ class Calibration { // We're not checking if the orientation is a valid unit quaternion if (!validate(data)) { - console.log(validate.errors); - return null; - } + throw JSON.stringify(validate.errors, null, 2); + } const cameraCalibration = new CameraCalibration( data.camera.width, From 1fd893a0dc8cf15ca029fafa0aa8bdfe880bf424 Mon Sep 17 00:00:00 2001 From: Fabio de Albuquerque Dela Antonio Date: Wed, 11 May 2022 23:56:13 +0100 Subject: [PATCH 3/6] Moving Calibration editor to js file --- .../calibration-editor/calibration-editor.js | 118 ++++++++++++++++++ examples/calibration_editor.html | 38 ++++++ examples/calibration_parser.html | 97 -------------- 3 files changed, 156 insertions(+), 97 deletions(-) create mode 100644 examples/calibration-editor/calibration-editor.js create mode 100644 examples/calibration_editor.html delete mode 100644 examples/calibration_parser.html diff --git a/examples/calibration-editor/calibration-editor.js b/examples/calibration-editor/calibration-editor.js new file mode 100644 index 0000000..10bd011 --- /dev/null +++ b/examples/calibration-editor/calibration-editor.js @@ -0,0 +1,118 @@ +import { Calibration } from 'reality-mixer'; + +const exampleCalibrationJSON = ` +{ + "schemaVersion": 1, + "camera": { + "width": 1920, + "height": 1080, + "fov": 38, + "position": [0, 1.5, 0], + "orientation": [0, 0, 0, 1] + }, + "chromaKey": { + "color": [0, 1, 0], + "similarity": 0.25, + "smoothness": 0 + }, + "delay": 4 +} +` + +function CalibrationInput( + onCompleted, + initialCalibrationJSON = exampleCalibrationJSON, +) { + let popupDiv = document.createElement("div"); + + popupDiv.style = ` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #303841; + border-radius: 4px; + font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; + color: #EFEFEF; + overflow: hidden; + ` + + let titleDiv = document.createElement("div"); + + titleDiv.style = "background-color: #50565E; padding: 8px"; + titleDiv.innerText = "Paste or drag and drop your Mixed Reality calibration below:" + + let resultDiv = document.createElement("div"); + + resultDiv.style = "padding: 8px; white-space: pre-wrap; background-color: green;"; + + let editor = document.createElement("textarea"); + + editor.style = ` + font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; + border: none; + box-shadow: none; + outline: none; + background-color: #303841; + color: #EFEFEF; + resize: none; + margin: 0px; + ` + + editor.rows = 20; + editor.cols = 80; + editor.spellcheck = false; + editor.value = initialCalibrationJSON; + + function validateCalibration() { + const maybeJson = editor.value; + + try { + const json = JSON.parse(maybeJson); + const calibration = Calibration.fromData(json); + + resultDiv.style.backgroundColor = "green"; + resultDiv.innerHTML = ""; + + let link = document.createElement("a"); + link.innerText = "Click here to continue..."; + link.href = "#"; + link.style.color = "#EFEFEF"; + link.onclick = function() { + onCompleted(popupDiv, calibration); + return false; + } + + resultDiv.appendChild(link); + } catch (error) { + resultDiv.innerText = error; + resultDiv.style.backgroundColor = "red"; + } + } + + editor.oninput = validateCalibration; + validateCalibration(); + + popupDiv.appendChild(titleDiv); + popupDiv.appendChild(editor); + popupDiv.appendChild(resultDiv); + + popupDiv.ondrop = function(e) { + e.preventDefault(); + + let file = e.dataTransfer.files[0], + reader = new FileReader(); + + reader.onload = function(event) { + editor.value = event.target.result; + validateCalibration(); + }; + + reader.readAsText(file); + return false; + } + + return popupDiv; +} + +export { CalibrationInput }; diff --git a/examples/calibration_editor.html b/examples/calibration_editor.html new file mode 100644 index 0000000..0f5d24f --- /dev/null +++ b/examples/calibration_editor.html @@ -0,0 +1,38 @@ + + + + + Calibration editor + + + + + + + + + + + + diff --git a/examples/calibration_parser.html b/examples/calibration_parser.html deleted file mode 100644 index 8581ad2..0000000 --- a/examples/calibration_parser.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - Calibration parser - - - - - - - - - - - - - - From 8ed9e9923fc414d429ba4c565b7118f3e2765e91 Mon Sep 17 00:00:00 2001 From: Fabio de Albuquerque Dela Antonio Date: Thu, 12 May 2022 00:35:46 +0100 Subject: [PATCH 4/6] Editing ballshooter example --- examples/calibration_editor.html | 2 +- examples/webxr_vr_ballshooter.html | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/calibration_editor.html b/examples/calibration_editor.html index 0f5d24f..0cfe0b1 100644 --- a/examples/calibration_editor.html +++ b/examples/calibration_editor.html @@ -21,7 +21,7 @@