UNPKG

@bezlepkin/nativescript-ar

Version:

NativeScript Augmented Reality plugin. ARKit on iOS and (with the help of Sceneform) ARCore on Android.

318 lines (317 loc) 11.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ARMaterialFactory = void 0; const core_1 = require("@nativescript/core"); class ARMaterialFactory { static applyMaterial(node, material) { if (typeof material === "string") { return new Promise((resolve, reject) => { reject("not implemented"); }); } else if (material.constructor.name === "Color") { return ARMaterialFactory.applyColor(node, material.android) .catch(err => console.log("Error applying material: " + err)); } else { return ARMaterialFactory.applyARMaterial(node, material) .catch(err => console.log("Error applying material: " + err)); } } static applyColor(node, color) { return new Promise((resolve, reject) => { com.google.ar.sceneform.rendering.MaterialFactory.makeOpaqueWithColor(core_1.Utils.ad.getApplicationContext(), new com.google.ar.sceneform.rendering.Color(color)) .thenAccept(new java.util.function.Consumer({ accept: material => { const renderable = node.getRenderable(); if (renderable) { renderable.setMaterial(material); } resolve(); } })) .exceptionally(new java.util.function.Function({ apply: error => reject(error) })); }); } static applyARMaterial(node, material) { return new Promise((resolve, reject) => { android.os.AsyncTask.execute(new java.lang.Runnable({ run: () => { let gltf = blankGLTF(); let index = 0; if (material.diffuse) { if (material.diffuse.constructor.name === "Color") { addPbrMetallic(gltf, { "baseColorFactor": colorFrom(material.diffuse), }); } else { addTexture(gltf, material.diffuse, index); addPbrMetallic(gltf, { "baseColorTexture": { "index": index } }); gltf.materials[0]["extensions"] = { "KHR_materials_pbrSpecularGlossiness": { "diffuseTexture": { "index": index } } }; index++; } } if (material.normal) { if (material.normal.constructor.name === "Color") { } else { addTexture(gltf, material.normal, index); gltf.materials[0]["normalTexture"] = { "index": index }; index++; } } if (material.roughness) { if (material.roughness.constructor.name === "Color") { } else { addTexture(gltf, material.roughness, index); addPbrMetallic(gltf, { "metallicRoughnessTexture": { "index": index } }); index++; } } if (material.emission) { if (material.emission.constructor.name === "Color") { } else { addTexture(gltf, material.emission, index); gltf.materials[0]["emissiveFactor"] = [ 1.0, 1.0, 1.0 ]; gltf.materials[0]["emissiveTexture"] = { "index": index }; index++; } } const p = core_1.path.join(core_1.knownFolders.temp().path, "ar-" + (new Date()).getTime()); const tmp = core_1.Folder.fromPath(p); const file = tmp.getFile("model_source.gltf"); const modelPath = file.path; let promise = file.writeText(JSON.stringify(gltf, null, " ")) .then(() => copyAsset("material.bin", tmp.getFile("material.bin").path)); gltf.images.forEach(image => { promise = promise.then(() => { return copyAsset(image.uri, tmp.getFile(image.uri).path) .catch(err => console.log("Failed to copy " + image.uri + " with error: " + err)); }); }); promise.then(() => { let context = core_1.Utils.ad.getApplicationContext(); let model = com.google.ar.sceneform.assets.RenderableSource.builder().setSource(context, android.net.Uri.parse(modelPath), com.google.ar.sceneform.assets.RenderableSource.SourceType.GLTF2).build(); com.google.ar.sceneform.rendering.ModelRenderable.builder() .setSource(context, model) .build() .thenAccept(new java.util.function.Consumer({ accept: renderable => { node.getRenderable().setMaterial(renderable.getMaterial()); } })) .exceptionally(new java.util.function.Function({ apply: error => { console.error("failed loading custom material: " + error); reject(error); } })); }).catch((err) => { console.error("failed to load custom material"); console.log(err); reject(err); }); } })); }); } } exports.ARMaterialFactory = ARMaterialFactory; const getWrapMode = (wrapMode) => { if (wrapMode === "Mirror") { return 33648; } else if (wrapMode === "Clamp") { return 33071; } else if (wrapMode === "ClampToBorder") { return 33071; } else { return 10497; } }; let counter = 0; const copyAsset = (asset, to) => { return new Promise((resolve, reject) => { const context = core_1.Utils.ad.getApplicationContext(); let input = context.getAssets().open(asset); let out = new java.io.FileOutputStream(new java.io.File(to)); let buf = Array.create("byte", 1024); let len; while ((len = input.read(buf)) > 0) { out.write(buf, 0, len); } input.close(); out.close(); resolve(); }); }; const colorFrom = (color) => { const c = new com.google.ar.sceneform.rendering.Color(color.android); return [c.r, c.g, c.b, c.a]; }; const addPbrMetallic = (gltf, property) => { if (gltf.materials[0]["pbrMetallicRoughness"] === undefined) { gltf.materials[0]["pbrMetallicRoughness"] = {}; } Object.keys(property).forEach(key => gltf.materials[0]["pbrMetallicRoughness"][key] = property[key]); }; const addTexture = (gltf, material, index) => { let property = (typeof material === "string" ? { contents: material, wrapMode: "Repeat" } : material); gltf.images.push({ "uri": property.contents }); gltf.samplers.push({ "magFilter": 9729, "minFilter": 9987, "wrapT": getWrapMode(property.wrapMode), "wrapS": getWrapMode(property.wrapMode) }); gltf.textures.push({ "sampler": index, "source": index }); }; const blankGLTF = () => { return { "asset": { "version": "2.0", "generator": "Khronos glTF Blender I/O v0.9.53" }, "scene": 0, "scenes": [ { "nodes": [ 0 ], "name": "Scene" } ], "nodes": [ { "mesh": 0, "name": "Cube" } ], "images": [], "materials": [ { "name": "Material", "alphaMode": "BLEND" } ], "samplers": [], "textures": [], "meshes": [ { "primitives": [ { "attributes": { "POSITION": 0, "NORMAL": 1, "TEXCOORD_0": 2 }, "material": 0, "indices": 3 } ], "name": "Cube" } ], "accessors": [ { "componentType": 5126, "count": 24, "type": "VEC3", "min": [ -1.0000003576278687, -1, -1.0000003576278687 ], "bufferView": 0, "max": [ 1.0000004768371582, 1, 1.0000005960464478 ] }, { "componentType": 5126, "bufferView": 1, "count": 24, "type": "VEC3" }, { "componentType": 5126, "bufferView": 2, "count": 24, "type": "VEC2" }, { "componentType": 5123, "bufferView": 3, "count": 36, "type": "SCALAR" } ], "bufferViews": [ { "byteLength": 288, "buffer": 0, "byteOffset": 0 }, { "byteLength": 288, "buffer": 0, "byteOffset": 288 }, { "byteLength": 192, "buffer": 0, "byteOffset": 576 }, { "byteLength": 72, "buffer": 0, "byteOffset": 768 } ], "buffers": [ { "byteLength": 840, "uri": "material.bin" } ] }; };