@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
JavaScript
;
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"
}
]
};
};