molstar
Version:
A comprehensive macromolecular library.
213 lines • 15.2 kB
JavaScript
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sukolsak Sakshuwong <sukolsak@stanford.edu>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.UsdzExporter = void 0;
var tslib_1 = require("tslib");
var ascii_1 = require("../../mol-io/common/ascii");
var linear_algebra_1 = require("../../mol-math/linear-algebra");
var version_1 = require("../../mol-plugin/version");
var mol_util_1 = require("../../mol-util");
var color_1 = require("../../mol-util/color/color");
var zip_1 = require("../../mol-util/zip/zip");
var mesh_exporter_1 = require("./mesh-exporter");
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
var v3fromArray = linear_algebra_1.Vec3.fromArray;
var v3transformMat4 = linear_algebra_1.Vec3.transformMat4;
var v3transformMat3 = linear_algebra_1.Vec3.transformMat3;
var mat3directionTransform = linear_algebra_1.Mat3.directionTransform;
var UsdzExporter = /** @class */ (function (_super) {
(0, tslib_1.__extends)(UsdzExporter, _super);
function UsdzExporter(style, boundingBox, radius) {
var _this = _super.call(this) || this;
_this.style = style;
_this.fileExtension = 'usdz';
_this.meshes = [];
_this.materials = [];
_this.materialSet = new Set();
var t = (0, linear_algebra_1.Mat4)();
// scale the model so that it fits within 1 meter
linear_algebra_1.Mat4.fromUniformScaling(t, Math.min(1 / (radius * 2), 1));
// translate the model so that it sits on the ground plane (y = 0)
linear_algebra_1.Mat4.translate(t, t, linear_algebra_1.Vec3.create(-(boundingBox.min[0] + boundingBox.max[0]) / 2, -boundingBox.min[1], -(boundingBox.min[2] + boundingBox.max[2]) / 2));
_this.centerTransform = t;
return _this;
}
UsdzExporter.getMaterialKey = function (color, alpha) {
return color * 256 + Math.round(alpha * 255);
};
UsdzExporter.prototype.addMaterial = function (color, alpha) {
var materialKey = UsdzExporter.getMaterialKey(color, alpha);
if (this.materialSet.has(materialKey))
return;
this.materialSet.add(materialKey);
var _a = color_1.Color.toRgbNormalized(color), r = _a[0], g = _a[1], b = _a[2];
this.materials.push("\ndef Material \"material" + materialKey + "\"\n{\n token outputs:surface.connect = </material" + materialKey + "/shader.outputs:surface>\n def Shader \"shader\"\n {\n uniform token info:id = \"UsdPreviewSurface\"\n color3f inputs:diffuseColor = (" + r + "," + g + "," + b + ")\n float inputs:opacity = " + alpha + "\n float inputs:metallic = " + this.style.metalness + "\n float inputs:roughness = " + this.style.roughness + "\n token outputs:surface\n }\n}\n");
};
UsdzExporter.prototype.addMeshWithColors = function (input) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var mesh, values, isGeoTexture, webgl, ctx, t, n, tmpV, stride, groupCount, colorType, uAlpha, dTransparency, tTransparency, aTransform, instanceCount, interpolatedColors, _loop_1, this_1, instanceIndex;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
mesh = input.mesh, values = input.values, isGeoTexture = input.isGeoTexture, webgl = input.webgl, ctx = input.ctx;
t = (0, linear_algebra_1.Mat4)();
n = (0, linear_algebra_1.Mat3)();
tmpV = (0, linear_algebra_1.Vec3)();
stride = isGeoTexture ? 4 : 3;
groupCount = values.uGroupCount.ref.value;
colorType = values.dColorType.ref.value;
uAlpha = values.uAlpha.ref.value;
dTransparency = values.dTransparency.ref.value;
tTransparency = values.tTransparency.ref.value;
aTransform = values.aTransform.ref.value;
instanceCount = values.uInstanceCount.ref.value;
if (colorType === 'volume' || colorType === 'volumeInstance') {
interpolatedColors = UsdzExporter.getInterpolatedColors(mesh.vertices, mesh.vertexCount, values, stride, colorType, webgl);
UsdzExporter.quantizeColors(interpolatedColors, mesh.vertexCount);
}
return [4 /*yield*/, ctx.update({ isIndeterminate: false, current: 0, max: instanceCount })];
case 1:
_a.sent();
_loop_1 = function (instanceIndex) {
var _b, vertices, normals, indices, groups, vertexCount, drawCount, vertexBuilder, normalBuilder, indexBuilder, i, i, i, v, faceIndicesByMaterial, i, v, color, alpha, group, transparency, materialKey, faceIndices, materialBinding, materialKey, geomSubsets_1;
return (0, tslib_1.__generator)(this, function (_c) {
switch (_c.label) {
case 0:
if (!ctx.shouldUpdate) return [3 /*break*/, 2];
return [4 /*yield*/, ctx.update({ current: instanceIndex + 1 })];
case 1:
_c.sent();
_c.label = 2;
case 2:
_b = UsdzExporter.getInstance(input, instanceIndex), vertices = _b.vertices, normals = _b.normals, indices = _b.indices, groups = _b.groups, vertexCount = _b.vertexCount, drawCount = _b.drawCount;
linear_algebra_1.Mat4.fromArray(t, aTransform, instanceIndex * 16);
linear_algebra_1.Mat4.mul(t, this_1.centerTransform, t);
mat3directionTransform(n, t);
vertexBuilder = mol_util_1.StringBuilder.create();
normalBuilder = mol_util_1.StringBuilder.create();
indexBuilder = mol_util_1.StringBuilder.create();
// position
for (i = 0; i < vertexCount; ++i) {
v3transformMat4(tmpV, v3fromArray(tmpV, vertices, i * stride), t);
mol_util_1.StringBuilder.writeSafe(vertexBuilder, (i === 0) ? '(' : ',(');
mol_util_1.StringBuilder.writeFloat(vertexBuilder, tmpV[0], 10000);
mol_util_1.StringBuilder.writeSafe(vertexBuilder, ',');
mol_util_1.StringBuilder.writeFloat(vertexBuilder, tmpV[1], 10000);
mol_util_1.StringBuilder.writeSafe(vertexBuilder, ',');
mol_util_1.StringBuilder.writeFloat(vertexBuilder, tmpV[2], 10000);
mol_util_1.StringBuilder.writeSafe(vertexBuilder, ')');
}
// normal
for (i = 0; i < vertexCount; ++i) {
v3transformMat3(tmpV, v3fromArray(tmpV, normals, i * stride), n);
mol_util_1.StringBuilder.writeSafe(normalBuilder, (i === 0) ? '(' : ',(');
mol_util_1.StringBuilder.writeFloat(normalBuilder, tmpV[0], 100);
mol_util_1.StringBuilder.writeSafe(normalBuilder, ',');
mol_util_1.StringBuilder.writeFloat(normalBuilder, tmpV[1], 100);
mol_util_1.StringBuilder.writeSafe(normalBuilder, ',');
mol_util_1.StringBuilder.writeFloat(normalBuilder, tmpV[2], 100);
mol_util_1.StringBuilder.writeSafe(normalBuilder, ')');
}
// face
for (i = 0; i < drawCount; ++i) {
v = isGeoTexture ? i : indices[i];
if (i > 0)
mol_util_1.StringBuilder.writeSafe(indexBuilder, ',');
mol_util_1.StringBuilder.writeInteger(indexBuilder, v);
}
faceIndicesByMaterial = new Map();
for (i = 0; i < drawCount; i += 3) {
v = isGeoTexture ? i : indices[i];
color = UsdzExporter.getColor(values, groups, vertexCount, instanceIndex, isGeoTexture, interpolatedColors, v);
alpha = uAlpha;
if (dTransparency) {
group = isGeoTexture ? UsdzExporter.getGroup(groups, i) : groups[indices[i]];
transparency = tTransparency.array[instanceIndex * groupCount + group] / 255;
alpha *= 1 - transparency;
}
this_1.addMaterial(color, alpha);
materialKey = UsdzExporter.getMaterialKey(color, alpha);
faceIndices = faceIndicesByMaterial.get(materialKey);
if (faceIndices === undefined) {
faceIndices = [];
faceIndicesByMaterial.set(materialKey, faceIndices);
}
faceIndices.push(i / 3);
}
materialBinding = void 0;
if (faceIndicesByMaterial.size === 1) {
materialKey = faceIndicesByMaterial.keys().next().value;
materialBinding = "rel material:binding = </material" + materialKey + ">";
}
else {
geomSubsets_1 = [];
faceIndicesByMaterial.forEach(function (faceIndices, materialKey) {
geomSubsets_1.push("\n def GeomSubset \"g" + materialKey + "\"\n {\n uniform token elementType = \"face\"\n uniform token familyName = \"materialBind\"\n int[] indices = [" + faceIndices.join(',') + "]\n rel material:binding = </material" + materialKey + ">\n }\n");
});
materialBinding = geomSubsets_1.join('');
}
this_1.meshes.push("\ndef Mesh \"mesh" + this_1.meshes.length + "\"\n{\n int[] faceVertexCounts = [" + new Array(drawCount / 3).fill(3).join(',') + "]\n int[] faceVertexIndices = [" + mol_util_1.StringBuilder.getString(indexBuilder) + "]\n point3f[] points = [" + mol_util_1.StringBuilder.getString(vertexBuilder) + "]\n normal3f[] primvars:normals = [" + mol_util_1.StringBuilder.getString(normalBuilder) + "] (\n interpolation = \"vertex\"\n )\n uniform token subdivisionScheme = \"none\"\n " + materialBinding + "\n}\n");
return [2 /*return*/];
}
});
};
this_1 = this;
instanceIndex = 0;
_a.label = 2;
case 2:
if (!(instanceIndex < instanceCount)) return [3 /*break*/, 5];
return [5 /*yield**/, _loop_1(instanceIndex)];
case 3:
_a.sent();
_a.label = 4;
case 4:
++instanceIndex;
return [3 /*break*/, 2];
case 5: return [2 /*return*/];
}
});
});
};
UsdzExporter.prototype.getData = function (ctx) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var header, usda, usdaData, zipDataObj;
var _a, _b;
return (0, tslib_1.__generator)(this, function (_c) {
switch (_c.label) {
case 0:
header = "#usda 1.0\n(\n customLayerData = {\n string creator = \"Mol* " + version_1.PLUGIN_VERSION + "\"\n }\n metersPerUnit = 1\n)\n";
usda = (0, tslib_1.__spreadArray)((0, tslib_1.__spreadArray)([header], this.materials, true), this.meshes, true).join('');
usdaData = new Uint8Array(usda.length);
(0, ascii_1.asciiWrite)(usdaData, usda);
zipDataObj = (_a = {},
_a['model.usda'] = usdaData,
_a);
_b = {};
return [4 /*yield*/, (0, zip_1.zip)(ctx, zipDataObj, true)];
case 1: return [2 /*return*/, (_b.usdz = _c.sent(),
_b)];
}
});
});
};
UsdzExporter.prototype.getBlob = function (ctx) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var usdz;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getData(ctx)];
case 1:
usdz = (_a.sent()).usdz;
return [2 /*return*/, new Blob([usdz], { type: 'model/vnd.usdz+zip' })];
}
});
});
};
return UsdzExporter;
}(mesh_exporter_1.MeshExporter));
exports.UsdzExporter = UsdzExporter;
//# sourceMappingURL=usdz-exporter.js.map
;