UNPKG

molstar

Version:

A comprehensive macromolecular library.

210 lines 14.5 kB
/** * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> */ import { __awaiter, __extends, __generator, __spreadArray } from "tslib"; import { asciiWrite } from '../../mol-io/common/ascii'; import { Vec3, Mat3, Mat4 } from '../../mol-math/linear-algebra'; import { PLUGIN_VERSION } from '../../mol-plugin/version'; import { StringBuilder } from '../../mol-util'; import { Color } from '../../mol-util/color/color'; import { zip } from '../../mol-util/zip/zip'; import { MeshExporter } from './mesh-exporter'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) var v3fromArray = Vec3.fromArray; var v3transformMat4 = Vec3.transformMat4; var v3transformMat3 = Vec3.transformMat3; var mat3directionTransform = Mat3.directionTransform; var UsdzExporter = /** @class */ (function (_super) { __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 = Mat4(); // scale the model so that it fits within 1 meter Mat4.fromUniformScaling(t, Math.min(1 / (radius * 2), 1)); // translate the model so that it sits on the ground plane (y = 0) Mat4.translate(t, t, 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.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 __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 __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 = Mat4(); n = Mat3(); tmpV = 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 __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; Mat4.fromArray(t, aTransform, instanceIndex * 16); Mat4.mul(t, this_1.centerTransform, t); mat3directionTransform(n, t); vertexBuilder = StringBuilder.create(); normalBuilder = StringBuilder.create(); indexBuilder = StringBuilder.create(); // position for (i = 0; i < vertexCount; ++i) { v3transformMat4(tmpV, v3fromArray(tmpV, vertices, i * stride), t); StringBuilder.writeSafe(vertexBuilder, (i === 0) ? '(' : ',('); StringBuilder.writeFloat(vertexBuilder, tmpV[0], 10000); StringBuilder.writeSafe(vertexBuilder, ','); StringBuilder.writeFloat(vertexBuilder, tmpV[1], 10000); StringBuilder.writeSafe(vertexBuilder, ','); StringBuilder.writeFloat(vertexBuilder, tmpV[2], 10000); StringBuilder.writeSafe(vertexBuilder, ')'); } // normal for (i = 0; i < vertexCount; ++i) { v3transformMat3(tmpV, v3fromArray(tmpV, normals, i * stride), n); StringBuilder.writeSafe(normalBuilder, (i === 0) ? '(' : ',('); StringBuilder.writeFloat(normalBuilder, tmpV[0], 100); StringBuilder.writeSafe(normalBuilder, ','); StringBuilder.writeFloat(normalBuilder, tmpV[1], 100); StringBuilder.writeSafe(normalBuilder, ','); StringBuilder.writeFloat(normalBuilder, tmpV[2], 100); StringBuilder.writeSafe(normalBuilder, ')'); } // face for (i = 0; i < drawCount; ++i) { v = isGeoTexture ? i : indices[i]; if (i > 0) StringBuilder.writeSafe(indexBuilder, ','); 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 = [" + StringBuilder.getString(indexBuilder) + "]\n point3f[] points = [" + StringBuilder.getString(vertexBuilder) + "]\n normal3f[] primvars:normals = [" + 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 __awaiter(this, void 0, void 0, function () { var header, usda, usdaData, zipDataObj; var _a, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: header = "#usda 1.0\n(\n customLayerData = {\n string creator = \"Mol* " + PLUGIN_VERSION + "\"\n }\n metersPerUnit = 1\n)\n"; usda = __spreadArray(__spreadArray([header], this.materials, true), this.meshes, true).join(''); usdaData = new Uint8Array(usda.length); asciiWrite(usdaData, usda); zipDataObj = (_a = {}, _a['model.usda'] = usdaData, _a); _b = {}; return [4 /*yield*/, zip(ctx, zipDataObj, true)]; case 1: return [2 /*return*/, (_b.usdz = _c.sent(), _b)]; } }); }); }; UsdzExporter.prototype.getBlob = function (ctx) { return __awaiter(this, void 0, void 0, function () { var usdz; return __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; }(MeshExporter)); export { UsdzExporter }; //# sourceMappingURL=usdz-exporter.js.map