@onerjs/serializers 8.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OBJ/index.d.ts +1 -0
- package/OBJ/index.js +2 -0
- package/OBJ/index.js.map +1 -0
- package/OBJ/objSerializer.d.ts +21 -0
- package/OBJ/objSerializer.js +171 -0
- package/OBJ/objSerializer.js.map +1 -0
- package/USDZ/index.d.ts +1 -0
- package/USDZ/index.js +3 -0
- package/USDZ/index.js.map +1 -0
- package/USDZ/usdzExporter.d.ts +50 -0
- package/USDZ/usdzExporter.js +589 -0
- package/USDZ/usdzExporter.js.map +1 -0
- package/exportUtils.d.ts +12 -0
- package/exportUtils.js +37 -0
- package/exportUtils.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.d.ts +24 -0
- package/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.js +61 -0
- package/glTF/2.0/Extensions/EXT_materials_diffuse_roughness.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.d.ts +36 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.js +109 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.d.ts +32 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.js +135 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.js +145 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.js +62 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.js +85 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.js +118 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.d.ts +31 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.js +63 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.d.ts +27 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.js +54 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.d.ts +29 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.js +55 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.js +69 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.js +66 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.d.ts +41 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.js +94 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.d.ts +41 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.js +92 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.d.ts +20 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.js +46 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.js +96 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.d.ts +21 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.js +93 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.js.map +1 -0
- package/glTF/2.0/Extensions/index.d.ts +17 -0
- package/glTF/2.0/Extensions/index.js +18 -0
- package/glTF/2.0/Extensions/index.js.map +1 -0
- package/glTF/2.0/bufferManager.d.ts +68 -0
- package/glTF/2.0/bufferManager.js +154 -0
- package/glTF/2.0/bufferManager.js.map +1 -0
- package/glTF/2.0/dataWriter.d.ts +20 -0
- package/glTF/2.0/dataWriter.js +83 -0
- package/glTF/2.0/dataWriter.js.map +1 -0
- package/glTF/2.0/glTFAnimation.d.ts +191 -0
- package/glTF/2.0/glTFAnimation.js +786 -0
- package/glTF/2.0/glTFAnimation.js.map +1 -0
- package/glTF/2.0/glTFData.d.ts +21 -0
- package/glTF/2.0/glTFData.js +30 -0
- package/glTF/2.0/glTFData.js.map +1 -0
- package/glTF/2.0/glTFExporter.d.ts +109 -0
- package/glTF/2.0/glTFExporter.js +1166 -0
- package/glTF/2.0/glTFExporter.js.map +1 -0
- package/glTF/2.0/glTFExporterExtension.d.ts +77 -0
- package/glTF/2.0/glTFExporterExtension.js +4 -0
- package/glTF/2.0/glTFExporterExtension.js.map +1 -0
- package/glTF/2.0/glTFMaterialExporter.d.ts +99 -0
- package/glTF/2.0/glTFMaterialExporter.js +778 -0
- package/glTF/2.0/glTFMaterialExporter.js.map +1 -0
- package/glTF/2.0/glTFMorphTargetsUtilities.d.ts +14 -0
- package/glTF/2.0/glTFMorphTargetsUtilities.js +149 -0
- package/glTF/2.0/glTFMorphTargetsUtilities.js.map +1 -0
- package/glTF/2.0/glTFSerializer.d.ts +78 -0
- package/glTF/2.0/glTFSerializer.js +39 -0
- package/glTF/2.0/glTFSerializer.js.map +1 -0
- package/glTF/2.0/glTFUtilities.d.ts +89 -0
- package/glTF/2.0/glTFUtilities.js +349 -0
- package/glTF/2.0/glTFUtilities.js.map +1 -0
- package/glTF/2.0/index.d.ts +4 -0
- package/glTF/2.0/index.js +6 -0
- package/glTF/2.0/index.js.map +1 -0
- package/glTF/glTFFileExporter.d.ts +20 -0
- package/glTF/glTFFileExporter.js +4 -0
- package/glTF/glTFFileExporter.js.map +1 -0
- package/glTF/index.d.ts +2 -0
- package/glTF/index.js +4 -0
- package/glTF/index.js.map +1 -0
- package/index.d.ts +4 -0
- package/index.js +6 -0
- package/index.js.map +1 -0
- package/legacy/legacy-glTF2Serializer.d.ts +2 -0
- package/legacy/legacy-glTF2Serializer.js +45 -0
- package/legacy/legacy-glTF2Serializer.js.map +1 -0
- package/legacy/legacy-objSerializer.d.ts +1 -0
- package/legacy/legacy-objSerializer.js +14 -0
- package/legacy/legacy-objSerializer.js.map +1 -0
- package/legacy/legacy-stlSerializer.d.ts +1 -0
- package/legacy/legacy-stlSerializer.js +14 -0
- package/legacy/legacy-stlSerializer.js.map +1 -0
- package/legacy/legacy-usdzSerializer.d.ts +1 -0
- package/legacy/legacy-usdzSerializer.js +14 -0
- package/legacy/legacy-usdzSerializer.js.map +1 -0
- package/legacy/legacy.d.ts +5 -0
- package/legacy/legacy.js +8 -0
- package/legacy/legacy.js.map +1 -0
- package/license.md +71 -0
- package/package.json +49 -0
- package/readme.md +29 -0
- package/stl/index.d.ts +1 -0
- package/stl/index.js +2 -0
- package/stl/index.js.map +1 -0
- package/stl/stlSerializer.d.ts +20 -0
- package/stl/stlSerializer.js +135 -0
- package/stl/stlSerializer.js.map +1 -0
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
+
import { VertexBuffer } from "@babylonjs/core/Buffers/buffer.js";
|
|
3
|
+
import { Constants } from "@babylonjs/core/Engines/constants.js";
|
|
4
|
+
import { Material } from "@babylonjs/core/Materials/material.js";
|
|
5
|
+
import { PBRBaseMaterial } from "@babylonjs/core/Materials/PBR/pbrBaseMaterial.js";
|
|
6
|
+
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
|
|
7
|
+
import { Color3 } from "@babylonjs/core/Maths/math.color.js";
|
|
8
|
+
import { Matrix, Vector2 } from "@babylonjs/core/Maths/math.vector.js";
|
|
9
|
+
import { DumpTools } from "@babylonjs/core/Misc/dumpTools.js";
|
|
10
|
+
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
|
11
|
+
import { IsNoopNode } from "../exportUtils.js";
|
|
12
|
+
import { GetTextureDataAsync } from "@babylonjs/core/Misc/textureTools.js";
|
|
13
|
+
function BuildHeader() {
|
|
14
|
+
return `#usda 1.0
|
|
15
|
+
(
|
|
16
|
+
customLayerData = {
|
|
17
|
+
string creator = "Babylon.js USDZExportAsync"
|
|
18
|
+
}
|
|
19
|
+
defaultPrim = "Root"
|
|
20
|
+
metersPerUnit = 1
|
|
21
|
+
upAxis = "Y"
|
|
22
|
+
)`;
|
|
23
|
+
}
|
|
24
|
+
function BuildRootAndSceneStart(options) {
|
|
25
|
+
const alignment = options.includeAnchoringProperties === true
|
|
26
|
+
? `
|
|
27
|
+
token preliminary:anchoring:type = "${options.anchoringType}"
|
|
28
|
+
token preliminary:planeAnchoring:alignment = "${options.planeAnchoringAlignment}"`
|
|
29
|
+
: "";
|
|
30
|
+
return `def Xform "Root"
|
|
31
|
+
{
|
|
32
|
+
def Scope "Scenes" (
|
|
33
|
+
kind = "sceneLibrary"
|
|
34
|
+
)
|
|
35
|
+
{
|
|
36
|
+
def Xform "Scene" (
|
|
37
|
+
customData = {
|
|
38
|
+
bool preliminary_collidesWithEnvironment = 0
|
|
39
|
+
string sceneName = "Scene"
|
|
40
|
+
}
|
|
41
|
+
sceneName = "Scene"
|
|
42
|
+
)
|
|
43
|
+
{${alignment}
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
function BuildSceneEnd() {
|
|
47
|
+
return `
|
|
48
|
+
}
|
|
49
|
+
}`;
|
|
50
|
+
}
|
|
51
|
+
function BuildRootEnd() {
|
|
52
|
+
return `
|
|
53
|
+
}`;
|
|
54
|
+
}
|
|
55
|
+
function BuildMeshVertexCount(geometry) {
|
|
56
|
+
const count = geometry.getIndices()?.length ? geometry.getTotalIndices() : geometry.getTotalVertices();
|
|
57
|
+
return Array(count / 3)
|
|
58
|
+
.fill(3)
|
|
59
|
+
.join(", ");
|
|
60
|
+
}
|
|
61
|
+
function BuildMeshVertexIndices(geometry) {
|
|
62
|
+
const indices = geometry.getIndices();
|
|
63
|
+
const count = indices?.length ?? geometry.getTotalVertices();
|
|
64
|
+
const array = [];
|
|
65
|
+
if (indices !== null) {
|
|
66
|
+
for (let i = 0; i < count; i++) {
|
|
67
|
+
array.push(indices[i]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
for (let i = 0; i < count; i++) {
|
|
72
|
+
array.push(i);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return array.join(", ");
|
|
76
|
+
}
|
|
77
|
+
function BuildVector3Array(attribute, options, stride = 3, convertToRightHanded = false) {
|
|
78
|
+
const array = [];
|
|
79
|
+
for (let i = 0; i < attribute.length / stride; i++) {
|
|
80
|
+
const x = attribute[i * stride] * (convertToRightHanded ? -1 : 1);
|
|
81
|
+
const y = attribute[i * stride + 1];
|
|
82
|
+
const z = attribute[i * stride + 2];
|
|
83
|
+
array.push(`(${x.toPrecision(options.precision)}, ${y.toPrecision(options.precision)}, ${z.toPrecision(options.precision)})`);
|
|
84
|
+
}
|
|
85
|
+
return array.join(", ");
|
|
86
|
+
}
|
|
87
|
+
function BuildVector2Array(attribute, options) {
|
|
88
|
+
const array = [];
|
|
89
|
+
for (let i = 0; i < attribute.length / 2; i++) {
|
|
90
|
+
const x = attribute[i * 2];
|
|
91
|
+
const y = attribute[i * 2 + 1];
|
|
92
|
+
array.push(`(${x.toPrecision(options.precision)}, ${(1 - y).toPrecision(options.precision)})`);
|
|
93
|
+
}
|
|
94
|
+
return array.join(", ");
|
|
95
|
+
}
|
|
96
|
+
function BuildAdditionalAttributes(geometry, options) {
|
|
97
|
+
let string = "";
|
|
98
|
+
for (let i = 0; i < 4; i++) {
|
|
99
|
+
const id = i > 0 ? i : "";
|
|
100
|
+
const uvAttribute = geometry.getVerticesData(VertexBuffer.UVKind + (id ? id + 1 : "")); // UV names go like "uv", "uv2", "uv3", etc.
|
|
101
|
+
if (uvAttribute) {
|
|
102
|
+
string += `
|
|
103
|
+
texCoord2f[] primvars:st${id} = [${BuildVector2Array(uvAttribute, options)}] (
|
|
104
|
+
interpolation = "vertex"
|
|
105
|
+
)`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// vertex colors
|
|
109
|
+
const colorAttribute = geometry.getVerticesData(VertexBuffer.ColorKind);
|
|
110
|
+
if (colorAttribute) {
|
|
111
|
+
string += `
|
|
112
|
+
color3f[] primvars:displayColor = [${BuildVector3Array(colorAttribute, options, colorAttribute.length / geometry.getTotalVertices())}] (
|
|
113
|
+
interpolation = "vertex"
|
|
114
|
+
)`;
|
|
115
|
+
}
|
|
116
|
+
return string;
|
|
117
|
+
}
|
|
118
|
+
function BuildMesh(geometry, options, windingOrder, convertToRightHanded) {
|
|
119
|
+
const name = "Geometry";
|
|
120
|
+
const position = geometry.getVerticesData(VertexBuffer.PositionKind);
|
|
121
|
+
const normal = geometry.getVerticesData(VertexBuffer.NormalKind);
|
|
122
|
+
if (!position || !normal) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
return `
|
|
126
|
+
def Mesh "${name}"
|
|
127
|
+
{
|
|
128
|
+
uniform token orientation = "${windingOrder}"
|
|
129
|
+
int[] faceVertexCounts = [${BuildMeshVertexCount(geometry)}]
|
|
130
|
+
int[] faceVertexIndices = [${BuildMeshVertexIndices(geometry)}]
|
|
131
|
+
normal3f[] normals = [${BuildVector3Array(normal, options, undefined, convertToRightHanded)}] (
|
|
132
|
+
interpolation = "vertex"
|
|
133
|
+
)
|
|
134
|
+
point3f[] points = [${BuildVector3Array(position, options, undefined, convertToRightHanded)}]
|
|
135
|
+
${BuildAdditionalAttributes(geometry, options)}
|
|
136
|
+
uniform token subdivisionScheme = "none"
|
|
137
|
+
}
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
function BuildMeshObject(geometry, options, windingOrder, convertToRightHanded) {
|
|
141
|
+
const meshObject = BuildMesh(geometry, options, windingOrder, convertToRightHanded);
|
|
142
|
+
return `
|
|
143
|
+
def "Geometry"
|
|
144
|
+
{
|
|
145
|
+
${meshObject}
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
function BuildUSDFileAsString(dataToInsert) {
|
|
150
|
+
let output = BuildHeader();
|
|
151
|
+
output += dataToInsert;
|
|
152
|
+
return fflate.strToU8(output);
|
|
153
|
+
}
|
|
154
|
+
function BuildMatrix(matrix) {
|
|
155
|
+
const array = matrix.m;
|
|
156
|
+
return `( ${BuildMatrixRow(array, 0)}, ${BuildMatrixRow(array, 4)}, ${BuildMatrixRow(array, 8)}, ${BuildMatrixRow(array, 12)} )`;
|
|
157
|
+
}
|
|
158
|
+
function BuildMatrixRow(array, offset) {
|
|
159
|
+
return `(${array[offset + 0]}, ${array[offset + 1]}, ${array[offset + 2]}, ${array[offset + 3]})`;
|
|
160
|
+
}
|
|
161
|
+
function BuildXform(mesh, matrix) {
|
|
162
|
+
const name = "Object_" + mesh.uniqueId;
|
|
163
|
+
const transform = BuildMatrix(matrix);
|
|
164
|
+
return `def Xform "${name}" (
|
|
165
|
+
prepend references = @./geometries/Geometry_${mesh.geometry.uniqueId}.usda@</Geometry>
|
|
166
|
+
prepend apiSchemas = ["MaterialBindingAPI"]
|
|
167
|
+
)
|
|
168
|
+
{
|
|
169
|
+
matrix4d xformOp:transform = ${transform}
|
|
170
|
+
uniform token[] xformOpOrder = ["xformOp:transform"]
|
|
171
|
+
|
|
172
|
+
rel material:binding = </Root/Materials/Material_${mesh.material.uniqueId}>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
function BuildMaterials(materials, textureToExports, options) {
|
|
178
|
+
const array = [];
|
|
179
|
+
for (const uuid in materials) {
|
|
180
|
+
const material = materials[uuid];
|
|
181
|
+
array.push(BuildMaterial(material, textureToExports, options));
|
|
182
|
+
}
|
|
183
|
+
return `
|
|
184
|
+
def "Materials"
|
|
185
|
+
{
|
|
186
|
+
${array.join("")}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
`;
|
|
190
|
+
}
|
|
191
|
+
function BuildWrapping(wrapping) {
|
|
192
|
+
switch (wrapping) {
|
|
193
|
+
case Constants.TEXTURE_CLAMP_ADDRESSMODE:
|
|
194
|
+
return "clamp";
|
|
195
|
+
case Constants.TEXTURE_MIRROR_ADDRESSMODE:
|
|
196
|
+
return "mirror";
|
|
197
|
+
case Constants.TEXTURE_WRAP_ADDRESSMODE:
|
|
198
|
+
default:
|
|
199
|
+
return "repeat";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function BuildColor4(color) {
|
|
203
|
+
return `(${color.r}, ${color.g}, ${color.b}, 1.0)`;
|
|
204
|
+
}
|
|
205
|
+
function BuildVector2(vector) {
|
|
206
|
+
return `(${vector.x}, ${vector.y})`;
|
|
207
|
+
}
|
|
208
|
+
function BuildColor(color) {
|
|
209
|
+
return `(${color.r}, ${color.g}, ${color.b})`;
|
|
210
|
+
}
|
|
211
|
+
function BuildTexture(texture, material, mapType, color, textureToExports, options) {
|
|
212
|
+
const id = texture.getInternalTexture().uniqueId + "_" + texture.invertY;
|
|
213
|
+
textureToExports[id] = texture;
|
|
214
|
+
const uv = texture.coordinatesIndex > 0 ? "st" + texture.coordinatesIndex : "st";
|
|
215
|
+
const repeat = new Vector2(texture.uScale, texture.vScale);
|
|
216
|
+
const offset = new Vector2(texture.uOffset, texture.vOffset);
|
|
217
|
+
const rotation = texture.wAng;
|
|
218
|
+
// rotation is around the wrong point. after rotation we need to shift offset again so that we're rotating around the right spot
|
|
219
|
+
const xRotationOffset = Math.sin(rotation);
|
|
220
|
+
const yRotationOffset = Math.cos(rotation);
|
|
221
|
+
// texture coordinates start in the opposite corner, need to correct
|
|
222
|
+
offset.y = 1 - offset.y - repeat.y;
|
|
223
|
+
offset.x += xRotationOffset * repeat.x;
|
|
224
|
+
offset.y += (1 - yRotationOffset) * repeat.y;
|
|
225
|
+
return `
|
|
226
|
+
def Shader "PrimvarReader_${mapType}"
|
|
227
|
+
{
|
|
228
|
+
uniform token info:id = "UsdPrimvarReader_float2"
|
|
229
|
+
float2 inputs:fallback = (0.0, 0.0)
|
|
230
|
+
token inputs:varname = "${uv}"
|
|
231
|
+
float2 outputs:result
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
def Shader "Transform2d_${mapType}"
|
|
235
|
+
{
|
|
236
|
+
uniform token info:id = "UsdTransform2d"
|
|
237
|
+
token inputs:in.connect = </Root/Materials/Material_${material.uniqueId}/PrimvarReader_${mapType}.outputs:result>
|
|
238
|
+
float inputs:rotation = ${(rotation * (180 / Math.PI)).toFixed(options.precision)}
|
|
239
|
+
float2 inputs:scale = ${BuildVector2(repeat)}
|
|
240
|
+
float2 inputs:translation = ${BuildVector2(offset)}
|
|
241
|
+
float2 outputs:result
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
def Shader "Texture_${texture.uniqueId}_${mapType}"
|
|
245
|
+
{
|
|
246
|
+
uniform token info:id = "UsdUVTexture"
|
|
247
|
+
asset inputs:file = @textures/Texture_${id}.png@
|
|
248
|
+
float2 inputs:st.connect = </Root/Materials/Material_${material.uniqueId}/Transform2d_${mapType}.outputs:result>
|
|
249
|
+
${color ? "float4 inputs:scale = " + BuildColor4(color) : ""}
|
|
250
|
+
token inputs:sourceColorSpace = "${texture.gammaSpace ? "sRGB" : "raw"}"
|
|
251
|
+
token inputs:wrapS = "${BuildWrapping(texture.wrapU)}"
|
|
252
|
+
token inputs:wrapT = "${BuildWrapping(texture.wrapV)}"
|
|
253
|
+
float outputs:r
|
|
254
|
+
float outputs:g
|
|
255
|
+
float outputs:b
|
|
256
|
+
float3 outputs:rgb
|
|
257
|
+
${material.needAlphaBlending() || material.needAlphaTesting() ? "float outputs:a" : ""}
|
|
258
|
+
}`;
|
|
259
|
+
}
|
|
260
|
+
function ExtractTextureInformations(material) {
|
|
261
|
+
const defaults = {
|
|
262
|
+
diffuseMap: null,
|
|
263
|
+
diffuse: null,
|
|
264
|
+
alphaCutOff: 0,
|
|
265
|
+
emissiveMap: null,
|
|
266
|
+
emissive: null,
|
|
267
|
+
normalMap: null,
|
|
268
|
+
roughnessMap: null,
|
|
269
|
+
roughnessChannel: "a",
|
|
270
|
+
roughness: 0,
|
|
271
|
+
metalnessMap: null,
|
|
272
|
+
metalnessChannel: "r",
|
|
273
|
+
metalness: 0,
|
|
274
|
+
aoMap: null,
|
|
275
|
+
aoMapChannel: "rgb",
|
|
276
|
+
aoMapIntensity: 0,
|
|
277
|
+
alphaMap: null,
|
|
278
|
+
ior: 1,
|
|
279
|
+
clearCoatEnabled: false,
|
|
280
|
+
clearCoat: 0,
|
|
281
|
+
clearCoatMap: null,
|
|
282
|
+
clearCoatRoughness: 0,
|
|
283
|
+
clearCoatRoughnessMap: null,
|
|
284
|
+
};
|
|
285
|
+
if (material instanceof StandardMaterial) {
|
|
286
|
+
return {
|
|
287
|
+
...defaults,
|
|
288
|
+
diffuseMap: material.diffuseTexture,
|
|
289
|
+
diffuse: material.diffuseColor,
|
|
290
|
+
alphaCutOff: material.alphaCutOff,
|
|
291
|
+
emissiveMap: material.emissiveTexture,
|
|
292
|
+
emissive: material.emissiveColor,
|
|
293
|
+
roughness: 1,
|
|
294
|
+
alphaMap: material.opacityTexture,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (material instanceof PBRBaseMaterial) {
|
|
298
|
+
return {
|
|
299
|
+
...defaults,
|
|
300
|
+
diffuseMap: material._albedoTexture,
|
|
301
|
+
diffuse: material._albedoColor,
|
|
302
|
+
alphaCutOff: material._alphaCutOff,
|
|
303
|
+
emissiveMap: material._emissiveTexture,
|
|
304
|
+
emissive: material._emissiveColor,
|
|
305
|
+
normalMap: material._bumpTexture,
|
|
306
|
+
roughnessMap: material._metallicTexture,
|
|
307
|
+
roughnessChannel: material._useRoughnessFromMetallicTextureAlpha ? "a" : "g",
|
|
308
|
+
roughness: material._roughness ?? 1,
|
|
309
|
+
metalnessMap: material._metallicTexture,
|
|
310
|
+
metalnessChannel: material._useMetallnessFromMetallicTextureBlue ? "b" : "r",
|
|
311
|
+
metalness: material._metallic ?? 0,
|
|
312
|
+
aoMap: material._ambientTexture,
|
|
313
|
+
aoMapChannel: material._useAmbientInGrayScale ? "r" : "rgb",
|
|
314
|
+
aoMapIntensity: material._ambientTextureStrength,
|
|
315
|
+
alphaMap: material._opacityTexture,
|
|
316
|
+
ior: material.subSurface.indexOfRefraction,
|
|
317
|
+
clearCoatEnabled: material.clearCoat.isEnabled,
|
|
318
|
+
clearCoat: material.clearCoat.intensity,
|
|
319
|
+
clearCoatMap: material.clearCoat.texture,
|
|
320
|
+
clearCoatRoughness: material.clearCoat.roughness,
|
|
321
|
+
clearCoatRoughnessMap: material.clearCoat.useRoughnessFromMainTexture ? material.clearCoat.texture : material.clearCoat.textureRoughness,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return defaults;
|
|
325
|
+
}
|
|
326
|
+
function BuildMaterial(material, textureToExports, options) {
|
|
327
|
+
// https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html
|
|
328
|
+
const pad = " ";
|
|
329
|
+
const inputs = [];
|
|
330
|
+
const samplers = [];
|
|
331
|
+
const { diffuseMap, diffuse, alphaCutOff, emissiveMap, emissive, normalMap, roughnessMap, roughnessChannel, roughness, metalnessMap, metalnessChannel, metalness, aoMap, aoMapChannel, aoMapIntensity, alphaMap, ior, clearCoatEnabled, clearCoat, clearCoatMap, clearCoatRoughness, clearCoatRoughnessMap, } = ExtractTextureInformations(material);
|
|
332
|
+
if (diffuseMap !== null) {
|
|
333
|
+
inputs.push(`${pad}color3f inputs:diffuseColor.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${diffuseMap.uniqueId}_diffuse.outputs:rgb>`);
|
|
334
|
+
if (material.needAlphaBlending()) {
|
|
335
|
+
inputs.push(`${pad}float inputs:opacity.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${diffuseMap.uniqueId}_diffuse.outputs:a>`);
|
|
336
|
+
}
|
|
337
|
+
else if (material.needAlphaTesting()) {
|
|
338
|
+
inputs.push(`${pad}float inputs:opacity.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${diffuseMap.uniqueId}_diffuse.outputs:a>`);
|
|
339
|
+
inputs.push(`${pad}float inputs:opacityThreshold = ${alphaCutOff}`);
|
|
340
|
+
}
|
|
341
|
+
samplers.push(BuildTexture(diffuseMap, material, "diffuse", diffuse, textureToExports, options));
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
inputs.push(`${pad}color3f inputs:diffuseColor = ${BuildColor(diffuse || Color3.White())}`);
|
|
345
|
+
}
|
|
346
|
+
if (emissiveMap !== null) {
|
|
347
|
+
inputs.push(`${pad}color3f inputs:emissiveColor.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${emissiveMap.uniqueId}_emissive.outputs:rgb>`);
|
|
348
|
+
samplers.push(BuildTexture(emissiveMap, material, "emissive", emissive, textureToExports, options));
|
|
349
|
+
}
|
|
350
|
+
else if (emissive && emissive.toLuminance() > 0) {
|
|
351
|
+
inputs.push(`${pad}color3f inputs:emissiveColor = ${BuildColor(emissive)}`);
|
|
352
|
+
}
|
|
353
|
+
if (normalMap !== null) {
|
|
354
|
+
inputs.push(`${pad}normal3f inputs:normal.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${normalMap.uniqueId}_normal.outputs:rgb>`);
|
|
355
|
+
samplers.push(BuildTexture(normalMap, material, "normal", null, textureToExports, options));
|
|
356
|
+
}
|
|
357
|
+
if (aoMap !== null) {
|
|
358
|
+
inputs.push(`${pad}float inputs:occlusion.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${aoMap.uniqueId}_occlusion.outputs:${aoMapChannel}>`);
|
|
359
|
+
samplers.push(BuildTexture(aoMap, material, "occlusion", new Color3(aoMapIntensity, aoMapIntensity, aoMapIntensity), textureToExports, options));
|
|
360
|
+
}
|
|
361
|
+
if (roughnessMap !== null) {
|
|
362
|
+
inputs.push(`${pad}float inputs:roughness.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${roughnessMap.uniqueId}_roughness.outputs:${roughnessChannel}>`);
|
|
363
|
+
samplers.push(BuildTexture(roughnessMap, material, "roughness", new Color3(roughness, roughness, roughness), textureToExports, options));
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
inputs.push(`${pad}float inputs:roughness = ${roughness}`);
|
|
367
|
+
}
|
|
368
|
+
if (metalnessMap !== null) {
|
|
369
|
+
inputs.push(`${pad}float inputs:metallic.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${metalnessMap.uniqueId}_metallic.outputs:${metalnessChannel}>`);
|
|
370
|
+
samplers.push(BuildTexture(metalnessMap, material, "metallic", new Color3(metalness, metalness, metalness), textureToExports, options));
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
inputs.push(`${pad}float inputs:metallic = ${metalness}`);
|
|
374
|
+
}
|
|
375
|
+
if (alphaMap !== null) {
|
|
376
|
+
inputs.push(`${pad}float inputs:opacity.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${alphaMap.uniqueId}_opacity.outputs:r>`);
|
|
377
|
+
inputs.push(`${pad}float inputs:opacityThreshold = 0.0001`);
|
|
378
|
+
samplers.push(BuildTexture(alphaMap, material, "opacity", null, textureToExports, options));
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
inputs.push(`${pad}float inputs:opacity = ${material.alpha}`);
|
|
382
|
+
}
|
|
383
|
+
if (clearCoatEnabled) {
|
|
384
|
+
if (clearCoatMap !== null) {
|
|
385
|
+
inputs.push(`${pad}float inputs:clearcoat.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${clearCoatMap.uniqueId}_clearcoat.outputs:r>`);
|
|
386
|
+
samplers.push(BuildTexture(clearCoatMap, material, "clearcoat", new Color3(clearCoat, clearCoat, clearCoat), textureToExports, options));
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
inputs.push(`${pad}float inputs:clearcoat = ${clearCoat}`);
|
|
390
|
+
}
|
|
391
|
+
if (clearCoatRoughnessMap !== null) {
|
|
392
|
+
inputs.push(`${pad}float inputs:clearcoatRoughness.connect = </Root/Materials/Material_${material.uniqueId}/Texture_${clearCoatRoughnessMap.uniqueId}_clearcoatRoughness.outputs:g>`);
|
|
393
|
+
samplers.push(BuildTexture(clearCoatRoughnessMap, material, "clearcoatRoughness", new Color3(clearCoatRoughness, clearCoatRoughness, clearCoatRoughness), textureToExports, options));
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
inputs.push(`${pad}float inputs:clearcoatRoughness = ${clearCoatRoughness}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
inputs.push(`${pad}float inputs:ior = ${ior}`);
|
|
400
|
+
return `
|
|
401
|
+
def Material "Material_${material.uniqueId}"
|
|
402
|
+
{
|
|
403
|
+
def Shader "PreviewSurface"
|
|
404
|
+
{
|
|
405
|
+
uniform token info:id = "UsdPreviewSurface"
|
|
406
|
+
${inputs.join("\n")}
|
|
407
|
+
int inputs:useSpecularWorkflow = 0
|
|
408
|
+
token outputs:surface
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
token outputs:surface.connect = </Root/Materials/Material_${material.uniqueId}/PreviewSurface.outputs:surface>
|
|
412
|
+
|
|
413
|
+
${samplers.join("\n")}
|
|
414
|
+
|
|
415
|
+
}
|
|
416
|
+
`;
|
|
417
|
+
}
|
|
418
|
+
function BuildCamera(camera, options) {
|
|
419
|
+
const name = "Camera_" + camera.uniqueId;
|
|
420
|
+
const matrix = Matrix.RotationY(Math.PI).multiply(camera.getWorldMatrix()); // work towards positive z
|
|
421
|
+
const transform = BuildMatrix(matrix);
|
|
422
|
+
if (camera.mode === Constants.ORTHOGRAPHIC_CAMERA) {
|
|
423
|
+
return `def Camera "${name}"
|
|
424
|
+
{
|
|
425
|
+
matrix4d xformOp:transform = ${transform}
|
|
426
|
+
uniform token[] xformOpOrder = ["xformOp:transform"]
|
|
427
|
+
|
|
428
|
+
float2 clippingRange = (${camera.minZ.toPrecision(options.precision)}, ${camera.maxZ.toPrecision(options.precision)})
|
|
429
|
+
float horizontalAperture = ${((Math.abs(camera.orthoLeft || 1) + Math.abs(camera.orthoRight || 1)) * 10).toPrecision(options.precision)}
|
|
430
|
+
float verticalAperture = ${((Math.abs(camera.orthoTop || 1) + Math.abs(camera.orthoBottom || 1)) * 10).toPrecision(options.precision)}
|
|
431
|
+
token projection = "orthographic"
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
`;
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
const aspect = camera.getEngine().getAspectRatio(camera);
|
|
438
|
+
const sensorwidth = options.cameraSensorWidth || 35;
|
|
439
|
+
return `def Camera "${name}"
|
|
440
|
+
{
|
|
441
|
+
matrix4d xformOp:transform = ${transform}
|
|
442
|
+
uniform token[] xformOpOrder = ["xformOp:transform"]
|
|
443
|
+
|
|
444
|
+
float2 clippingRange = (${camera.minZ.toPrecision(options.precision)}, ${camera.maxZ.toPrecision(options.precision)})
|
|
445
|
+
float focalLength = ${(sensorwidth / (2 * Math.tan(camera.fov * 0.5))).toPrecision(options.precision)}
|
|
446
|
+
token projection = "perspective"
|
|
447
|
+
float horizontalAperture = ${(sensorwidth * aspect).toPrecision(options.precision)}
|
|
448
|
+
float verticalAperture = ${(sensorwidth / aspect).toPrecision(options.precision)}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
`;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function ExtractMeshInformations(mesh) {
|
|
455
|
+
mesh.computeWorldMatrix(true);
|
|
456
|
+
const matrix = mesh.getWorldMatrix().clone();
|
|
457
|
+
const sceneIsRightHanded = mesh.getScene().useRightHandedSystem;
|
|
458
|
+
let sideOrientation = mesh.material?._getEffectiveOrientation(mesh) ?? mesh.sideOrientation;
|
|
459
|
+
let convertToRightHanded = !sceneIsRightHanded;
|
|
460
|
+
// Search for a root conversion node from the glTF loader in the mesh's ancestors.
|
|
461
|
+
let current = mesh.parent;
|
|
462
|
+
while (current) {
|
|
463
|
+
if (IsNoopNode(current, sceneIsRightHanded) && current.parent === null) {
|
|
464
|
+
if (!sceneIsRightHanded) {
|
|
465
|
+
// If it's a RH->LH node, cancel out its inversion effect on the mesh's matrix and winding order.
|
|
466
|
+
matrix.multiplyToRef(current.getWorldMatrix().invert(), matrix);
|
|
467
|
+
sideOrientation = sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
|
|
468
|
+
}
|
|
469
|
+
convertToRightHanded = false;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
current = current.parent;
|
|
473
|
+
}
|
|
474
|
+
if (matrix.determinant() < 0) {
|
|
475
|
+
// RealityKit doesn't seem to automatically flip faces of a mesh with negative scale, like other engines do (including us).
|
|
476
|
+
Tools.Warn(`Mesh ${mesh.name} has a negative scale, which may look incorrect in destinations like QuickLook.`);
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
matrix,
|
|
480
|
+
windingOrder: sideOrientation === Material.ClockWiseSideOrientation ? "leftHanded" : "rightHanded",
|
|
481
|
+
convertToRightHanded,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
*
|
|
486
|
+
* @param scene scene to export
|
|
487
|
+
* @param options options to configure the export
|
|
488
|
+
* @param meshPredicate predicate to filter the meshes to export
|
|
489
|
+
* @returns a uint8 array containing the USDZ file
|
|
490
|
+
* @see [Simple sphere](https://playground.babylonjs.com/#H2G5XW#6)
|
|
491
|
+
* @see [Red sphere](https://playground.babylonjs.com/#H2G5XW#7)
|
|
492
|
+
* @see [Boombox](https://playground.babylonjs.com/#5N3RWK#5)
|
|
493
|
+
*/
|
|
494
|
+
export async function USDZExportAsync(scene, options, meshPredicate) {
|
|
495
|
+
const localOptions = {
|
|
496
|
+
fflateUrl: "https://unpkg.com/fflate@0.8.2",
|
|
497
|
+
includeAnchoringProperties: true,
|
|
498
|
+
anchoringType: "plane",
|
|
499
|
+
planeAnchoringAlignment: "horizontal",
|
|
500
|
+
modelFileName: "model.usda",
|
|
501
|
+
precision: 5,
|
|
502
|
+
exportCamera: false,
|
|
503
|
+
cameraSensorWidth: 35,
|
|
504
|
+
...options,
|
|
505
|
+
};
|
|
506
|
+
// Get the fflate library
|
|
507
|
+
if (typeof fflate === "undefined") {
|
|
508
|
+
await Tools.LoadScriptAsync(localOptions.fflateUrl);
|
|
509
|
+
}
|
|
510
|
+
// Start the export
|
|
511
|
+
const files = {};
|
|
512
|
+
// model file should be first in USDZ archive so we init it here
|
|
513
|
+
files[localOptions.modelFileName] = null;
|
|
514
|
+
let output = BuildHeader();
|
|
515
|
+
output += BuildRootAndSceneStart(localOptions);
|
|
516
|
+
const materialToExports = {};
|
|
517
|
+
// Meshes
|
|
518
|
+
for (const abstractMesh of scene.meshes) {
|
|
519
|
+
if (abstractMesh.getTotalVertices() === 0) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const mesh = abstractMesh;
|
|
523
|
+
const geometry = mesh.geometry;
|
|
524
|
+
const material = mesh.material;
|
|
525
|
+
if (!material || !geometry || (meshPredicate && !meshPredicate(mesh))) {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
const supportedMaterials = ["StandardMaterial", "PBRMaterial", "PBRMetallicRoughnessMaterial"];
|
|
529
|
+
if (supportedMaterials.indexOf(material.getClassName()) !== -1) {
|
|
530
|
+
const geometryFileName = "geometries/Geometry_" + geometry.uniqueId + ".usda";
|
|
531
|
+
const { matrix, windingOrder, convertToRightHanded } = ExtractMeshInformations(mesh);
|
|
532
|
+
if (!(geometryFileName in files)) {
|
|
533
|
+
const meshObject = BuildMeshObject(geometry, localOptions, windingOrder, convertToRightHanded);
|
|
534
|
+
files[geometryFileName] = BuildUSDFileAsString(meshObject);
|
|
535
|
+
}
|
|
536
|
+
if (!(material.uniqueId in materialToExports)) {
|
|
537
|
+
materialToExports[material.uniqueId] = material;
|
|
538
|
+
}
|
|
539
|
+
output += BuildXform(mesh, matrix);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
Tools.Warn("USDZExportAsync does not support this material type: " + material.getClassName());
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
// Camera
|
|
546
|
+
if (scene.activeCamera && localOptions.exportCamera) {
|
|
547
|
+
output += BuildCamera(scene.activeCamera, localOptions);
|
|
548
|
+
}
|
|
549
|
+
// Close scene
|
|
550
|
+
output += BuildSceneEnd();
|
|
551
|
+
// Materials
|
|
552
|
+
const textureToExports = {};
|
|
553
|
+
output += BuildMaterials(materialToExports, textureToExports, localOptions);
|
|
554
|
+
// Close root
|
|
555
|
+
output += BuildRootEnd();
|
|
556
|
+
// Compress
|
|
557
|
+
files[localOptions.modelFileName] = fflate.strToU8(output);
|
|
558
|
+
// Textures
|
|
559
|
+
for (const id in textureToExports) {
|
|
560
|
+
const texture = textureToExports[id];
|
|
561
|
+
const size = texture.getSize();
|
|
562
|
+
// eslint-disable-next-line no-await-in-loop
|
|
563
|
+
const textureData = await GetTextureDataAsync(texture);
|
|
564
|
+
// eslint-disable-next-line no-await-in-loop
|
|
565
|
+
const fileContent = await DumpTools.DumpDataAsync(size.width, size.height, textureData, "image/png", undefined, false, true);
|
|
566
|
+
files[`textures/Texture_${id}.png`] = new Uint8Array(fileContent).slice(); // This is to avoid getting a link and not a copy
|
|
567
|
+
}
|
|
568
|
+
// 64 byte alignment
|
|
569
|
+
// https://github.com/101arrowz/fflate/issues/39#issuecomment-777263109
|
|
570
|
+
let offset = 0;
|
|
571
|
+
for (const filename in files) {
|
|
572
|
+
const file = files[filename];
|
|
573
|
+
if (!file) {
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
const headerSize = 34 + filename.length;
|
|
577
|
+
offset += headerSize;
|
|
578
|
+
const offsetMod64 = offset & 63;
|
|
579
|
+
if (offsetMod64 !== 4) {
|
|
580
|
+
const padLength = 64 - offsetMod64;
|
|
581
|
+
const padding = new Uint8Array(padLength);
|
|
582
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
583
|
+
files[filename] = [file, { extra: { 12345: padding } }];
|
|
584
|
+
}
|
|
585
|
+
offset = file.length;
|
|
586
|
+
}
|
|
587
|
+
return fflate.zipSync(files, { level: 0 });
|
|
588
|
+
}
|
|
589
|
+
//# sourceMappingURL=usdzExporter.js.map
|