|
6 | 6 |
|
7 | 7 | import { Vec3 } from 'molstar/lib/mol-math/linear-algebra';
|
8 | 8 | import { Color } from 'molstar/lib/mol-util/color/color';
|
| 9 | +import { ValueType, UsdAttribute, UsdData, CrateFile } from './usdz'; |
9 | 10 |
|
10 | 11 | function computeBounding(points: Vec3[]) {
|
11 | 12 | const min = Vec3.create(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
@@ -207,3 +208,66 @@ export function exportGlb(meshByColor: Map<Color, Mesh>) {
|
207 | 208 | ]);
|
208 | 209 | return glb;
|
209 | 210 | }
|
| 211 | + |
| 212 | +export function exportUsdz(meshByColor: Map<Color, Mesh>) { |
| 213 | + const root = new UsdData('', ''); |
| 214 | + const usdObj = root.createChild('ar', 'Xform'); |
| 215 | + usdObj.metadata['assetInfo'] = {'name': 'ar'}; |
| 216 | + usdObj.metadata['kind'] = 'component'; |
| 217 | + |
| 218 | + const materials_scope = usdObj.createChild('Materials', 'Scope'); |
| 219 | + |
| 220 | + let refId = 0; |
| 221 | + |
| 222 | + const vecsToFloatArray = (v: number[][]) => { |
| 223 | + const a = new Float32Array(v.length * 3); |
| 224 | + for (let i = 0; i < v.length; ++i) { |
| 225 | + a[i * 3] = v[i][0]; |
| 226 | + a[i * 3 + 1] = v[i][1]; |
| 227 | + a[i * 3 + 2] = v[i][2]; |
| 228 | + } |
| 229 | + return a; |
| 230 | + }; |
| 231 | + |
| 232 | + meshByColor.forEach((mesh, color) => { |
| 233 | + const { positions, normals, faces } = mesh; |
| 234 | + const positions2 = vecsToFloatArray(positions); |
| 235 | + const normals2 = vecsToFloatArray(normals); |
| 236 | + const faceVertexCounts = new Uint32Array(faces.length / 3); |
| 237 | + faceVertexCounts.fill(3); |
| 238 | + |
| 239 | + const rgb = new Float32Array(Color.toRgbNormalized(color)); |
| 240 | + const usdMaterial = materials_scope.createChild('k' + String(refId), 'Material'); |
| 241 | + |
| 242 | + const usdShader = usdMaterial.createChild('surfaceShader', 'Shader'); |
| 243 | + const infoIdAtt = new UsdAttribute('info:id', 'UsdPreviewSurface', ValueType.token, 'token'); |
| 244 | + infoIdAtt.addQualifier('uniform'); |
| 245 | + usdShader.addAttribute(infoIdAtt); |
| 246 | + usdShader.addAttribute(new UsdAttribute('inputs:diffuseColor', rgb, ValueType.vec3f, 'color3f')); |
| 247 | + usdShader.addAttribute(new UsdAttribute('inputs:roughness', 0.2, ValueType.float, 'float')); |
| 248 | + const surface = new UsdAttribute('outputs:surface', null, ValueType.token, 'token'); |
| 249 | + usdShader.addAttribute(surface); |
| 250 | + |
| 251 | + usdMaterial.addAttribute(new UsdAttribute('outputs:surface', surface, ValueType.Invalid, 'token')); |
| 252 | + |
| 253 | + const usdMesh = usdObj.createChild('m' + String(refId), 'Mesh'); |
| 254 | + usdMesh.addAttribute(new UsdAttribute('material:binding', usdMaterial, ValueType.Invalid, 'rel')); |
| 255 | + usdMesh.addAttribute(new UsdAttribute('doubleSided', false, ValueType.bool, 'bool')); |
| 256 | + usdMesh.addAttribute(new UsdAttribute('faceVertexCounts', faceVertexCounts, ValueType.int, 'int[]', true)); |
| 257 | + usdMesh.addAttribute(new UsdAttribute('faceVertexIndices', faces, ValueType.int, 'int[]', true)); |
| 258 | + usdMesh.addAttribute(new UsdAttribute('points', positions2, ValueType.vec3f, 'point3f[]', true)); |
| 259 | + const normalsAtt = new UsdAttribute('primvars:normals', normals2, ValueType.vec3f, 'normal3f[]', true); |
| 260 | + normalsAtt.metadata['interpolation'] = 'vertex'; |
| 261 | + usdMesh.addAttribute(normalsAtt); |
| 262 | + const subdivAtt = new UsdAttribute('subdivisionScheme', 'none', ValueType.token, 'token'); |
| 263 | + subdivAtt.addQualifier('uniform'); |
| 264 | + usdMesh.addAttribute(subdivAtt); |
| 265 | + |
| 266 | + refId++; |
| 267 | + }); |
| 268 | + |
| 269 | + const crateFile = new CrateFile(); |
| 270 | + crateFile.writeUsd(root); |
| 271 | + const usdz = crateFile.getUsdz(); |
| 272 | + return Buffer.from(usdz.buffer); |
| 273 | +} |
0 commit comments