minerender 2.1.0-alpha.49 → 2.1.0-alpha.50
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/dist/browser/index.d.mts +35 -2
- package/dist/browser/index.d.ts +35 -2
- package/dist/browser/index.js +2712 -152
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +2722 -117
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +2615 -22
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +35 -2
- package/dist/node/index.d.ts +35 -2
- package/dist/node/index.js +2715 -153
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +2722 -117
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.mjs
CHANGED
|
@@ -3404,7 +3404,7 @@ var init_SceneObject = __esm({
|
|
|
3404
3404
|
});
|
|
3405
3405
|
|
|
3406
3406
|
// src/model/ModelCulling.ts
|
|
3407
|
-
import { Vector3 as
|
|
3407
|
+
import { Vector3 as Vector39 } from "three";
|
|
3408
3408
|
var ModelCulling;
|
|
3409
3409
|
var init_ModelCulling = __esm({
|
|
3410
3410
|
"src/model/ModelCulling.ts"() {
|
|
@@ -3413,7 +3413,7 @@ var init_ModelCulling = __esm({
|
|
|
3413
3413
|
static toLocalMask(worldMask, rotation) {
|
|
3414
3414
|
let localMask = 0;
|
|
3415
3415
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
3416
|
-
const normal = new
|
|
3416
|
+
const normal = new Vector39(...offset).applyEuler(rotation);
|
|
3417
3417
|
const worldFace = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
3418
3418
|
if (worldFace < 0) return 0;
|
|
3419
3419
|
if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
|
|
@@ -3447,15 +3447,15 @@ var init_ModelCulling = __esm({
|
|
|
3447
3447
|
|
|
3448
3448
|
// src/three/BufferGeometryUtils.js
|
|
3449
3449
|
import {
|
|
3450
|
-
BufferAttribute as
|
|
3451
|
-
BufferGeometry,
|
|
3452
|
-
Float32BufferAttribute as
|
|
3450
|
+
BufferAttribute as BufferAttribute4,
|
|
3451
|
+
BufferGeometry as BufferGeometry2,
|
|
3452
|
+
Float32BufferAttribute as Float32BufferAttribute4,
|
|
3453
3453
|
InterleavedBuffer,
|
|
3454
3454
|
InterleavedBufferAttribute,
|
|
3455
3455
|
TriangleFanDrawMode,
|
|
3456
3456
|
TriangleStripDrawMode,
|
|
3457
3457
|
TrianglesDrawMode,
|
|
3458
|
-
Vector3 as
|
|
3458
|
+
Vector3 as Vector310
|
|
3459
3459
|
} from "three";
|
|
3460
3460
|
function computeTangents(geometry) {
|
|
3461
3461
|
geometry.computeTangents();
|
|
@@ -3468,7 +3468,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
|
|
|
3468
3468
|
const attributes = {};
|
|
3469
3469
|
const morphAttributes = {};
|
|
3470
3470
|
const morphTargetsRelative = geometries[0].morphTargetsRelative;
|
|
3471
|
-
const mergedGeometry = new
|
|
3471
|
+
const mergedGeometry = new BufferGeometry2();
|
|
3472
3472
|
let offset = 0;
|
|
3473
3473
|
for (let i = 0; i < geometries.length; ++i) {
|
|
3474
3474
|
const geometry = geometries[i];
|
|
@@ -3592,7 +3592,7 @@ function mergeBufferAttributes(attributes) {
|
|
|
3592
3592
|
array.set(attributes[i].array, offset);
|
|
3593
3593
|
offset += attributes[i].array.length;
|
|
3594
3594
|
}
|
|
3595
|
-
return new
|
|
3595
|
+
return new BufferAttribute4(array, itemSize, normalized);
|
|
3596
3596
|
}
|
|
3597
3597
|
function interleaveAttributes(attributes) {
|
|
3598
3598
|
let TypedArray;
|
|
@@ -3701,13 +3701,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
|
|
|
3701
3701
|
const name = attributeNames[i];
|
|
3702
3702
|
const oldAttribute = geometry.getAttribute(name);
|
|
3703
3703
|
const buffer = new oldAttribute.array.constructor(attrArrays[name]);
|
|
3704
|
-
const attribute = new
|
|
3704
|
+
const attribute = new BufferAttribute4(buffer, oldAttribute.itemSize, oldAttribute.normalized);
|
|
3705
3705
|
result.setAttribute(name, attribute);
|
|
3706
3706
|
if (name in morphAttrsArrays) {
|
|
3707
3707
|
for (let j = 0; j < morphAttrsArrays[name].length; j++) {
|
|
3708
3708
|
const oldMorphAttribute = geometry.morphAttributes[name][j];
|
|
3709
3709
|
const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
|
|
3710
|
-
const morphAttribute = new
|
|
3710
|
+
const morphAttribute = new BufferAttribute4(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
|
|
3711
3711
|
result.morphAttributes[name][j] = morphAttribute;
|
|
3712
3712
|
}
|
|
3713
3713
|
}
|
|
@@ -3774,15 +3774,15 @@ function computeMorphedAttributes(object) {
|
|
|
3774
3774
|
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
|
|
3775
3775
|
return null;
|
|
3776
3776
|
}
|
|
3777
|
-
const _vA = new
|
|
3778
|
-
const _vB = new
|
|
3779
|
-
const _vC = new
|
|
3780
|
-
const _tempA = new
|
|
3781
|
-
const _tempB = new
|
|
3782
|
-
const _tempC = new
|
|
3783
|
-
const _morphA = new
|
|
3784
|
-
const _morphB = new
|
|
3785
|
-
const _morphC = new
|
|
3777
|
+
const _vA = new Vector310();
|
|
3778
|
+
const _vB = new Vector310();
|
|
3779
|
+
const _vC = new Vector310();
|
|
3780
|
+
const _tempA = new Vector310();
|
|
3781
|
+
const _tempB = new Vector310();
|
|
3782
|
+
const _tempC = new Vector310();
|
|
3783
|
+
const _morphA = new Vector310();
|
|
3784
|
+
const _morphB = new Vector310();
|
|
3785
|
+
const _morphC = new Vector310();
|
|
3786
3786
|
function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
|
|
3787
3787
|
_vA.fromBufferAttribute(attribute, a2);
|
|
3788
3788
|
_vB.fromBufferAttribute(attribute, b2);
|
|
@@ -3977,8 +3977,8 @@ function computeMorphedAttributes(object) {
|
|
|
3977
3977
|
}
|
|
3978
3978
|
}
|
|
3979
3979
|
}
|
|
3980
|
-
const morphedPositionAttribute = new
|
|
3981
|
-
const morphedNormalAttribute = new
|
|
3980
|
+
const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
|
|
3981
|
+
const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
|
|
3982
3982
|
return {
|
|
3983
3983
|
positionAttribute,
|
|
3984
3984
|
normalAttribute,
|
|
@@ -3992,7 +3992,7 @@ var init_BufferGeometryUtils = __esm({
|
|
|
3992
3992
|
});
|
|
3993
3993
|
|
|
3994
3994
|
// src/model/scene/ModelObject.ts
|
|
3995
|
-
import { BoxGeometry as BoxGeometry5, BufferAttribute as
|
|
3995
|
+
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color7, Euler as Euler6, Matrix4 as Matrix46 } from "three";
|
|
3996
3996
|
function isModelObject(obj) {
|
|
3997
3997
|
return obj.isModelObject;
|
|
3998
3998
|
}
|
|
@@ -4065,19 +4065,19 @@ var init_ModelObject = __esm({
|
|
|
4065
4065
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
4066
4066
|
const tint = this.options.tints[tintIndex];
|
|
4067
4067
|
if (tint === void 0) continue;
|
|
4068
|
-
const color = new
|
|
4068
|
+
const color = new Color7(tint);
|
|
4069
4069
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
4070
4070
|
color.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
4071
4071
|
}
|
|
4072
4072
|
}
|
|
4073
|
-
elGeo.setAttribute("color", new
|
|
4073
|
+
elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
|
|
4074
4074
|
}
|
|
4075
|
-
elGeo.applyMatrix4(new
|
|
4076
|
-
elGeo.applyMatrix4(new
|
|
4075
|
+
elGeo.applyMatrix4(new Matrix46().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
|
|
4076
|
+
elGeo.applyMatrix4(new Matrix46().makeTranslation(el.from[0], el.from[1], el.from[2]));
|
|
4077
4077
|
if (el.rotation) {
|
|
4078
4078
|
applyElementRotation(el.rotation, elGeo);
|
|
4079
4079
|
}
|
|
4080
|
-
elGeo.applyMatrix4(new
|
|
4080
|
+
elGeo.applyMatrix4(new Matrix46().makeTranslation(-8, -8, -8));
|
|
4081
4081
|
if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
|
|
4082
4082
|
if (this.options.mergeMeshes) {
|
|
4083
4083
|
allGeos.push(elGeo);
|
|
@@ -4192,7 +4192,7 @@ var init_fluidBlocks = __esm({
|
|
|
4192
4192
|
});
|
|
4193
4193
|
|
|
4194
4194
|
// src/model/fluid/FluidGeometry.ts
|
|
4195
|
-
import { BufferGeometry as
|
|
4195
|
+
import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
|
|
4196
4196
|
function getBlockFluidState(key, state) {
|
|
4197
4197
|
const rule = key && fluidRules[key.toNamespacedString()];
|
|
4198
4198
|
if (rule) return {
|
|
@@ -4210,7 +4210,7 @@ function ownHeight(sample) {
|
|
|
4210
4210
|
return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
|
|
4211
4211
|
}
|
|
4212
4212
|
function createFluidGeometry(kind, sample) {
|
|
4213
|
-
const geometry = new
|
|
4213
|
+
const geometry = new BufferGeometry3();
|
|
4214
4214
|
const positions = [], normals = [], uvs = [], indices = [];
|
|
4215
4215
|
const self = sample(0, 0, 0);
|
|
4216
4216
|
const height = (x, z) => {
|
|
@@ -4309,9 +4309,9 @@ function createFluidGeometry(kind, sample) {
|
|
|
4309
4309
|
1
|
|
4310
4310
|
);
|
|
4311
4311
|
}
|
|
4312
|
-
geometry.setAttribute("position", new
|
|
4313
|
-
geometry.setAttribute("normal", new
|
|
4314
|
-
geometry.setAttribute("uv", new
|
|
4312
|
+
geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
|
|
4313
|
+
geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
|
|
4314
|
+
geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
|
|
4315
4315
|
geometry.setIndex(indices);
|
|
4316
4316
|
return geometry;
|
|
4317
4317
|
}
|
|
@@ -4331,7 +4331,7 @@ __export(FluidModelObject_exports, {
|
|
|
4331
4331
|
FluidModelObject: () => FluidModelObject,
|
|
4332
4332
|
sampleFluid: () => sampleFluid
|
|
4333
4333
|
});
|
|
4334
|
-
import { BufferAttribute as
|
|
4334
|
+
import { BufferAttribute as BufferAttribute6, Color as Color8, DoubleSide as DoubleSide3 } from "three";
|
|
4335
4335
|
function sampleFluid(kind, sample) {
|
|
4336
4336
|
const cells = [];
|
|
4337
4337
|
const key = [];
|
|
@@ -4382,10 +4382,10 @@ var init_FluidModelObject = __esm({
|
|
|
4382
4382
|
}
|
|
4383
4383
|
}
|
|
4384
4384
|
geometry.clearGroups();
|
|
4385
|
-
const color = new
|
|
4385
|
+
const color = new Color8(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
4386
4386
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
4387
4387
|
for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
|
|
4388
|
-
geometry.setAttribute("color", new
|
|
4388
|
+
geometry.setAttribute("color", new BufferAttribute6(colors, 3));
|
|
4389
4389
|
geometry.computeBoundingBox();
|
|
4390
4390
|
geometry.computeBoundingSphere();
|
|
4391
4391
|
if (this.options.instanceMeshes) {
|
|
@@ -4399,7 +4399,7 @@ var init_FluidModelObject = __esm({
|
|
|
4399
4399
|
super.applyTextures();
|
|
4400
4400
|
this.iterateAllMeshes((mesh) => {
|
|
4401
4401
|
const material = mesh.material;
|
|
4402
|
-
material.side =
|
|
4402
|
+
material.side = DoubleSide3;
|
|
4403
4403
|
material.forceSinglePass = true;
|
|
4404
4404
|
material.depthWrite = !material.transparent;
|
|
4405
4405
|
});
|
|
@@ -4789,6 +4789,37 @@ init_PersistentCache();
|
|
|
4789
4789
|
init_CanvasCompat();
|
|
4790
4790
|
init_CanvasImage();
|
|
4791
4791
|
|
|
4792
|
+
// src/canvas/trimCanvas.ts
|
|
4793
|
+
init_CanvasCompat();
|
|
4794
|
+
function trimCanvas(source) {
|
|
4795
|
+
if (source.width === 0 || source.height === 0) return createCanvas(1, 1);
|
|
4796
|
+
const canvas = createCanvas(source.width, source.height);
|
|
4797
|
+
const context = canvas.getContext("2d");
|
|
4798
|
+
if (!context) throw new Error("Image export requires a 2D canvas context");
|
|
4799
|
+
context.drawImage(source, 0, 0);
|
|
4800
|
+
const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;
|
|
4801
|
+
let left = canvas.width, top = canvas.height, right = -1, bottom = -1;
|
|
4802
|
+
for (let y = 0; y < canvas.height; y++) {
|
|
4803
|
+
for (let x = 0; x < canvas.width; x++) {
|
|
4804
|
+
if (pixels[(y * canvas.width + x) * 4 + 3] === 0) continue;
|
|
4805
|
+
left = Math.min(left, x);
|
|
4806
|
+
top = Math.min(top, y);
|
|
4807
|
+
right = Math.max(right, x);
|
|
4808
|
+
bottom = Math.max(bottom, y);
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4811
|
+
if (right < left) {
|
|
4812
|
+
canvas.width = canvas.height = 1;
|
|
4813
|
+
return canvas;
|
|
4814
|
+
}
|
|
4815
|
+
const width = right - left + 1, height = bottom - top + 1;
|
|
4816
|
+
const cropped = context.getImageData(left, top, width, height);
|
|
4817
|
+
canvas.width = width;
|
|
4818
|
+
canvas.height = height;
|
|
4819
|
+
context.putImageData(cropped, 0, 0);
|
|
4820
|
+
return canvas;
|
|
4821
|
+
}
|
|
4822
|
+
|
|
4792
4823
|
// src/entity/scene/EntityObject.ts
|
|
4793
4824
|
init_SceneObject();
|
|
4794
4825
|
init_Caching();
|
|
@@ -4910,6 +4941,2555 @@ function isEntityObject(obj) {
|
|
|
4910
4941
|
// src/error/index.ts
|
|
4911
4942
|
init_MineRenderError();
|
|
4912
4943
|
|
|
4944
|
+
// src/export/SceneExporter.ts
|
|
4945
|
+
import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color6, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix45, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
|
|
4946
|
+
|
|
4947
|
+
// ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
|
|
4948
|
+
import {
|
|
4949
|
+
Color as Color3,
|
|
4950
|
+
Matrix3,
|
|
4951
|
+
Vector2 as Vector22,
|
|
4952
|
+
Vector3 as Vector36
|
|
4953
|
+
} from "three";
|
|
4954
|
+
var OBJExporter = class {
|
|
4955
|
+
parse(object) {
|
|
4956
|
+
let output = "";
|
|
4957
|
+
let indexVertex = 0;
|
|
4958
|
+
let indexVertexUvs = 0;
|
|
4959
|
+
let indexNormals = 0;
|
|
4960
|
+
const vertex = new Vector36();
|
|
4961
|
+
const color = new Color3();
|
|
4962
|
+
const normal = new Vector36();
|
|
4963
|
+
const uv = new Vector22();
|
|
4964
|
+
const face = [];
|
|
4965
|
+
function parseMesh(mesh) {
|
|
4966
|
+
let nbVertex = 0;
|
|
4967
|
+
let nbNormals = 0;
|
|
4968
|
+
let nbVertexUvs = 0;
|
|
4969
|
+
const geometry = mesh.geometry;
|
|
4970
|
+
const normalMatrixWorld = new Matrix3();
|
|
4971
|
+
const vertices = geometry.getAttribute("position");
|
|
4972
|
+
const normals = geometry.getAttribute("normal");
|
|
4973
|
+
const uvs = geometry.getAttribute("uv");
|
|
4974
|
+
const indices = geometry.getIndex();
|
|
4975
|
+
output += "o " + mesh.name + "\n";
|
|
4976
|
+
if (mesh.material && mesh.material.name) {
|
|
4977
|
+
output += "usemtl " + mesh.material.name + "\n";
|
|
4978
|
+
}
|
|
4979
|
+
if (vertices !== void 0) {
|
|
4980
|
+
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
|
|
4981
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
4982
|
+
vertex.applyMatrix4(mesh.matrixWorld);
|
|
4983
|
+
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
if (uvs !== void 0) {
|
|
4987
|
+
for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
|
|
4988
|
+
uv.fromBufferAttribute(uvs, i);
|
|
4989
|
+
output += "vt " + uv.x + " " + uv.y + "\n";
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
if (normals !== void 0) {
|
|
4993
|
+
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
|
|
4994
|
+
for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
|
|
4995
|
+
normal.fromBufferAttribute(normals, i);
|
|
4996
|
+
normal.applyMatrix3(normalMatrixWorld).normalize();
|
|
4997
|
+
output += "vn " + normal.x + " " + normal.y + " " + normal.z + "\n";
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
if (indices !== null) {
|
|
5001
|
+
for (let i = 0, l = indices.count; i < l; i += 3) {
|
|
5002
|
+
for (let m = 0; m < 3; m++) {
|
|
5003
|
+
const j = indices.getX(i + m) + 1;
|
|
5004
|
+
face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
|
|
5005
|
+
}
|
|
5006
|
+
output += "f " + face.join(" ") + "\n";
|
|
5007
|
+
}
|
|
5008
|
+
} else {
|
|
5009
|
+
for (let i = 0, l = vertices.count; i < l; i += 3) {
|
|
5010
|
+
for (let m = 0; m < 3; m++) {
|
|
5011
|
+
const j = i + m + 1;
|
|
5012
|
+
face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
|
|
5013
|
+
}
|
|
5014
|
+
output += "f " + face.join(" ") + "\n";
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
indexVertex += nbVertex;
|
|
5018
|
+
indexVertexUvs += nbVertexUvs;
|
|
5019
|
+
indexNormals += nbNormals;
|
|
5020
|
+
}
|
|
5021
|
+
function parseLine(line) {
|
|
5022
|
+
let nbVertex = 0;
|
|
5023
|
+
const geometry = line.geometry;
|
|
5024
|
+
const type = line.type;
|
|
5025
|
+
const vertices = geometry.getAttribute("position");
|
|
5026
|
+
output += "o " + line.name + "\n";
|
|
5027
|
+
if (vertices !== void 0) {
|
|
5028
|
+
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
|
|
5029
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5030
|
+
vertex.applyMatrix4(line.matrixWorld);
|
|
5031
|
+
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
if (type === "Line") {
|
|
5035
|
+
output += "l ";
|
|
5036
|
+
for (let j = 1, l = vertices.count; j <= l; j++) {
|
|
5037
|
+
output += indexVertex + j + " ";
|
|
5038
|
+
}
|
|
5039
|
+
output += "\n";
|
|
5040
|
+
}
|
|
5041
|
+
if (type === "LineSegments") {
|
|
5042
|
+
for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
|
|
5043
|
+
output += "l " + (indexVertex + j) + " " + (indexVertex + k) + "\n";
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
indexVertex += nbVertex;
|
|
5047
|
+
}
|
|
5048
|
+
function parsePoints(points) {
|
|
5049
|
+
let nbVertex = 0;
|
|
5050
|
+
const geometry = points.geometry;
|
|
5051
|
+
const vertices = geometry.getAttribute("position");
|
|
5052
|
+
const colors = geometry.getAttribute("color");
|
|
5053
|
+
output += "o " + points.name + "\n";
|
|
5054
|
+
if (vertices !== void 0) {
|
|
5055
|
+
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
|
|
5056
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5057
|
+
vertex.applyMatrix4(points.matrixWorld);
|
|
5058
|
+
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
5059
|
+
if (colors !== void 0) {
|
|
5060
|
+
color.fromBufferAttribute(colors, i).convertLinearToSRGB();
|
|
5061
|
+
output += " " + color.r + " " + color.g + " " + color.b;
|
|
5062
|
+
}
|
|
5063
|
+
output += "\n";
|
|
5064
|
+
}
|
|
5065
|
+
output += "p ";
|
|
5066
|
+
for (let j = 1, l = vertices.count; j <= l; j++) {
|
|
5067
|
+
output += indexVertex + j + " ";
|
|
5068
|
+
}
|
|
5069
|
+
output += "\n";
|
|
5070
|
+
}
|
|
5071
|
+
indexVertex += nbVertex;
|
|
5072
|
+
}
|
|
5073
|
+
object.traverse(function(child) {
|
|
5074
|
+
if (child.isMesh === true) {
|
|
5075
|
+
parseMesh(child);
|
|
5076
|
+
}
|
|
5077
|
+
if (child.isLine === true) {
|
|
5078
|
+
parseLine(child);
|
|
5079
|
+
}
|
|
5080
|
+
if (child.isPoints === true) {
|
|
5081
|
+
parsePoints(child);
|
|
5082
|
+
}
|
|
5083
|
+
});
|
|
5084
|
+
return output;
|
|
5085
|
+
}
|
|
5086
|
+
};
|
|
5087
|
+
|
|
5088
|
+
// ../../node_modules/three/examples/jsm/exporters/PLYExporter.js
|
|
5089
|
+
import {
|
|
5090
|
+
Matrix3 as Matrix32,
|
|
5091
|
+
Vector3 as Vector37,
|
|
5092
|
+
Color as Color4
|
|
5093
|
+
} from "three";
|
|
5094
|
+
var PLYExporter = class {
|
|
5095
|
+
parse(object, onDone, options = {}) {
|
|
5096
|
+
function traverseMeshes(cb) {
|
|
5097
|
+
object.traverse(function(child) {
|
|
5098
|
+
if (child.isMesh === true || child.isPoints) {
|
|
5099
|
+
const mesh = child;
|
|
5100
|
+
const geometry = mesh.geometry;
|
|
5101
|
+
if (geometry.hasAttribute("position") === true) {
|
|
5102
|
+
cb(mesh, geometry);
|
|
5103
|
+
}
|
|
5104
|
+
}
|
|
5105
|
+
});
|
|
5106
|
+
}
|
|
5107
|
+
const defaultOptions = {
|
|
5108
|
+
binary: false,
|
|
5109
|
+
excludeAttributes: [],
|
|
5110
|
+
// normal, uv, color, index
|
|
5111
|
+
littleEndian: false
|
|
5112
|
+
};
|
|
5113
|
+
options = Object.assign(defaultOptions, options);
|
|
5114
|
+
const excludeAttributes = options.excludeAttributes;
|
|
5115
|
+
let includeIndices = true;
|
|
5116
|
+
let includeNormals = false;
|
|
5117
|
+
let includeColors = false;
|
|
5118
|
+
let includeUVs = false;
|
|
5119
|
+
let vertexCount = 0;
|
|
5120
|
+
let faceCount = 0;
|
|
5121
|
+
object.traverse(function(child) {
|
|
5122
|
+
if (child.isMesh === true) {
|
|
5123
|
+
const mesh = child;
|
|
5124
|
+
const geometry = mesh.geometry;
|
|
5125
|
+
const vertices = geometry.getAttribute("position");
|
|
5126
|
+
const normals = geometry.getAttribute("normal");
|
|
5127
|
+
const uvs = geometry.getAttribute("uv");
|
|
5128
|
+
const colors = geometry.getAttribute("color");
|
|
5129
|
+
const indices = geometry.getIndex();
|
|
5130
|
+
if (vertices === void 0) {
|
|
5131
|
+
return;
|
|
5132
|
+
}
|
|
5133
|
+
vertexCount += vertices.count;
|
|
5134
|
+
faceCount += indices ? indices.count / 3 : vertices.count / 3;
|
|
5135
|
+
if (normals !== void 0) includeNormals = true;
|
|
5136
|
+
if (uvs !== void 0) includeUVs = true;
|
|
5137
|
+
if (colors !== void 0) includeColors = true;
|
|
5138
|
+
} else if (child.isPoints) {
|
|
5139
|
+
const mesh = child;
|
|
5140
|
+
const geometry = mesh.geometry;
|
|
5141
|
+
const vertices = geometry.getAttribute("position");
|
|
5142
|
+
const normals = geometry.getAttribute("normal");
|
|
5143
|
+
const colors = geometry.getAttribute("color");
|
|
5144
|
+
vertexCount += vertices.count;
|
|
5145
|
+
if (normals !== void 0) includeNormals = true;
|
|
5146
|
+
if (colors !== void 0) includeColors = true;
|
|
5147
|
+
includeIndices = false;
|
|
5148
|
+
}
|
|
5149
|
+
});
|
|
5150
|
+
const tempColor = new Color4();
|
|
5151
|
+
includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
|
|
5152
|
+
includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
|
|
5153
|
+
includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
|
|
5154
|
+
includeUVs = includeUVs && excludeAttributes.indexOf("uv") === -1;
|
|
5155
|
+
if (includeIndices && faceCount !== Math.floor(faceCount)) {
|
|
5156
|
+
console.error(
|
|
5157
|
+
"PLYExporter: Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3."
|
|
5158
|
+
);
|
|
5159
|
+
return null;
|
|
5160
|
+
}
|
|
5161
|
+
const indexByteCount = 4;
|
|
5162
|
+
let header = `ply
|
|
5163
|
+
format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
|
|
5164
|
+
element vertex ${vertexCount}
|
|
5165
|
+
property float x
|
|
5166
|
+
property float y
|
|
5167
|
+
property float z
|
|
5168
|
+
`;
|
|
5169
|
+
if (includeNormals === true) {
|
|
5170
|
+
header += "property float nx\nproperty float ny\nproperty float nz\n";
|
|
5171
|
+
}
|
|
5172
|
+
if (includeUVs === true) {
|
|
5173
|
+
header += "property float s\nproperty float t\n";
|
|
5174
|
+
}
|
|
5175
|
+
if (includeColors === true) {
|
|
5176
|
+
header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
|
|
5177
|
+
}
|
|
5178
|
+
if (includeIndices === true) {
|
|
5179
|
+
header += `element face ${faceCount}
|
|
5180
|
+
property list uchar int vertex_index
|
|
5181
|
+
`;
|
|
5182
|
+
}
|
|
5183
|
+
header += "end_header\n";
|
|
5184
|
+
const vertex = new Vector37();
|
|
5185
|
+
const normalMatrixWorld = new Matrix32();
|
|
5186
|
+
let result = null;
|
|
5187
|
+
if (options.binary === true) {
|
|
5188
|
+
const headerBin = new TextEncoder().encode(header);
|
|
5189
|
+
const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
|
|
5190
|
+
const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
|
|
5191
|
+
const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
|
|
5192
|
+
new Uint8Array(output.buffer).set(headerBin, 0);
|
|
5193
|
+
let vOffset = headerBin.length;
|
|
5194
|
+
let fOffset = headerBin.length + vertexListLength;
|
|
5195
|
+
let writtenVertices = 0;
|
|
5196
|
+
traverseMeshes(function(mesh, geometry) {
|
|
5197
|
+
const vertices = geometry.getAttribute("position");
|
|
5198
|
+
const normals = geometry.getAttribute("normal");
|
|
5199
|
+
const uvs = geometry.getAttribute("uv");
|
|
5200
|
+
const colors = geometry.getAttribute("color");
|
|
5201
|
+
const indices = geometry.getIndex();
|
|
5202
|
+
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
|
|
5203
|
+
for (let i = 0, l = vertices.count; i < l; i++) {
|
|
5204
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5205
|
+
vertex.applyMatrix4(mesh.matrixWorld);
|
|
5206
|
+
output.setFloat32(vOffset, vertex.x, options.littleEndian);
|
|
5207
|
+
vOffset += 4;
|
|
5208
|
+
output.setFloat32(vOffset, vertex.y, options.littleEndian);
|
|
5209
|
+
vOffset += 4;
|
|
5210
|
+
output.setFloat32(vOffset, vertex.z, options.littleEndian);
|
|
5211
|
+
vOffset += 4;
|
|
5212
|
+
if (includeNormals === true) {
|
|
5213
|
+
if (normals != null) {
|
|
5214
|
+
vertex.fromBufferAttribute(normals, i);
|
|
5215
|
+
vertex.applyMatrix3(normalMatrixWorld).normalize();
|
|
5216
|
+
output.setFloat32(vOffset, vertex.x, options.littleEndian);
|
|
5217
|
+
vOffset += 4;
|
|
5218
|
+
output.setFloat32(vOffset, vertex.y, options.littleEndian);
|
|
5219
|
+
vOffset += 4;
|
|
5220
|
+
output.setFloat32(vOffset, vertex.z, options.littleEndian);
|
|
5221
|
+
vOffset += 4;
|
|
5222
|
+
} else {
|
|
5223
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5224
|
+
vOffset += 4;
|
|
5225
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5226
|
+
vOffset += 4;
|
|
5227
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5228
|
+
vOffset += 4;
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
if (includeUVs === true) {
|
|
5232
|
+
if (uvs != null) {
|
|
5233
|
+
output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
|
|
5234
|
+
vOffset += 4;
|
|
5235
|
+
output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
|
|
5236
|
+
vOffset += 4;
|
|
5237
|
+
} else {
|
|
5238
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5239
|
+
vOffset += 4;
|
|
5240
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5241
|
+
vOffset += 4;
|
|
5242
|
+
}
|
|
5243
|
+
}
|
|
5244
|
+
if (includeColors === true) {
|
|
5245
|
+
if (colors != null) {
|
|
5246
|
+
tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
|
|
5247
|
+
output.setUint8(vOffset, Math.floor(tempColor.r * 255));
|
|
5248
|
+
vOffset += 1;
|
|
5249
|
+
output.setUint8(vOffset, Math.floor(tempColor.g * 255));
|
|
5250
|
+
vOffset += 1;
|
|
5251
|
+
output.setUint8(vOffset, Math.floor(tempColor.b * 255));
|
|
5252
|
+
vOffset += 1;
|
|
5253
|
+
} else {
|
|
5254
|
+
output.setUint8(vOffset, 255);
|
|
5255
|
+
vOffset += 1;
|
|
5256
|
+
output.setUint8(vOffset, 255);
|
|
5257
|
+
vOffset += 1;
|
|
5258
|
+
output.setUint8(vOffset, 255);
|
|
5259
|
+
vOffset += 1;
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
if (includeIndices === true) {
|
|
5264
|
+
if (indices !== null) {
|
|
5265
|
+
for (let i = 0, l = indices.count; i < l; i += 3) {
|
|
5266
|
+
output.setUint8(fOffset, 3);
|
|
5267
|
+
fOffset += 1;
|
|
5268
|
+
output.setUint32(fOffset, indices.getX(i + 0) + writtenVertices, options.littleEndian);
|
|
5269
|
+
fOffset += indexByteCount;
|
|
5270
|
+
output.setUint32(fOffset, indices.getX(i + 1) + writtenVertices, options.littleEndian);
|
|
5271
|
+
fOffset += indexByteCount;
|
|
5272
|
+
output.setUint32(fOffset, indices.getX(i + 2) + writtenVertices, options.littleEndian);
|
|
5273
|
+
fOffset += indexByteCount;
|
|
5274
|
+
}
|
|
5275
|
+
} else {
|
|
5276
|
+
for (let i = 0, l = vertices.count; i < l; i += 3) {
|
|
5277
|
+
output.setUint8(fOffset, 3);
|
|
5278
|
+
fOffset += 1;
|
|
5279
|
+
output.setUint32(fOffset, writtenVertices + i, options.littleEndian);
|
|
5280
|
+
fOffset += indexByteCount;
|
|
5281
|
+
output.setUint32(fOffset, writtenVertices + i + 1, options.littleEndian);
|
|
5282
|
+
fOffset += indexByteCount;
|
|
5283
|
+
output.setUint32(fOffset, writtenVertices + i + 2, options.littleEndian);
|
|
5284
|
+
fOffset += indexByteCount;
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
writtenVertices += vertices.count;
|
|
5289
|
+
});
|
|
5290
|
+
result = output.buffer;
|
|
5291
|
+
} else {
|
|
5292
|
+
let writtenVertices = 0;
|
|
5293
|
+
let vertexList = "";
|
|
5294
|
+
let faceList = "";
|
|
5295
|
+
traverseMeshes(function(mesh, geometry) {
|
|
5296
|
+
const vertices = geometry.getAttribute("position");
|
|
5297
|
+
const normals = geometry.getAttribute("normal");
|
|
5298
|
+
const uvs = geometry.getAttribute("uv");
|
|
5299
|
+
const colors = geometry.getAttribute("color");
|
|
5300
|
+
const indices = geometry.getIndex();
|
|
5301
|
+
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
|
|
5302
|
+
for (let i = 0, l = vertices.count; i < l; i++) {
|
|
5303
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5304
|
+
vertex.applyMatrix4(mesh.matrixWorld);
|
|
5305
|
+
let line = vertex.x + " " + vertex.y + " " + vertex.z;
|
|
5306
|
+
if (includeNormals === true) {
|
|
5307
|
+
if (normals != null) {
|
|
5308
|
+
vertex.fromBufferAttribute(normals, i);
|
|
5309
|
+
vertex.applyMatrix3(normalMatrixWorld).normalize();
|
|
5310
|
+
line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
5311
|
+
} else {
|
|
5312
|
+
line += " 0 0 0";
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
if (includeUVs === true) {
|
|
5316
|
+
if (uvs != null) {
|
|
5317
|
+
line += " " + uvs.getX(i) + " " + uvs.getY(i);
|
|
5318
|
+
} else {
|
|
5319
|
+
line += " 0 0";
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
if (includeColors === true) {
|
|
5323
|
+
if (colors != null) {
|
|
5324
|
+
tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
|
|
5325
|
+
line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
|
|
5326
|
+
} else {
|
|
5327
|
+
line += " 255 255 255";
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
vertexList += line + "\n";
|
|
5331
|
+
}
|
|
5332
|
+
if (includeIndices === true) {
|
|
5333
|
+
if (indices !== null) {
|
|
5334
|
+
for (let i = 0, l = indices.count; i < l; i += 3) {
|
|
5335
|
+
faceList += `3 ${indices.getX(i + 0) + writtenVertices}`;
|
|
5336
|
+
faceList += ` ${indices.getX(i + 1) + writtenVertices}`;
|
|
5337
|
+
faceList += ` ${indices.getX(i + 2) + writtenVertices}
|
|
5338
|
+
`;
|
|
5339
|
+
}
|
|
5340
|
+
} else {
|
|
5341
|
+
for (let i = 0, l = vertices.count; i < l; i += 3) {
|
|
5342
|
+
faceList += `3 ${writtenVertices + i} ${writtenVertices + i + 1} ${writtenVertices + i + 2}
|
|
5343
|
+
`;
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
faceCount += indices ? indices.count / 3 : vertices.count / 3;
|
|
5347
|
+
}
|
|
5348
|
+
writtenVertices += vertices.count;
|
|
5349
|
+
});
|
|
5350
|
+
result = `${header}${vertexList}${includeIndices ? `${faceList}
|
|
5351
|
+
` : "\n"}`;
|
|
5352
|
+
}
|
|
5353
|
+
if (typeof onDone === "function") requestAnimationFrame(() => onDone(result));
|
|
5354
|
+
return result;
|
|
5355
|
+
}
|
|
5356
|
+
};
|
|
5357
|
+
|
|
5358
|
+
// ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
|
|
5359
|
+
import {
|
|
5360
|
+
BufferAttribute as BufferAttribute3,
|
|
5361
|
+
ClampToEdgeWrapping,
|
|
5362
|
+
Color as Color5,
|
|
5363
|
+
DoubleSide as DoubleSide2,
|
|
5364
|
+
InterpolateDiscrete,
|
|
5365
|
+
InterpolateLinear,
|
|
5366
|
+
NoColorSpace,
|
|
5367
|
+
LinearFilter,
|
|
5368
|
+
LinearMipmapLinearFilter,
|
|
5369
|
+
LinearMipmapNearestFilter,
|
|
5370
|
+
MathUtils as MathUtils2,
|
|
5371
|
+
Matrix4 as Matrix44,
|
|
5372
|
+
MirroredRepeatWrapping,
|
|
5373
|
+
NearestFilter as NearestFilter2,
|
|
5374
|
+
NearestMipmapLinearFilter,
|
|
5375
|
+
NearestMipmapNearestFilter,
|
|
5376
|
+
PropertyBinding,
|
|
5377
|
+
RGBAFormat as RGBAFormat2,
|
|
5378
|
+
RepeatWrapping,
|
|
5379
|
+
Scene as Scene3,
|
|
5380
|
+
Source,
|
|
5381
|
+
SRGBColorSpace as SRGBColorSpace4,
|
|
5382
|
+
CompressedTexture,
|
|
5383
|
+
Vector3 as Vector38,
|
|
5384
|
+
Quaternion as Quaternion4
|
|
5385
|
+
} from "three";
|
|
5386
|
+
|
|
5387
|
+
// ../../node_modules/three/examples/jsm/utils/TextureUtils.js
|
|
5388
|
+
import {
|
|
5389
|
+
PlaneGeometry,
|
|
5390
|
+
ShaderMaterial as ShaderMaterial2,
|
|
5391
|
+
Uniform,
|
|
5392
|
+
Mesh as Mesh4,
|
|
5393
|
+
PerspectiveCamera,
|
|
5394
|
+
Scene as Scene2,
|
|
5395
|
+
WebGLRenderer,
|
|
5396
|
+
Texture as Texture3,
|
|
5397
|
+
SRGBColorSpace as SRGBColorSpace3
|
|
5398
|
+
} from "three";
|
|
5399
|
+
var _renderer;
|
|
5400
|
+
var fullscreenQuadGeometry;
|
|
5401
|
+
var fullscreenQuadMaterial;
|
|
5402
|
+
var fullscreenQuad;
|
|
5403
|
+
function decompress(texture, maxTextureSize = Infinity, renderer = null) {
|
|
5404
|
+
if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
|
|
5405
|
+
if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
|
|
5406
|
+
uniforms: { blitTexture: new Uniform(texture) },
|
|
5407
|
+
vertexShader: `
|
|
5408
|
+
varying vec2 vUv;
|
|
5409
|
+
void main(){
|
|
5410
|
+
vUv = uv;
|
|
5411
|
+
gl_Position = vec4(position.xy * 1.0,0.,.999999);
|
|
5412
|
+
}`,
|
|
5413
|
+
fragmentShader: `
|
|
5414
|
+
uniform sampler2D blitTexture;
|
|
5415
|
+
varying vec2 vUv;
|
|
5416
|
+
|
|
5417
|
+
void main(){
|
|
5418
|
+
gl_FragColor = vec4(vUv.xy, 0, 1);
|
|
5419
|
+
|
|
5420
|
+
#ifdef IS_SRGB
|
|
5421
|
+
gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
|
|
5422
|
+
#else
|
|
5423
|
+
gl_FragColor = texture2D( blitTexture, vUv);
|
|
5424
|
+
#endif
|
|
5425
|
+
}`
|
|
5426
|
+
});
|
|
5427
|
+
fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
|
|
5428
|
+
fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
|
|
5429
|
+
fullscreenQuadMaterial.needsUpdate = true;
|
|
5430
|
+
if (!fullscreenQuad) {
|
|
5431
|
+
fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
|
|
5432
|
+
fullscreenQuad.frustrumCulled = false;
|
|
5433
|
+
}
|
|
5434
|
+
const _camera = new PerspectiveCamera();
|
|
5435
|
+
const _scene = new Scene2();
|
|
5436
|
+
_scene.add(fullscreenQuad);
|
|
5437
|
+
if (!renderer) {
|
|
5438
|
+
renderer = _renderer = new WebGLRenderer({ antialias: false });
|
|
5439
|
+
}
|
|
5440
|
+
renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
|
|
5441
|
+
renderer.clear();
|
|
5442
|
+
renderer.render(_scene, _camera);
|
|
5443
|
+
const readableTexture = new Texture3(renderer.domElement);
|
|
5444
|
+
readableTexture.minFilter = texture.minFilter;
|
|
5445
|
+
readableTexture.magFilter = texture.magFilter;
|
|
5446
|
+
readableTexture.wrapS = texture.wrapS;
|
|
5447
|
+
readableTexture.wrapT = texture.wrapT;
|
|
5448
|
+
readableTexture.name = texture.name;
|
|
5449
|
+
if (_renderer) {
|
|
5450
|
+
_renderer.dispose();
|
|
5451
|
+
_renderer = null;
|
|
5452
|
+
}
|
|
5453
|
+
return readableTexture;
|
|
5454
|
+
}
|
|
5455
|
+
|
|
5456
|
+
// ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
|
|
5457
|
+
var KHR_mesh_quantization_ExtraAttrTypes = {
|
|
5458
|
+
POSITION: [
|
|
5459
|
+
"byte",
|
|
5460
|
+
"byte normalized",
|
|
5461
|
+
"unsigned byte",
|
|
5462
|
+
"unsigned byte normalized",
|
|
5463
|
+
"short",
|
|
5464
|
+
"short normalized",
|
|
5465
|
+
"unsigned short",
|
|
5466
|
+
"unsigned short normalized"
|
|
5467
|
+
],
|
|
5468
|
+
NORMAL: [
|
|
5469
|
+
"byte normalized",
|
|
5470
|
+
"short normalized"
|
|
5471
|
+
],
|
|
5472
|
+
TANGENT: [
|
|
5473
|
+
"byte normalized",
|
|
5474
|
+
"short normalized"
|
|
5475
|
+
],
|
|
5476
|
+
TEXCOORD: [
|
|
5477
|
+
"byte",
|
|
5478
|
+
"byte normalized",
|
|
5479
|
+
"unsigned byte",
|
|
5480
|
+
"short",
|
|
5481
|
+
"short normalized",
|
|
5482
|
+
"unsigned short"
|
|
5483
|
+
]
|
|
5484
|
+
};
|
|
5485
|
+
var GLTFExporter = class {
|
|
5486
|
+
constructor() {
|
|
5487
|
+
this.pluginCallbacks = [];
|
|
5488
|
+
this.register(function(writer) {
|
|
5489
|
+
return new GLTFLightExtension(writer);
|
|
5490
|
+
});
|
|
5491
|
+
this.register(function(writer) {
|
|
5492
|
+
return new GLTFMaterialsUnlitExtension(writer);
|
|
5493
|
+
});
|
|
5494
|
+
this.register(function(writer) {
|
|
5495
|
+
return new GLTFMaterialsTransmissionExtension(writer);
|
|
5496
|
+
});
|
|
5497
|
+
this.register(function(writer) {
|
|
5498
|
+
return new GLTFMaterialsVolumeExtension(writer);
|
|
5499
|
+
});
|
|
5500
|
+
this.register(function(writer) {
|
|
5501
|
+
return new GLTFMaterialsIorExtension(writer);
|
|
5502
|
+
});
|
|
5503
|
+
this.register(function(writer) {
|
|
5504
|
+
return new GLTFMaterialsSpecularExtension(writer);
|
|
5505
|
+
});
|
|
5506
|
+
this.register(function(writer) {
|
|
5507
|
+
return new GLTFMaterialsClearcoatExtension(writer);
|
|
5508
|
+
});
|
|
5509
|
+
this.register(function(writer) {
|
|
5510
|
+
return new GLTFMaterialsIridescenceExtension(writer);
|
|
5511
|
+
});
|
|
5512
|
+
this.register(function(writer) {
|
|
5513
|
+
return new GLTFMaterialsSheenExtension(writer);
|
|
5514
|
+
});
|
|
5515
|
+
this.register(function(writer) {
|
|
5516
|
+
return new GLTFMaterialsAnisotropyExtension(writer);
|
|
5517
|
+
});
|
|
5518
|
+
this.register(function(writer) {
|
|
5519
|
+
return new GLTFMaterialsEmissiveStrengthExtension(writer);
|
|
5520
|
+
});
|
|
5521
|
+
this.register(function(writer) {
|
|
5522
|
+
return new GLTFMeshGpuInstancing(writer);
|
|
5523
|
+
});
|
|
5524
|
+
}
|
|
5525
|
+
register(callback) {
|
|
5526
|
+
if (this.pluginCallbacks.indexOf(callback) === -1) {
|
|
5527
|
+
this.pluginCallbacks.push(callback);
|
|
5528
|
+
}
|
|
5529
|
+
return this;
|
|
5530
|
+
}
|
|
5531
|
+
unregister(callback) {
|
|
5532
|
+
if (this.pluginCallbacks.indexOf(callback) !== -1) {
|
|
5533
|
+
this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
|
|
5534
|
+
}
|
|
5535
|
+
return this;
|
|
5536
|
+
}
|
|
5537
|
+
/**
|
|
5538
|
+
* Parse scenes and generate GLTF output
|
|
5539
|
+
* @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
|
|
5540
|
+
* @param {Function} onDone Callback on completed
|
|
5541
|
+
* @param {Function} onError Callback on errors
|
|
5542
|
+
* @param {Object} options options
|
|
5543
|
+
*/
|
|
5544
|
+
parse(input, onDone, onError, options) {
|
|
5545
|
+
const writer = new GLTFWriter();
|
|
5546
|
+
const plugins = [];
|
|
5547
|
+
for (let i = 0, il = this.pluginCallbacks.length; i < il; i++) {
|
|
5548
|
+
plugins.push(this.pluginCallbacks[i](writer));
|
|
5549
|
+
}
|
|
5550
|
+
writer.setPlugins(plugins);
|
|
5551
|
+
writer.write(input, onDone, options).catch(onError);
|
|
5552
|
+
}
|
|
5553
|
+
parseAsync(input, options) {
|
|
5554
|
+
const scope = this;
|
|
5555
|
+
return new Promise(function(resolve, reject) {
|
|
5556
|
+
scope.parse(input, resolve, reject, options);
|
|
5557
|
+
});
|
|
5558
|
+
}
|
|
5559
|
+
};
|
|
5560
|
+
var WEBGL_CONSTANTS = {
|
|
5561
|
+
POINTS: 0,
|
|
5562
|
+
LINES: 1,
|
|
5563
|
+
LINE_LOOP: 2,
|
|
5564
|
+
LINE_STRIP: 3,
|
|
5565
|
+
TRIANGLES: 4,
|
|
5566
|
+
TRIANGLE_STRIP: 5,
|
|
5567
|
+
TRIANGLE_FAN: 6,
|
|
5568
|
+
BYTE: 5120,
|
|
5569
|
+
UNSIGNED_BYTE: 5121,
|
|
5570
|
+
SHORT: 5122,
|
|
5571
|
+
UNSIGNED_SHORT: 5123,
|
|
5572
|
+
INT: 5124,
|
|
5573
|
+
UNSIGNED_INT: 5125,
|
|
5574
|
+
FLOAT: 5126,
|
|
5575
|
+
ARRAY_BUFFER: 34962,
|
|
5576
|
+
ELEMENT_ARRAY_BUFFER: 34963,
|
|
5577
|
+
NEAREST: 9728,
|
|
5578
|
+
LINEAR: 9729,
|
|
5579
|
+
NEAREST_MIPMAP_NEAREST: 9984,
|
|
5580
|
+
LINEAR_MIPMAP_NEAREST: 9985,
|
|
5581
|
+
NEAREST_MIPMAP_LINEAR: 9986,
|
|
5582
|
+
LINEAR_MIPMAP_LINEAR: 9987,
|
|
5583
|
+
CLAMP_TO_EDGE: 33071,
|
|
5584
|
+
MIRRORED_REPEAT: 33648,
|
|
5585
|
+
REPEAT: 10497
|
|
5586
|
+
};
|
|
5587
|
+
var KHR_MESH_QUANTIZATION = "KHR_mesh_quantization";
|
|
5588
|
+
var THREE_TO_WEBGL = {};
|
|
5589
|
+
THREE_TO_WEBGL[NearestFilter2] = WEBGL_CONSTANTS.NEAREST;
|
|
5590
|
+
THREE_TO_WEBGL[NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
|
|
5591
|
+
THREE_TO_WEBGL[NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
|
|
5592
|
+
THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
|
|
5593
|
+
THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
|
|
5594
|
+
THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
|
|
5595
|
+
THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
|
|
5596
|
+
THREE_TO_WEBGL[RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
|
|
5597
|
+
THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
|
|
5598
|
+
var PATH_PROPERTIES = {
|
|
5599
|
+
scale: "scale",
|
|
5600
|
+
position: "translation",
|
|
5601
|
+
quaternion: "rotation",
|
|
5602
|
+
morphTargetInfluences: "weights"
|
|
5603
|
+
};
|
|
5604
|
+
var DEFAULT_SPECULAR_COLOR = new Color5();
|
|
5605
|
+
var GLB_HEADER_BYTES = 12;
|
|
5606
|
+
var GLB_HEADER_MAGIC = 1179937895;
|
|
5607
|
+
var GLB_VERSION = 2;
|
|
5608
|
+
var GLB_CHUNK_PREFIX_BYTES = 8;
|
|
5609
|
+
var GLB_CHUNK_TYPE_JSON = 1313821514;
|
|
5610
|
+
var GLB_CHUNK_TYPE_BIN = 5130562;
|
|
5611
|
+
function equalArray(array1, array2) {
|
|
5612
|
+
return array1.length === array2.length && array1.every(function(element, index) {
|
|
5613
|
+
return element === array2[index];
|
|
5614
|
+
});
|
|
5615
|
+
}
|
|
5616
|
+
function stringToArrayBuffer(text) {
|
|
5617
|
+
return new TextEncoder().encode(text).buffer;
|
|
5618
|
+
}
|
|
5619
|
+
function isIdentityMatrix(matrix) {
|
|
5620
|
+
return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
5621
|
+
}
|
|
5622
|
+
function getMinMax(attribute, start, count) {
|
|
5623
|
+
const output = {
|
|
5624
|
+
min: new Array(attribute.itemSize).fill(Number.POSITIVE_INFINITY),
|
|
5625
|
+
max: new Array(attribute.itemSize).fill(Number.NEGATIVE_INFINITY)
|
|
5626
|
+
};
|
|
5627
|
+
for (let i = start; i < start + count; i++) {
|
|
5628
|
+
for (let a = 0; a < attribute.itemSize; a++) {
|
|
5629
|
+
let value;
|
|
5630
|
+
if (attribute.itemSize > 4) {
|
|
5631
|
+
value = attribute.array[i * attribute.itemSize + a];
|
|
5632
|
+
} else {
|
|
5633
|
+
if (a === 0) value = attribute.getX(i);
|
|
5634
|
+
else if (a === 1) value = attribute.getY(i);
|
|
5635
|
+
else if (a === 2) value = attribute.getZ(i);
|
|
5636
|
+
else if (a === 3) value = attribute.getW(i);
|
|
5637
|
+
if (attribute.normalized === true) {
|
|
5638
|
+
value = MathUtils2.normalize(value, attribute.array);
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
output.min[a] = Math.min(output.min[a], value);
|
|
5642
|
+
output.max[a] = Math.max(output.max[a], value);
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
return output;
|
|
5646
|
+
}
|
|
5647
|
+
function getPaddedBufferSize(bufferSize) {
|
|
5648
|
+
return Math.ceil(bufferSize / 4) * 4;
|
|
5649
|
+
}
|
|
5650
|
+
function getPaddedArrayBuffer(arrayBuffer, paddingByte = 0) {
|
|
5651
|
+
const paddedLength = getPaddedBufferSize(arrayBuffer.byteLength);
|
|
5652
|
+
if (paddedLength !== arrayBuffer.byteLength) {
|
|
5653
|
+
const array = new Uint8Array(paddedLength);
|
|
5654
|
+
array.set(new Uint8Array(arrayBuffer));
|
|
5655
|
+
if (paddingByte !== 0) {
|
|
5656
|
+
for (let i = arrayBuffer.byteLength; i < paddedLength; i++) {
|
|
5657
|
+
array[i] = paddingByte;
|
|
5658
|
+
}
|
|
5659
|
+
}
|
|
5660
|
+
return array.buffer;
|
|
5661
|
+
}
|
|
5662
|
+
return arrayBuffer;
|
|
5663
|
+
}
|
|
5664
|
+
function getCanvas() {
|
|
5665
|
+
if (typeof document === "undefined" && typeof OffscreenCanvas !== "undefined") {
|
|
5666
|
+
return new OffscreenCanvas(1, 1);
|
|
5667
|
+
}
|
|
5668
|
+
return document.createElement("canvas");
|
|
5669
|
+
}
|
|
5670
|
+
function getToBlobPromise(canvas, mimeType) {
|
|
5671
|
+
if (canvas.toBlob !== void 0) {
|
|
5672
|
+
return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
|
|
5673
|
+
}
|
|
5674
|
+
let quality;
|
|
5675
|
+
if (mimeType === "image/jpeg") {
|
|
5676
|
+
quality = 0.92;
|
|
5677
|
+
} else if (mimeType === "image/webp") {
|
|
5678
|
+
quality = 0.8;
|
|
5679
|
+
}
|
|
5680
|
+
return canvas.convertToBlob({
|
|
5681
|
+
type: mimeType,
|
|
5682
|
+
quality
|
|
5683
|
+
});
|
|
5684
|
+
}
|
|
5685
|
+
var GLTFWriter = class {
|
|
5686
|
+
constructor() {
|
|
5687
|
+
this.plugins = [];
|
|
5688
|
+
this.options = {};
|
|
5689
|
+
this.pending = [];
|
|
5690
|
+
this.buffers = [];
|
|
5691
|
+
this.byteOffset = 0;
|
|
5692
|
+
this.buffers = [];
|
|
5693
|
+
this.nodeMap = /* @__PURE__ */ new Map();
|
|
5694
|
+
this.skins = [];
|
|
5695
|
+
this.extensionsUsed = {};
|
|
5696
|
+
this.extensionsRequired = {};
|
|
5697
|
+
this.uids = /* @__PURE__ */ new Map();
|
|
5698
|
+
this.uid = 0;
|
|
5699
|
+
this.json = {
|
|
5700
|
+
asset: {
|
|
5701
|
+
version: "2.0",
|
|
5702
|
+
generator: "THREE.GLTFExporter"
|
|
5703
|
+
}
|
|
5704
|
+
};
|
|
5705
|
+
this.cache = {
|
|
5706
|
+
meshes: /* @__PURE__ */ new Map(),
|
|
5707
|
+
attributes: /* @__PURE__ */ new Map(),
|
|
5708
|
+
attributesNormalized: /* @__PURE__ */ new Map(),
|
|
5709
|
+
materials: /* @__PURE__ */ new Map(),
|
|
5710
|
+
textures: /* @__PURE__ */ new Map(),
|
|
5711
|
+
images: /* @__PURE__ */ new Map()
|
|
5712
|
+
};
|
|
5713
|
+
}
|
|
5714
|
+
setPlugins(plugins) {
|
|
5715
|
+
this.plugins = plugins;
|
|
5716
|
+
}
|
|
5717
|
+
/**
|
|
5718
|
+
* Parse scenes and generate GLTF output
|
|
5719
|
+
* @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
|
|
5720
|
+
* @param {Function} onDone Callback on completed
|
|
5721
|
+
* @param {Object} options options
|
|
5722
|
+
*/
|
|
5723
|
+
async write(input, onDone, options = {}) {
|
|
5724
|
+
this.options = Object.assign({
|
|
5725
|
+
// default options
|
|
5726
|
+
binary: false,
|
|
5727
|
+
trs: false,
|
|
5728
|
+
onlyVisible: true,
|
|
5729
|
+
maxTextureSize: Infinity,
|
|
5730
|
+
animations: [],
|
|
5731
|
+
includeCustomExtensions: false
|
|
5732
|
+
}, options);
|
|
5733
|
+
if (this.options.animations.length > 0) {
|
|
5734
|
+
this.options.trs = true;
|
|
5735
|
+
}
|
|
5736
|
+
this.processInput(input);
|
|
5737
|
+
await Promise.all(this.pending);
|
|
5738
|
+
const writer = this;
|
|
5739
|
+
const buffers = writer.buffers;
|
|
5740
|
+
const json = writer.json;
|
|
5741
|
+
options = writer.options;
|
|
5742
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
5743
|
+
const extensionsRequired = writer.extensionsRequired;
|
|
5744
|
+
const blob = new Blob(buffers, { type: "application/octet-stream" });
|
|
5745
|
+
const extensionsUsedList = Object.keys(extensionsUsed);
|
|
5746
|
+
const extensionsRequiredList = Object.keys(extensionsRequired);
|
|
5747
|
+
if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
|
|
5748
|
+
if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
|
|
5749
|
+
if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
|
|
5750
|
+
if (options.binary === true) {
|
|
5751
|
+
const reader = new FileReader();
|
|
5752
|
+
reader.readAsArrayBuffer(blob);
|
|
5753
|
+
reader.onloadend = function() {
|
|
5754
|
+
const binaryChunk = getPaddedArrayBuffer(reader.result);
|
|
5755
|
+
const binaryChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
|
|
5756
|
+
binaryChunkPrefix.setUint32(0, binaryChunk.byteLength, true);
|
|
5757
|
+
binaryChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_BIN, true);
|
|
5758
|
+
const jsonChunk = getPaddedArrayBuffer(stringToArrayBuffer(JSON.stringify(json)), 32);
|
|
5759
|
+
const jsonChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
|
|
5760
|
+
jsonChunkPrefix.setUint32(0, jsonChunk.byteLength, true);
|
|
5761
|
+
jsonChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_JSON, true);
|
|
5762
|
+
const header = new ArrayBuffer(GLB_HEADER_BYTES);
|
|
5763
|
+
const headerView = new DataView(header);
|
|
5764
|
+
headerView.setUint32(0, GLB_HEADER_MAGIC, true);
|
|
5765
|
+
headerView.setUint32(4, GLB_VERSION, true);
|
|
5766
|
+
const totalByteLength = GLB_HEADER_BYTES + jsonChunkPrefix.byteLength + jsonChunk.byteLength + binaryChunkPrefix.byteLength + binaryChunk.byteLength;
|
|
5767
|
+
headerView.setUint32(8, totalByteLength, true);
|
|
5768
|
+
const glbBlob = new Blob([
|
|
5769
|
+
header,
|
|
5770
|
+
jsonChunkPrefix,
|
|
5771
|
+
jsonChunk,
|
|
5772
|
+
binaryChunkPrefix,
|
|
5773
|
+
binaryChunk
|
|
5774
|
+
], { type: "application/octet-stream" });
|
|
5775
|
+
const glbReader = new FileReader();
|
|
5776
|
+
glbReader.readAsArrayBuffer(glbBlob);
|
|
5777
|
+
glbReader.onloadend = function() {
|
|
5778
|
+
onDone(glbReader.result);
|
|
5779
|
+
};
|
|
5780
|
+
};
|
|
5781
|
+
} else {
|
|
5782
|
+
if (json.buffers && json.buffers.length > 0) {
|
|
5783
|
+
const reader = new FileReader();
|
|
5784
|
+
reader.readAsDataURL(blob);
|
|
5785
|
+
reader.onloadend = function() {
|
|
5786
|
+
const base64data = reader.result;
|
|
5787
|
+
json.buffers[0].uri = base64data;
|
|
5788
|
+
onDone(json);
|
|
5789
|
+
};
|
|
5790
|
+
} else {
|
|
5791
|
+
onDone(json);
|
|
5792
|
+
}
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
/**
|
|
5796
|
+
* Serializes a userData.
|
|
5797
|
+
*
|
|
5798
|
+
* @param {THREE.Object3D|THREE.Material} object
|
|
5799
|
+
* @param {Object} objectDef
|
|
5800
|
+
*/
|
|
5801
|
+
serializeUserData(object, objectDef) {
|
|
5802
|
+
if (Object.keys(object.userData).length === 0) return;
|
|
5803
|
+
const options = this.options;
|
|
5804
|
+
const extensionsUsed = this.extensionsUsed;
|
|
5805
|
+
try {
|
|
5806
|
+
const json = JSON.parse(JSON.stringify(object.userData));
|
|
5807
|
+
if (options.includeCustomExtensions && json.gltfExtensions) {
|
|
5808
|
+
if (objectDef.extensions === void 0) objectDef.extensions = {};
|
|
5809
|
+
for (const extensionName in json.gltfExtensions) {
|
|
5810
|
+
objectDef.extensions[extensionName] = json.gltfExtensions[extensionName];
|
|
5811
|
+
extensionsUsed[extensionName] = true;
|
|
5812
|
+
}
|
|
5813
|
+
delete json.gltfExtensions;
|
|
5814
|
+
}
|
|
5815
|
+
if (Object.keys(json).length > 0) objectDef.extras = json;
|
|
5816
|
+
} catch (error) {
|
|
5817
|
+
console.warn("THREE.GLTFExporter: userData of '" + object.name + "' won't be serialized because of JSON.stringify error - " + error.message);
|
|
5818
|
+
}
|
|
5819
|
+
}
|
|
5820
|
+
/**
|
|
5821
|
+
* Returns ids for buffer attributes.
|
|
5822
|
+
* @param {Object} object
|
|
5823
|
+
* @return {Integer}
|
|
5824
|
+
*/
|
|
5825
|
+
getUID(attribute, isRelativeCopy = false) {
|
|
5826
|
+
if (this.uids.has(attribute) === false) {
|
|
5827
|
+
const uids2 = /* @__PURE__ */ new Map();
|
|
5828
|
+
uids2.set(true, this.uid++);
|
|
5829
|
+
uids2.set(false, this.uid++);
|
|
5830
|
+
this.uids.set(attribute, uids2);
|
|
5831
|
+
}
|
|
5832
|
+
const uids = this.uids.get(attribute);
|
|
5833
|
+
return uids.get(isRelativeCopy);
|
|
5834
|
+
}
|
|
5835
|
+
/**
|
|
5836
|
+
* Checks if normal attribute values are normalized.
|
|
5837
|
+
*
|
|
5838
|
+
* @param {BufferAttribute} normal
|
|
5839
|
+
* @returns {Boolean}
|
|
5840
|
+
*/
|
|
5841
|
+
isNormalizedNormalAttribute(normal) {
|
|
5842
|
+
const cache = this.cache;
|
|
5843
|
+
if (cache.attributesNormalized.has(normal)) return false;
|
|
5844
|
+
const v = new Vector38();
|
|
5845
|
+
for (let i = 0, il = normal.count; i < il; i++) {
|
|
5846
|
+
if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1) > 5e-4) return false;
|
|
5847
|
+
}
|
|
5848
|
+
return true;
|
|
5849
|
+
}
|
|
5850
|
+
/**
|
|
5851
|
+
* Creates normalized normal buffer attribute.
|
|
5852
|
+
*
|
|
5853
|
+
* @param {BufferAttribute} normal
|
|
5854
|
+
* @returns {BufferAttribute}
|
|
5855
|
+
*
|
|
5856
|
+
*/
|
|
5857
|
+
createNormalizedNormalAttribute(normal) {
|
|
5858
|
+
const cache = this.cache;
|
|
5859
|
+
if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal);
|
|
5860
|
+
const attribute = normal.clone();
|
|
5861
|
+
const v = new Vector38();
|
|
5862
|
+
for (let i = 0, il = attribute.count; i < il; i++) {
|
|
5863
|
+
v.fromBufferAttribute(attribute, i);
|
|
5864
|
+
if (v.x === 0 && v.y === 0 && v.z === 0) {
|
|
5865
|
+
v.setX(1);
|
|
5866
|
+
} else {
|
|
5867
|
+
v.normalize();
|
|
5868
|
+
}
|
|
5869
|
+
attribute.setXYZ(i, v.x, v.y, v.z);
|
|
5870
|
+
}
|
|
5871
|
+
cache.attributesNormalized.set(normal, attribute);
|
|
5872
|
+
return attribute;
|
|
5873
|
+
}
|
|
5874
|
+
/**
|
|
5875
|
+
* Applies a texture transform, if present, to the map definition. Requires
|
|
5876
|
+
* the KHR_texture_transform extension.
|
|
5877
|
+
*
|
|
5878
|
+
* @param {Object} mapDef
|
|
5879
|
+
* @param {THREE.Texture} texture
|
|
5880
|
+
*/
|
|
5881
|
+
applyTextureTransform(mapDef, texture) {
|
|
5882
|
+
let didTransform = false;
|
|
5883
|
+
const transformDef = {};
|
|
5884
|
+
if (texture.offset.x !== 0 || texture.offset.y !== 0) {
|
|
5885
|
+
transformDef.offset = texture.offset.toArray();
|
|
5886
|
+
didTransform = true;
|
|
5887
|
+
}
|
|
5888
|
+
if (texture.rotation !== 0) {
|
|
5889
|
+
transformDef.rotation = texture.rotation;
|
|
5890
|
+
didTransform = true;
|
|
5891
|
+
}
|
|
5892
|
+
if (texture.repeat.x !== 1 || texture.repeat.y !== 1) {
|
|
5893
|
+
transformDef.scale = texture.repeat.toArray();
|
|
5894
|
+
didTransform = true;
|
|
5895
|
+
}
|
|
5896
|
+
if (didTransform) {
|
|
5897
|
+
mapDef.extensions = mapDef.extensions || {};
|
|
5898
|
+
mapDef.extensions["KHR_texture_transform"] = transformDef;
|
|
5899
|
+
this.extensionsUsed["KHR_texture_transform"] = true;
|
|
5900
|
+
}
|
|
5901
|
+
}
|
|
5902
|
+
buildMetalRoughTexture(metalnessMap, roughnessMap) {
|
|
5903
|
+
if (metalnessMap === roughnessMap) return metalnessMap;
|
|
5904
|
+
function getEncodingConversion(map) {
|
|
5905
|
+
if (map.colorSpace === SRGBColorSpace4) {
|
|
5906
|
+
return function SRGBToLinear(c) {
|
|
5907
|
+
return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
|
|
5908
|
+
};
|
|
5909
|
+
}
|
|
5910
|
+
return function LinearToLinear(c) {
|
|
5911
|
+
return c;
|
|
5912
|
+
};
|
|
5913
|
+
}
|
|
5914
|
+
console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
|
|
5915
|
+
if (metalnessMap instanceof CompressedTexture) {
|
|
5916
|
+
metalnessMap = decompress(metalnessMap);
|
|
5917
|
+
}
|
|
5918
|
+
if (roughnessMap instanceof CompressedTexture) {
|
|
5919
|
+
roughnessMap = decompress(roughnessMap);
|
|
5920
|
+
}
|
|
5921
|
+
const metalness = metalnessMap ? metalnessMap.image : null;
|
|
5922
|
+
const roughness = roughnessMap ? roughnessMap.image : null;
|
|
5923
|
+
const width = Math.max(metalness ? metalness.width : 0, roughness ? roughness.width : 0);
|
|
5924
|
+
const height = Math.max(metalness ? metalness.height : 0, roughness ? roughness.height : 0);
|
|
5925
|
+
const canvas = getCanvas();
|
|
5926
|
+
canvas.width = width;
|
|
5927
|
+
canvas.height = height;
|
|
5928
|
+
const context = canvas.getContext("2d");
|
|
5929
|
+
context.fillStyle = "#00ffff";
|
|
5930
|
+
context.fillRect(0, 0, width, height);
|
|
5931
|
+
const composite = context.getImageData(0, 0, width, height);
|
|
5932
|
+
if (metalness) {
|
|
5933
|
+
context.drawImage(metalness, 0, 0, width, height);
|
|
5934
|
+
const convert = getEncodingConversion(metalnessMap);
|
|
5935
|
+
const data = context.getImageData(0, 0, width, height).data;
|
|
5936
|
+
for (let i = 2; i < data.length; i += 4) {
|
|
5937
|
+
composite.data[i] = convert(data[i] / 256) * 256;
|
|
5938
|
+
}
|
|
5939
|
+
}
|
|
5940
|
+
if (roughness) {
|
|
5941
|
+
context.drawImage(roughness, 0, 0, width, height);
|
|
5942
|
+
const convert = getEncodingConversion(roughnessMap);
|
|
5943
|
+
const data = context.getImageData(0, 0, width, height).data;
|
|
5944
|
+
for (let i = 1; i < data.length; i += 4) {
|
|
5945
|
+
composite.data[i] = convert(data[i] / 256) * 256;
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5948
|
+
context.putImageData(composite, 0, 0);
|
|
5949
|
+
const reference = metalnessMap || roughnessMap;
|
|
5950
|
+
const texture = reference.clone();
|
|
5951
|
+
texture.source = new Source(canvas);
|
|
5952
|
+
texture.colorSpace = NoColorSpace;
|
|
5953
|
+
texture.channel = (metalnessMap || roughnessMap).channel;
|
|
5954
|
+
if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
|
|
5955
|
+
console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
|
|
5956
|
+
}
|
|
5957
|
+
return texture;
|
|
5958
|
+
}
|
|
5959
|
+
/**
|
|
5960
|
+
* Process a buffer to append to the default one.
|
|
5961
|
+
* @param {ArrayBuffer} buffer
|
|
5962
|
+
* @return {Integer}
|
|
5963
|
+
*/
|
|
5964
|
+
processBuffer(buffer) {
|
|
5965
|
+
const json = this.json;
|
|
5966
|
+
const buffers = this.buffers;
|
|
5967
|
+
if (!json.buffers) json.buffers = [{ byteLength: 0 }];
|
|
5968
|
+
buffers.push(buffer);
|
|
5969
|
+
return 0;
|
|
5970
|
+
}
|
|
5971
|
+
/**
|
|
5972
|
+
* Process and generate a BufferView
|
|
5973
|
+
* @param {BufferAttribute} attribute
|
|
5974
|
+
* @param {number} componentType
|
|
5975
|
+
* @param {number} start
|
|
5976
|
+
* @param {number} count
|
|
5977
|
+
* @param {number} target (Optional) Target usage of the BufferView
|
|
5978
|
+
* @return {Object}
|
|
5979
|
+
*/
|
|
5980
|
+
processBufferView(attribute, componentType, start, count, target) {
|
|
5981
|
+
const json = this.json;
|
|
5982
|
+
if (!json.bufferViews) json.bufferViews = [];
|
|
5983
|
+
let componentSize;
|
|
5984
|
+
switch (componentType) {
|
|
5985
|
+
case WEBGL_CONSTANTS.BYTE:
|
|
5986
|
+
case WEBGL_CONSTANTS.UNSIGNED_BYTE:
|
|
5987
|
+
componentSize = 1;
|
|
5988
|
+
break;
|
|
5989
|
+
case WEBGL_CONSTANTS.SHORT:
|
|
5990
|
+
case WEBGL_CONSTANTS.UNSIGNED_SHORT:
|
|
5991
|
+
componentSize = 2;
|
|
5992
|
+
break;
|
|
5993
|
+
default:
|
|
5994
|
+
componentSize = 4;
|
|
5995
|
+
}
|
|
5996
|
+
const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
|
|
5997
|
+
const dataView = new DataView(new ArrayBuffer(byteLength));
|
|
5998
|
+
let offset = 0;
|
|
5999
|
+
for (let i = start; i < start + count; i++) {
|
|
6000
|
+
for (let a = 0; a < attribute.itemSize; a++) {
|
|
6001
|
+
let value;
|
|
6002
|
+
if (attribute.itemSize > 4) {
|
|
6003
|
+
value = attribute.array[i * attribute.itemSize + a];
|
|
6004
|
+
} else {
|
|
6005
|
+
if (a === 0) value = attribute.getX(i);
|
|
6006
|
+
else if (a === 1) value = attribute.getY(i);
|
|
6007
|
+
else if (a === 2) value = attribute.getZ(i);
|
|
6008
|
+
else if (a === 3) value = attribute.getW(i);
|
|
6009
|
+
if (attribute.normalized === true) {
|
|
6010
|
+
value = MathUtils2.normalize(value, attribute.array);
|
|
6011
|
+
}
|
|
6012
|
+
}
|
|
6013
|
+
if (componentType === WEBGL_CONSTANTS.FLOAT) {
|
|
6014
|
+
dataView.setFloat32(offset, value, true);
|
|
6015
|
+
} else if (componentType === WEBGL_CONSTANTS.INT) {
|
|
6016
|
+
dataView.setInt32(offset, value, true);
|
|
6017
|
+
} else if (componentType === WEBGL_CONSTANTS.UNSIGNED_INT) {
|
|
6018
|
+
dataView.setUint32(offset, value, true);
|
|
6019
|
+
} else if (componentType === WEBGL_CONSTANTS.SHORT) {
|
|
6020
|
+
dataView.setInt16(offset, value, true);
|
|
6021
|
+
} else if (componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT) {
|
|
6022
|
+
dataView.setUint16(offset, value, true);
|
|
6023
|
+
} else if (componentType === WEBGL_CONSTANTS.BYTE) {
|
|
6024
|
+
dataView.setInt8(offset, value);
|
|
6025
|
+
} else if (componentType === WEBGL_CONSTANTS.UNSIGNED_BYTE) {
|
|
6026
|
+
dataView.setUint8(offset, value);
|
|
6027
|
+
}
|
|
6028
|
+
offset += componentSize;
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
const bufferViewDef = {
|
|
6032
|
+
buffer: this.processBuffer(dataView.buffer),
|
|
6033
|
+
byteOffset: this.byteOffset,
|
|
6034
|
+
byteLength
|
|
6035
|
+
};
|
|
6036
|
+
if (target !== void 0) bufferViewDef.target = target;
|
|
6037
|
+
if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
|
|
6038
|
+
bufferViewDef.byteStride = attribute.itemSize * componentSize;
|
|
6039
|
+
}
|
|
6040
|
+
this.byteOffset += byteLength;
|
|
6041
|
+
json.bufferViews.push(bufferViewDef);
|
|
6042
|
+
const output = {
|
|
6043
|
+
id: json.bufferViews.length - 1,
|
|
6044
|
+
byteLength: 0
|
|
6045
|
+
};
|
|
6046
|
+
return output;
|
|
6047
|
+
}
|
|
6048
|
+
/**
|
|
6049
|
+
* Process and generate a BufferView from an image Blob.
|
|
6050
|
+
* @param {Blob} blob
|
|
6051
|
+
* @return {Promise<Integer>}
|
|
6052
|
+
*/
|
|
6053
|
+
processBufferViewImage(blob) {
|
|
6054
|
+
const writer = this;
|
|
6055
|
+
const json = writer.json;
|
|
6056
|
+
if (!json.bufferViews) json.bufferViews = [];
|
|
6057
|
+
return new Promise(function(resolve) {
|
|
6058
|
+
const reader = new FileReader();
|
|
6059
|
+
reader.readAsArrayBuffer(blob);
|
|
6060
|
+
reader.onloadend = function() {
|
|
6061
|
+
const buffer = getPaddedArrayBuffer(reader.result);
|
|
6062
|
+
const bufferViewDef = {
|
|
6063
|
+
buffer: writer.processBuffer(buffer),
|
|
6064
|
+
byteOffset: writer.byteOffset,
|
|
6065
|
+
byteLength: buffer.byteLength
|
|
6066
|
+
};
|
|
6067
|
+
writer.byteOffset += buffer.byteLength;
|
|
6068
|
+
resolve(json.bufferViews.push(bufferViewDef) - 1);
|
|
6069
|
+
};
|
|
6070
|
+
});
|
|
6071
|
+
}
|
|
6072
|
+
/**
|
|
6073
|
+
* Process attribute to generate an accessor
|
|
6074
|
+
* @param {BufferAttribute} attribute Attribute to process
|
|
6075
|
+
* @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
|
|
6076
|
+
* @param {Integer} start (Optional)
|
|
6077
|
+
* @param {Integer} count (Optional)
|
|
6078
|
+
* @return {Integer|null} Index of the processed accessor on the "accessors" array
|
|
6079
|
+
*/
|
|
6080
|
+
processAccessor(attribute, geometry, start, count) {
|
|
6081
|
+
const json = this.json;
|
|
6082
|
+
const types = {
|
|
6083
|
+
1: "SCALAR",
|
|
6084
|
+
2: "VEC2",
|
|
6085
|
+
3: "VEC3",
|
|
6086
|
+
4: "VEC4",
|
|
6087
|
+
9: "MAT3",
|
|
6088
|
+
16: "MAT4"
|
|
6089
|
+
};
|
|
6090
|
+
let componentType;
|
|
6091
|
+
if (attribute.array.constructor === Float32Array) {
|
|
6092
|
+
componentType = WEBGL_CONSTANTS.FLOAT;
|
|
6093
|
+
} else if (attribute.array.constructor === Int32Array) {
|
|
6094
|
+
componentType = WEBGL_CONSTANTS.INT;
|
|
6095
|
+
} else if (attribute.array.constructor === Uint32Array) {
|
|
6096
|
+
componentType = WEBGL_CONSTANTS.UNSIGNED_INT;
|
|
6097
|
+
} else if (attribute.array.constructor === Int16Array) {
|
|
6098
|
+
componentType = WEBGL_CONSTANTS.SHORT;
|
|
6099
|
+
} else if (attribute.array.constructor === Uint16Array) {
|
|
6100
|
+
componentType = WEBGL_CONSTANTS.UNSIGNED_SHORT;
|
|
6101
|
+
} else if (attribute.array.constructor === Int8Array) {
|
|
6102
|
+
componentType = WEBGL_CONSTANTS.BYTE;
|
|
6103
|
+
} else if (attribute.array.constructor === Uint8Array) {
|
|
6104
|
+
componentType = WEBGL_CONSTANTS.UNSIGNED_BYTE;
|
|
6105
|
+
} else {
|
|
6106
|
+
throw new Error("THREE.GLTFExporter: Unsupported bufferAttribute component type: " + attribute.array.constructor.name);
|
|
6107
|
+
}
|
|
6108
|
+
if (start === void 0) start = 0;
|
|
6109
|
+
if (count === void 0 || count === Infinity) count = attribute.count;
|
|
6110
|
+
if (count === 0) return null;
|
|
6111
|
+
const minMax = getMinMax(attribute, start, count);
|
|
6112
|
+
let bufferViewTarget;
|
|
6113
|
+
if (geometry !== void 0) {
|
|
6114
|
+
bufferViewTarget = attribute === geometry.index ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER : WEBGL_CONSTANTS.ARRAY_BUFFER;
|
|
6115
|
+
}
|
|
6116
|
+
const bufferView = this.processBufferView(attribute, componentType, start, count, bufferViewTarget);
|
|
6117
|
+
const accessorDef = {
|
|
6118
|
+
bufferView: bufferView.id,
|
|
6119
|
+
byteOffset: bufferView.byteOffset,
|
|
6120
|
+
componentType,
|
|
6121
|
+
count,
|
|
6122
|
+
max: minMax.max,
|
|
6123
|
+
min: minMax.min,
|
|
6124
|
+
type: types[attribute.itemSize]
|
|
6125
|
+
};
|
|
6126
|
+
if (attribute.normalized === true) accessorDef.normalized = true;
|
|
6127
|
+
if (!json.accessors) json.accessors = [];
|
|
6128
|
+
return json.accessors.push(accessorDef) - 1;
|
|
6129
|
+
}
|
|
6130
|
+
/**
|
|
6131
|
+
* Process image
|
|
6132
|
+
* @param {Image} image to process
|
|
6133
|
+
* @param {Integer} format of the image (RGBAFormat)
|
|
6134
|
+
* @param {Boolean} flipY before writing out the image
|
|
6135
|
+
* @param {String} mimeType export format
|
|
6136
|
+
* @return {Integer} Index of the processed texture in the "images" array
|
|
6137
|
+
*/
|
|
6138
|
+
processImage(image, format, flipY, mimeType = "image/png") {
|
|
6139
|
+
if (image !== null) {
|
|
6140
|
+
const writer = this;
|
|
6141
|
+
const cache = writer.cache;
|
|
6142
|
+
const json = writer.json;
|
|
6143
|
+
const options = writer.options;
|
|
6144
|
+
const pending = writer.pending;
|
|
6145
|
+
if (!cache.images.has(image)) cache.images.set(image, {});
|
|
6146
|
+
const cachedImages = cache.images.get(image);
|
|
6147
|
+
const key = mimeType + ":flipY/" + flipY.toString();
|
|
6148
|
+
if (cachedImages[key] !== void 0) return cachedImages[key];
|
|
6149
|
+
if (!json.images) json.images = [];
|
|
6150
|
+
const imageDef = { mimeType };
|
|
6151
|
+
const canvas = getCanvas();
|
|
6152
|
+
canvas.width = Math.min(image.width, options.maxTextureSize);
|
|
6153
|
+
canvas.height = Math.min(image.height, options.maxTextureSize);
|
|
6154
|
+
const ctx = canvas.getContext("2d");
|
|
6155
|
+
if (flipY === true) {
|
|
6156
|
+
ctx.translate(0, canvas.height);
|
|
6157
|
+
ctx.scale(1, -1);
|
|
6158
|
+
}
|
|
6159
|
+
if (image.data !== void 0) {
|
|
6160
|
+
if (format !== RGBAFormat2) {
|
|
6161
|
+
console.error("GLTFExporter: Only RGBAFormat is supported.", format);
|
|
6162
|
+
}
|
|
6163
|
+
if (image.width > options.maxTextureSize || image.height > options.maxTextureSize) {
|
|
6164
|
+
console.warn("GLTFExporter: Image size is bigger than maxTextureSize", image);
|
|
6165
|
+
}
|
|
6166
|
+
const data = new Uint8ClampedArray(image.height * image.width * 4);
|
|
6167
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
6168
|
+
data[i + 0] = image.data[i + 0];
|
|
6169
|
+
data[i + 1] = image.data[i + 1];
|
|
6170
|
+
data[i + 2] = image.data[i + 2];
|
|
6171
|
+
data[i + 3] = image.data[i + 3];
|
|
6172
|
+
}
|
|
6173
|
+
ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
|
|
6174
|
+
} else {
|
|
6175
|
+
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
6176
|
+
}
|
|
6177
|
+
if (options.binary === true) {
|
|
6178
|
+
pending.push(
|
|
6179
|
+
getToBlobPromise(canvas, mimeType).then((blob) => writer.processBufferViewImage(blob)).then((bufferViewIndex) => {
|
|
6180
|
+
imageDef.bufferView = bufferViewIndex;
|
|
6181
|
+
})
|
|
6182
|
+
);
|
|
6183
|
+
} else {
|
|
6184
|
+
if (canvas.toDataURL !== void 0) {
|
|
6185
|
+
imageDef.uri = canvas.toDataURL(mimeType);
|
|
6186
|
+
} else {
|
|
6187
|
+
pending.push(
|
|
6188
|
+
getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
|
|
6189
|
+
imageDef.uri = dataURL;
|
|
6190
|
+
})
|
|
6191
|
+
);
|
|
6192
|
+
}
|
|
6193
|
+
}
|
|
6194
|
+
const index = json.images.push(imageDef) - 1;
|
|
6195
|
+
cachedImages[key] = index;
|
|
6196
|
+
return index;
|
|
6197
|
+
} else {
|
|
6198
|
+
throw new Error("THREE.GLTFExporter: No valid image data found. Unable to process texture.");
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
/**
|
|
6202
|
+
* Process sampler
|
|
6203
|
+
* @param {Texture} map Texture to process
|
|
6204
|
+
* @return {Integer} Index of the processed texture in the "samplers" array
|
|
6205
|
+
*/
|
|
6206
|
+
processSampler(map) {
|
|
6207
|
+
const json = this.json;
|
|
6208
|
+
if (!json.samplers) json.samplers = [];
|
|
6209
|
+
const samplerDef = {
|
|
6210
|
+
magFilter: THREE_TO_WEBGL[map.magFilter],
|
|
6211
|
+
minFilter: THREE_TO_WEBGL[map.minFilter],
|
|
6212
|
+
wrapS: THREE_TO_WEBGL[map.wrapS],
|
|
6213
|
+
wrapT: THREE_TO_WEBGL[map.wrapT]
|
|
6214
|
+
};
|
|
6215
|
+
return json.samplers.push(samplerDef) - 1;
|
|
6216
|
+
}
|
|
6217
|
+
/**
|
|
6218
|
+
* Process texture
|
|
6219
|
+
* @param {Texture} map Map to process
|
|
6220
|
+
* @return {Integer} Index of the processed texture in the "textures" array
|
|
6221
|
+
*/
|
|
6222
|
+
processTexture(map) {
|
|
6223
|
+
const writer = this;
|
|
6224
|
+
const options = writer.options;
|
|
6225
|
+
const cache = this.cache;
|
|
6226
|
+
const json = this.json;
|
|
6227
|
+
if (cache.textures.has(map)) return cache.textures.get(map);
|
|
6228
|
+
if (!json.textures) json.textures = [];
|
|
6229
|
+
if (map instanceof CompressedTexture) {
|
|
6230
|
+
map = decompress(map, options.maxTextureSize);
|
|
6231
|
+
}
|
|
6232
|
+
let mimeType = map.userData.mimeType;
|
|
6233
|
+
if (mimeType === "image/webp") mimeType = "image/png";
|
|
6234
|
+
const textureDef = {
|
|
6235
|
+
sampler: this.processSampler(map),
|
|
6236
|
+
source: this.processImage(map.image, map.format, map.flipY, mimeType)
|
|
6237
|
+
};
|
|
6238
|
+
if (map.name) textureDef.name = map.name;
|
|
6239
|
+
this._invokeAll(function(ext) {
|
|
6240
|
+
ext.writeTexture && ext.writeTexture(map, textureDef);
|
|
6241
|
+
});
|
|
6242
|
+
const index = json.textures.push(textureDef) - 1;
|
|
6243
|
+
cache.textures.set(map, index);
|
|
6244
|
+
return index;
|
|
6245
|
+
}
|
|
6246
|
+
/**
|
|
6247
|
+
* Process material
|
|
6248
|
+
* @param {THREE.Material} material Material to process
|
|
6249
|
+
* @return {Integer|null} Index of the processed material in the "materials" array
|
|
6250
|
+
*/
|
|
6251
|
+
processMaterial(material) {
|
|
6252
|
+
const cache = this.cache;
|
|
6253
|
+
const json = this.json;
|
|
6254
|
+
if (cache.materials.has(material)) return cache.materials.get(material);
|
|
6255
|
+
if (material.isShaderMaterial) {
|
|
6256
|
+
console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
|
|
6257
|
+
return null;
|
|
6258
|
+
}
|
|
6259
|
+
if (!json.materials) json.materials = [];
|
|
6260
|
+
const materialDef = { pbrMetallicRoughness: {} };
|
|
6261
|
+
if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
|
|
6262
|
+
console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
|
|
6263
|
+
}
|
|
6264
|
+
const color = material.color.toArray().concat([material.opacity]);
|
|
6265
|
+
if (!equalArray(color, [1, 1, 1, 1])) {
|
|
6266
|
+
materialDef.pbrMetallicRoughness.baseColorFactor = color;
|
|
6267
|
+
}
|
|
6268
|
+
if (material.isMeshStandardMaterial) {
|
|
6269
|
+
materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
|
|
6270
|
+
materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
|
|
6271
|
+
} else {
|
|
6272
|
+
materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
|
|
6273
|
+
materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
|
|
6274
|
+
}
|
|
6275
|
+
if (material.metalnessMap || material.roughnessMap) {
|
|
6276
|
+
const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
|
|
6277
|
+
const metalRoughMapDef = {
|
|
6278
|
+
index: this.processTexture(metalRoughTexture),
|
|
6279
|
+
channel: metalRoughTexture.channel
|
|
6280
|
+
};
|
|
6281
|
+
this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
|
|
6282
|
+
materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
|
|
6283
|
+
}
|
|
6284
|
+
if (material.map) {
|
|
6285
|
+
const baseColorMapDef = {
|
|
6286
|
+
index: this.processTexture(material.map),
|
|
6287
|
+
texCoord: material.map.channel
|
|
6288
|
+
};
|
|
6289
|
+
this.applyTextureTransform(baseColorMapDef, material.map);
|
|
6290
|
+
materialDef.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
|
|
6291
|
+
}
|
|
6292
|
+
if (material.emissive) {
|
|
6293
|
+
const emissive = material.emissive;
|
|
6294
|
+
const maxEmissiveComponent = Math.max(emissive.r, emissive.g, emissive.b);
|
|
6295
|
+
if (maxEmissiveComponent > 0) {
|
|
6296
|
+
materialDef.emissiveFactor = material.emissive.toArray();
|
|
6297
|
+
}
|
|
6298
|
+
if (material.emissiveMap) {
|
|
6299
|
+
const emissiveMapDef = {
|
|
6300
|
+
index: this.processTexture(material.emissiveMap),
|
|
6301
|
+
texCoord: material.emissiveMap.channel
|
|
6302
|
+
};
|
|
6303
|
+
this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
|
|
6304
|
+
materialDef.emissiveTexture = emissiveMapDef;
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6307
|
+
if (material.normalMap) {
|
|
6308
|
+
const normalMapDef = {
|
|
6309
|
+
index: this.processTexture(material.normalMap),
|
|
6310
|
+
texCoord: material.normalMap.channel
|
|
6311
|
+
};
|
|
6312
|
+
if (material.normalScale && material.normalScale.x !== 1) {
|
|
6313
|
+
normalMapDef.scale = material.normalScale.x;
|
|
6314
|
+
}
|
|
6315
|
+
this.applyTextureTransform(normalMapDef, material.normalMap);
|
|
6316
|
+
materialDef.normalTexture = normalMapDef;
|
|
6317
|
+
}
|
|
6318
|
+
if (material.aoMap) {
|
|
6319
|
+
const occlusionMapDef = {
|
|
6320
|
+
index: this.processTexture(material.aoMap),
|
|
6321
|
+
texCoord: material.aoMap.channel
|
|
6322
|
+
};
|
|
6323
|
+
if (material.aoMapIntensity !== 1) {
|
|
6324
|
+
occlusionMapDef.strength = material.aoMapIntensity;
|
|
6325
|
+
}
|
|
6326
|
+
this.applyTextureTransform(occlusionMapDef, material.aoMap);
|
|
6327
|
+
materialDef.occlusionTexture = occlusionMapDef;
|
|
6328
|
+
}
|
|
6329
|
+
if (material.transparent) {
|
|
6330
|
+
materialDef.alphaMode = "BLEND";
|
|
6331
|
+
} else {
|
|
6332
|
+
if (material.alphaTest > 0) {
|
|
6333
|
+
materialDef.alphaMode = "MASK";
|
|
6334
|
+
materialDef.alphaCutoff = material.alphaTest;
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
if (material.side === DoubleSide2) materialDef.doubleSided = true;
|
|
6338
|
+
if (material.name !== "") materialDef.name = material.name;
|
|
6339
|
+
this.serializeUserData(material, materialDef);
|
|
6340
|
+
this._invokeAll(function(ext) {
|
|
6341
|
+
ext.writeMaterial && ext.writeMaterial(material, materialDef);
|
|
6342
|
+
});
|
|
6343
|
+
const index = json.materials.push(materialDef) - 1;
|
|
6344
|
+
cache.materials.set(material, index);
|
|
6345
|
+
return index;
|
|
6346
|
+
}
|
|
6347
|
+
/**
|
|
6348
|
+
* Process mesh
|
|
6349
|
+
* @param {THREE.Mesh} mesh Mesh to process
|
|
6350
|
+
* @return {Integer|null} Index of the processed mesh in the "meshes" array
|
|
6351
|
+
*/
|
|
6352
|
+
processMesh(mesh) {
|
|
6353
|
+
const cache = this.cache;
|
|
6354
|
+
const json = this.json;
|
|
6355
|
+
const meshCacheKeyParts = [mesh.geometry.uuid];
|
|
6356
|
+
if (Array.isArray(mesh.material)) {
|
|
6357
|
+
for (let i = 0, l = mesh.material.length; i < l; i++) {
|
|
6358
|
+
meshCacheKeyParts.push(mesh.material[i].uuid);
|
|
6359
|
+
}
|
|
6360
|
+
} else {
|
|
6361
|
+
meshCacheKeyParts.push(mesh.material.uuid);
|
|
6362
|
+
}
|
|
6363
|
+
const meshCacheKey = meshCacheKeyParts.join(":");
|
|
6364
|
+
if (cache.meshes.has(meshCacheKey)) return cache.meshes.get(meshCacheKey);
|
|
6365
|
+
const geometry = mesh.geometry;
|
|
6366
|
+
let mode;
|
|
6367
|
+
if (mesh.isLineSegments) {
|
|
6368
|
+
mode = WEBGL_CONSTANTS.LINES;
|
|
6369
|
+
} else if (mesh.isLineLoop) {
|
|
6370
|
+
mode = WEBGL_CONSTANTS.LINE_LOOP;
|
|
6371
|
+
} else if (mesh.isLine) {
|
|
6372
|
+
mode = WEBGL_CONSTANTS.LINE_STRIP;
|
|
6373
|
+
} else if (mesh.isPoints) {
|
|
6374
|
+
mode = WEBGL_CONSTANTS.POINTS;
|
|
6375
|
+
} else {
|
|
6376
|
+
mode = mesh.material.wireframe ? WEBGL_CONSTANTS.LINES : WEBGL_CONSTANTS.TRIANGLES;
|
|
6377
|
+
}
|
|
6378
|
+
const meshDef = {};
|
|
6379
|
+
const attributes = {};
|
|
6380
|
+
const primitives = [];
|
|
6381
|
+
const targets = [];
|
|
6382
|
+
const nameConversion = {
|
|
6383
|
+
uv: "TEXCOORD_0",
|
|
6384
|
+
uv1: "TEXCOORD_1",
|
|
6385
|
+
uv2: "TEXCOORD_2",
|
|
6386
|
+
uv3: "TEXCOORD_3",
|
|
6387
|
+
color: "COLOR_0",
|
|
6388
|
+
skinWeight: "WEIGHTS_0",
|
|
6389
|
+
skinIndex: "JOINTS_0"
|
|
6390
|
+
};
|
|
6391
|
+
const originalNormal = geometry.getAttribute("normal");
|
|
6392
|
+
if (originalNormal !== void 0 && !this.isNormalizedNormalAttribute(originalNormal)) {
|
|
6393
|
+
console.warn("THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.");
|
|
6394
|
+
geometry.setAttribute("normal", this.createNormalizedNormalAttribute(originalNormal));
|
|
6395
|
+
}
|
|
6396
|
+
let modifiedAttribute = null;
|
|
6397
|
+
for (let attributeName in geometry.attributes) {
|
|
6398
|
+
if (attributeName.slice(0, 5) === "morph") continue;
|
|
6399
|
+
const attribute = geometry.attributes[attributeName];
|
|
6400
|
+
attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
|
|
6401
|
+
const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
|
|
6402
|
+
if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
|
|
6403
|
+
if (cache.attributes.has(this.getUID(attribute))) {
|
|
6404
|
+
attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
|
|
6405
|
+
continue;
|
|
6406
|
+
}
|
|
6407
|
+
modifiedAttribute = null;
|
|
6408
|
+
const array = attribute.array;
|
|
6409
|
+
if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
|
|
6410
|
+
console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
|
|
6411
|
+
modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
|
|
6412
|
+
}
|
|
6413
|
+
const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
|
|
6414
|
+
if (accessor !== null) {
|
|
6415
|
+
if (!attributeName.startsWith("_")) {
|
|
6416
|
+
this.detectMeshQuantization(attributeName, attribute);
|
|
6417
|
+
}
|
|
6418
|
+
attributes[attributeName] = accessor;
|
|
6419
|
+
cache.attributes.set(this.getUID(attribute), accessor);
|
|
6420
|
+
}
|
|
6421
|
+
}
|
|
6422
|
+
if (originalNormal !== void 0) geometry.setAttribute("normal", originalNormal);
|
|
6423
|
+
if (Object.keys(attributes).length === 0) return null;
|
|
6424
|
+
if (mesh.morphTargetInfluences !== void 0 && mesh.morphTargetInfluences.length > 0) {
|
|
6425
|
+
const weights = [];
|
|
6426
|
+
const targetNames = [];
|
|
6427
|
+
const reverseDictionary = {};
|
|
6428
|
+
if (mesh.morphTargetDictionary !== void 0) {
|
|
6429
|
+
for (const key in mesh.morphTargetDictionary) {
|
|
6430
|
+
reverseDictionary[mesh.morphTargetDictionary[key]] = key;
|
|
6431
|
+
}
|
|
6432
|
+
}
|
|
6433
|
+
for (let i = 0; i < mesh.morphTargetInfluences.length; ++i) {
|
|
6434
|
+
const target = {};
|
|
6435
|
+
let warned = false;
|
|
6436
|
+
for (const attributeName in geometry.morphAttributes) {
|
|
6437
|
+
if (attributeName !== "position" && attributeName !== "normal") {
|
|
6438
|
+
if (!warned) {
|
|
6439
|
+
console.warn("GLTFExporter: Only POSITION and NORMAL morph are supported.");
|
|
6440
|
+
warned = true;
|
|
6441
|
+
}
|
|
6442
|
+
continue;
|
|
6443
|
+
}
|
|
6444
|
+
const attribute = geometry.morphAttributes[attributeName][i];
|
|
6445
|
+
const gltfAttributeName = attributeName.toUpperCase();
|
|
6446
|
+
const baseAttribute = geometry.attributes[attributeName];
|
|
6447
|
+
if (cache.attributes.has(this.getUID(attribute, true))) {
|
|
6448
|
+
target[gltfAttributeName] = cache.attributes.get(this.getUID(attribute, true));
|
|
6449
|
+
continue;
|
|
6450
|
+
}
|
|
6451
|
+
const relativeAttribute = attribute.clone();
|
|
6452
|
+
if (!geometry.morphTargetsRelative) {
|
|
6453
|
+
for (let j = 0, jl = attribute.count; j < jl; j++) {
|
|
6454
|
+
for (let a = 0; a < attribute.itemSize; a++) {
|
|
6455
|
+
if (a === 0) relativeAttribute.setX(j, attribute.getX(j) - baseAttribute.getX(j));
|
|
6456
|
+
if (a === 1) relativeAttribute.setY(j, attribute.getY(j) - baseAttribute.getY(j));
|
|
6457
|
+
if (a === 2) relativeAttribute.setZ(j, attribute.getZ(j) - baseAttribute.getZ(j));
|
|
6458
|
+
if (a === 3) relativeAttribute.setW(j, attribute.getW(j) - baseAttribute.getW(j));
|
|
6459
|
+
}
|
|
6460
|
+
}
|
|
6461
|
+
}
|
|
6462
|
+
target[gltfAttributeName] = this.processAccessor(relativeAttribute, geometry);
|
|
6463
|
+
cache.attributes.set(this.getUID(baseAttribute, true), target[gltfAttributeName]);
|
|
6464
|
+
}
|
|
6465
|
+
targets.push(target);
|
|
6466
|
+
weights.push(mesh.morphTargetInfluences[i]);
|
|
6467
|
+
if (mesh.morphTargetDictionary !== void 0) targetNames.push(reverseDictionary[i]);
|
|
6468
|
+
}
|
|
6469
|
+
meshDef.weights = weights;
|
|
6470
|
+
if (targetNames.length > 0) {
|
|
6471
|
+
meshDef.extras = {};
|
|
6472
|
+
meshDef.extras.targetNames = targetNames;
|
|
6473
|
+
}
|
|
6474
|
+
}
|
|
6475
|
+
const isMultiMaterial = Array.isArray(mesh.material);
|
|
6476
|
+
if (isMultiMaterial && geometry.groups.length === 0) return null;
|
|
6477
|
+
const materials = isMultiMaterial ? mesh.material : [mesh.material];
|
|
6478
|
+
const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
|
|
6479
|
+
for (let i = 0, il = groups.length; i < il; i++) {
|
|
6480
|
+
const primitive = {
|
|
6481
|
+
mode,
|
|
6482
|
+
attributes
|
|
6483
|
+
};
|
|
6484
|
+
this.serializeUserData(geometry, primitive);
|
|
6485
|
+
if (targets.length > 0) primitive.targets = targets;
|
|
6486
|
+
if (geometry.index !== null) {
|
|
6487
|
+
let cacheKey = this.getUID(geometry.index);
|
|
6488
|
+
if (groups[i].start !== void 0 || groups[i].count !== void 0) {
|
|
6489
|
+
cacheKey += ":" + groups[i].start + ":" + groups[i].count;
|
|
6490
|
+
}
|
|
6491
|
+
if (cache.attributes.has(cacheKey)) {
|
|
6492
|
+
primitive.indices = cache.attributes.get(cacheKey);
|
|
6493
|
+
} else {
|
|
6494
|
+
primitive.indices = this.processAccessor(geometry.index, geometry, groups[i].start, groups[i].count);
|
|
6495
|
+
cache.attributes.set(cacheKey, primitive.indices);
|
|
6496
|
+
}
|
|
6497
|
+
if (primitive.indices === null) delete primitive.indices;
|
|
6498
|
+
}
|
|
6499
|
+
const material = this.processMaterial(materials[groups[i].materialIndex]);
|
|
6500
|
+
if (material !== null) primitive.material = material;
|
|
6501
|
+
primitives.push(primitive);
|
|
6502
|
+
}
|
|
6503
|
+
meshDef.primitives = primitives;
|
|
6504
|
+
if (!json.meshes) json.meshes = [];
|
|
6505
|
+
this._invokeAll(function(ext) {
|
|
6506
|
+
ext.writeMesh && ext.writeMesh(mesh, meshDef);
|
|
6507
|
+
});
|
|
6508
|
+
const index = json.meshes.push(meshDef) - 1;
|
|
6509
|
+
cache.meshes.set(meshCacheKey, index);
|
|
6510
|
+
return index;
|
|
6511
|
+
}
|
|
6512
|
+
/**
|
|
6513
|
+
* If a vertex attribute with a
|
|
6514
|
+
* [non-standard data type](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview)
|
|
6515
|
+
* is used, it is checked whether it is a valid data type according to the
|
|
6516
|
+
* [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md)
|
|
6517
|
+
* extension.
|
|
6518
|
+
* In this case the extension is automatically added to the list of used extensions.
|
|
6519
|
+
*
|
|
6520
|
+
* @param {string} attributeName
|
|
6521
|
+
* @param {THREE.BufferAttribute} attribute
|
|
6522
|
+
*/
|
|
6523
|
+
detectMeshQuantization(attributeName, attribute) {
|
|
6524
|
+
if (this.extensionsUsed[KHR_MESH_QUANTIZATION]) return;
|
|
6525
|
+
let attrType = void 0;
|
|
6526
|
+
switch (attribute.array.constructor) {
|
|
6527
|
+
case Int8Array:
|
|
6528
|
+
attrType = "byte";
|
|
6529
|
+
break;
|
|
6530
|
+
case Uint8Array:
|
|
6531
|
+
attrType = "unsigned byte";
|
|
6532
|
+
break;
|
|
6533
|
+
case Int16Array:
|
|
6534
|
+
attrType = "short";
|
|
6535
|
+
break;
|
|
6536
|
+
case Uint16Array:
|
|
6537
|
+
attrType = "unsigned short";
|
|
6538
|
+
break;
|
|
6539
|
+
default:
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6542
|
+
if (attribute.normalized) attrType += " normalized";
|
|
6543
|
+
const attrNamePrefix = attributeName.split("_", 1)[0];
|
|
6544
|
+
if (KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix] && KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix].includes(attrType)) {
|
|
6545
|
+
this.extensionsUsed[KHR_MESH_QUANTIZATION] = true;
|
|
6546
|
+
this.extensionsRequired[KHR_MESH_QUANTIZATION] = true;
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
/**
|
|
6550
|
+
* Process camera
|
|
6551
|
+
* @param {THREE.Camera} camera Camera to process
|
|
6552
|
+
* @return {Integer} Index of the processed mesh in the "camera" array
|
|
6553
|
+
*/
|
|
6554
|
+
processCamera(camera) {
|
|
6555
|
+
const json = this.json;
|
|
6556
|
+
if (!json.cameras) json.cameras = [];
|
|
6557
|
+
const isOrtho = camera.isOrthographicCamera;
|
|
6558
|
+
const cameraDef = {
|
|
6559
|
+
type: isOrtho ? "orthographic" : "perspective"
|
|
6560
|
+
};
|
|
6561
|
+
if (isOrtho) {
|
|
6562
|
+
cameraDef.orthographic = {
|
|
6563
|
+
xmag: camera.right * 2,
|
|
6564
|
+
ymag: camera.top * 2,
|
|
6565
|
+
zfar: camera.far <= 0 ? 1e-3 : camera.far,
|
|
6566
|
+
znear: camera.near < 0 ? 0 : camera.near
|
|
6567
|
+
};
|
|
6568
|
+
} else {
|
|
6569
|
+
cameraDef.perspective = {
|
|
6570
|
+
aspectRatio: camera.aspect,
|
|
6571
|
+
yfov: MathUtils2.degToRad(camera.fov),
|
|
6572
|
+
zfar: camera.far <= 0 ? 1e-3 : camera.far,
|
|
6573
|
+
znear: camera.near < 0 ? 0 : camera.near
|
|
6574
|
+
};
|
|
6575
|
+
}
|
|
6576
|
+
if (camera.name !== "") cameraDef.name = camera.type;
|
|
6577
|
+
return json.cameras.push(cameraDef) - 1;
|
|
6578
|
+
}
|
|
6579
|
+
/**
|
|
6580
|
+
* Creates glTF animation entry from AnimationClip object.
|
|
6581
|
+
*
|
|
6582
|
+
* Status:
|
|
6583
|
+
* - Only properties listed in PATH_PROPERTIES may be animated.
|
|
6584
|
+
*
|
|
6585
|
+
* @param {THREE.AnimationClip} clip
|
|
6586
|
+
* @param {THREE.Object3D} root
|
|
6587
|
+
* @return {number|null}
|
|
6588
|
+
*/
|
|
6589
|
+
processAnimation(clip, root) {
|
|
6590
|
+
const json = this.json;
|
|
6591
|
+
const nodeMap = this.nodeMap;
|
|
6592
|
+
if (!json.animations) json.animations = [];
|
|
6593
|
+
clip = GLTFExporter.Utils.mergeMorphTargetTracks(clip.clone(), root);
|
|
6594
|
+
const tracks = clip.tracks;
|
|
6595
|
+
const channels = [];
|
|
6596
|
+
const samplers = [];
|
|
6597
|
+
for (let i = 0; i < tracks.length; ++i) {
|
|
6598
|
+
const track = tracks[i];
|
|
6599
|
+
const trackBinding = PropertyBinding.parseTrackName(track.name);
|
|
6600
|
+
let trackNode = PropertyBinding.findNode(root, trackBinding.nodeName);
|
|
6601
|
+
const trackProperty = PATH_PROPERTIES[trackBinding.propertyName];
|
|
6602
|
+
if (trackBinding.objectName === "bones") {
|
|
6603
|
+
if (trackNode.isSkinnedMesh === true) {
|
|
6604
|
+
trackNode = trackNode.skeleton.getBoneByName(trackBinding.objectIndex);
|
|
6605
|
+
} else {
|
|
6606
|
+
trackNode = void 0;
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
if (!trackNode || !trackProperty) {
|
|
6610
|
+
console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
|
|
6611
|
+
return null;
|
|
6612
|
+
}
|
|
6613
|
+
const inputItemSize = 1;
|
|
6614
|
+
let outputItemSize = track.values.length / track.times.length;
|
|
6615
|
+
if (trackProperty === PATH_PROPERTIES.morphTargetInfluences) {
|
|
6616
|
+
outputItemSize /= trackNode.morphTargetInfluences.length;
|
|
6617
|
+
}
|
|
6618
|
+
let interpolation;
|
|
6619
|
+
if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) {
|
|
6620
|
+
interpolation = "CUBICSPLINE";
|
|
6621
|
+
outputItemSize /= 3;
|
|
6622
|
+
} else if (track.getInterpolation() === InterpolateDiscrete) {
|
|
6623
|
+
interpolation = "STEP";
|
|
6624
|
+
} else {
|
|
6625
|
+
interpolation = "LINEAR";
|
|
6626
|
+
}
|
|
6627
|
+
samplers.push({
|
|
6628
|
+
input: this.processAccessor(new BufferAttribute3(track.times, inputItemSize)),
|
|
6629
|
+
output: this.processAccessor(new BufferAttribute3(track.values, outputItemSize)),
|
|
6630
|
+
interpolation
|
|
6631
|
+
});
|
|
6632
|
+
channels.push({
|
|
6633
|
+
sampler: samplers.length - 1,
|
|
6634
|
+
target: {
|
|
6635
|
+
node: nodeMap.get(trackNode),
|
|
6636
|
+
path: trackProperty
|
|
6637
|
+
}
|
|
6638
|
+
});
|
|
6639
|
+
}
|
|
6640
|
+
json.animations.push({
|
|
6641
|
+
name: clip.name || "clip_" + json.animations.length,
|
|
6642
|
+
samplers,
|
|
6643
|
+
channels
|
|
6644
|
+
});
|
|
6645
|
+
return json.animations.length - 1;
|
|
6646
|
+
}
|
|
6647
|
+
/**
|
|
6648
|
+
* @param {THREE.Object3D} object
|
|
6649
|
+
* @return {number|null}
|
|
6650
|
+
*/
|
|
6651
|
+
processSkin(object) {
|
|
6652
|
+
const json = this.json;
|
|
6653
|
+
const nodeMap = this.nodeMap;
|
|
6654
|
+
const node = json.nodes[nodeMap.get(object)];
|
|
6655
|
+
const skeleton = object.skeleton;
|
|
6656
|
+
if (skeleton === void 0) return null;
|
|
6657
|
+
const rootJoint = object.skeleton.bones[0];
|
|
6658
|
+
if (rootJoint === void 0) return null;
|
|
6659
|
+
const joints = [];
|
|
6660
|
+
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
6661
|
+
const temporaryBoneInverse = new Matrix44();
|
|
6662
|
+
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
6663
|
+
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
6664
|
+
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
6665
|
+
temporaryBoneInverse.multiply(object.bindMatrix).toArray(inverseBindMatrices, i * 16);
|
|
6666
|
+
}
|
|
6667
|
+
if (json.skins === void 0) json.skins = [];
|
|
6668
|
+
json.skins.push({
|
|
6669
|
+
inverseBindMatrices: this.processAccessor(new BufferAttribute3(inverseBindMatrices, 16)),
|
|
6670
|
+
joints,
|
|
6671
|
+
skeleton: nodeMap.get(rootJoint)
|
|
6672
|
+
});
|
|
6673
|
+
const skinIndex = node.skin = json.skins.length - 1;
|
|
6674
|
+
return skinIndex;
|
|
6675
|
+
}
|
|
6676
|
+
/**
|
|
6677
|
+
* Process Object3D node
|
|
6678
|
+
* @param {THREE.Object3D} node Object3D to processNode
|
|
6679
|
+
* @return {Integer} Index of the node in the nodes list
|
|
6680
|
+
*/
|
|
6681
|
+
processNode(object) {
|
|
6682
|
+
const json = this.json;
|
|
6683
|
+
const options = this.options;
|
|
6684
|
+
const nodeMap = this.nodeMap;
|
|
6685
|
+
if (!json.nodes) json.nodes = [];
|
|
6686
|
+
const nodeDef = {};
|
|
6687
|
+
if (options.trs) {
|
|
6688
|
+
const rotation = object.quaternion.toArray();
|
|
6689
|
+
const position = object.position.toArray();
|
|
6690
|
+
const scale = object.scale.toArray();
|
|
6691
|
+
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
6692
|
+
nodeDef.rotation = rotation;
|
|
6693
|
+
}
|
|
6694
|
+
if (!equalArray(position, [0, 0, 0])) {
|
|
6695
|
+
nodeDef.translation = position;
|
|
6696
|
+
}
|
|
6697
|
+
if (!equalArray(scale, [1, 1, 1])) {
|
|
6698
|
+
nodeDef.scale = scale;
|
|
6699
|
+
}
|
|
6700
|
+
} else {
|
|
6701
|
+
if (object.matrixAutoUpdate) {
|
|
6702
|
+
object.updateMatrix();
|
|
6703
|
+
}
|
|
6704
|
+
if (isIdentityMatrix(object.matrix) === false) {
|
|
6705
|
+
nodeDef.matrix = object.matrix.elements;
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
if (object.name !== "") nodeDef.name = String(object.name);
|
|
6709
|
+
this.serializeUserData(object, nodeDef);
|
|
6710
|
+
if (object.isMesh || object.isLine || object.isPoints) {
|
|
6711
|
+
const meshIndex = this.processMesh(object);
|
|
6712
|
+
if (meshIndex !== null) nodeDef.mesh = meshIndex;
|
|
6713
|
+
} else if (object.isCamera) {
|
|
6714
|
+
nodeDef.camera = this.processCamera(object);
|
|
6715
|
+
}
|
|
6716
|
+
if (object.isSkinnedMesh) this.skins.push(object);
|
|
6717
|
+
if (object.children.length > 0) {
|
|
6718
|
+
const children = [];
|
|
6719
|
+
for (let i = 0, l = object.children.length; i < l; i++) {
|
|
6720
|
+
const child = object.children[i];
|
|
6721
|
+
if (child.visible || options.onlyVisible === false) {
|
|
6722
|
+
const nodeIndex2 = this.processNode(child);
|
|
6723
|
+
if (nodeIndex2 !== null) children.push(nodeIndex2);
|
|
6724
|
+
}
|
|
6725
|
+
}
|
|
6726
|
+
if (children.length > 0) nodeDef.children = children;
|
|
6727
|
+
}
|
|
6728
|
+
this._invokeAll(function(ext) {
|
|
6729
|
+
ext.writeNode && ext.writeNode(object, nodeDef);
|
|
6730
|
+
});
|
|
6731
|
+
const nodeIndex = json.nodes.push(nodeDef) - 1;
|
|
6732
|
+
nodeMap.set(object, nodeIndex);
|
|
6733
|
+
return nodeIndex;
|
|
6734
|
+
}
|
|
6735
|
+
/**
|
|
6736
|
+
* Process Scene
|
|
6737
|
+
* @param {Scene} node Scene to process
|
|
6738
|
+
*/
|
|
6739
|
+
processScene(scene) {
|
|
6740
|
+
const json = this.json;
|
|
6741
|
+
const options = this.options;
|
|
6742
|
+
if (!json.scenes) {
|
|
6743
|
+
json.scenes = [];
|
|
6744
|
+
json.scene = 0;
|
|
6745
|
+
}
|
|
6746
|
+
const sceneDef = {};
|
|
6747
|
+
if (scene.name !== "") sceneDef.name = scene.name;
|
|
6748
|
+
json.scenes.push(sceneDef);
|
|
6749
|
+
const nodes = [];
|
|
6750
|
+
for (let i = 0, l = scene.children.length; i < l; i++) {
|
|
6751
|
+
const child = scene.children[i];
|
|
6752
|
+
if (child.visible || options.onlyVisible === false) {
|
|
6753
|
+
const nodeIndex = this.processNode(child);
|
|
6754
|
+
if (nodeIndex !== null) nodes.push(nodeIndex);
|
|
6755
|
+
}
|
|
6756
|
+
}
|
|
6757
|
+
if (nodes.length > 0) sceneDef.nodes = nodes;
|
|
6758
|
+
this.serializeUserData(scene, sceneDef);
|
|
6759
|
+
}
|
|
6760
|
+
/**
|
|
6761
|
+
* Creates a Scene to hold a list of objects and parse it
|
|
6762
|
+
* @param {Array} objects List of objects to process
|
|
6763
|
+
*/
|
|
6764
|
+
processObjects(objects) {
|
|
6765
|
+
const scene = new Scene3();
|
|
6766
|
+
scene.name = "AuxScene";
|
|
6767
|
+
for (let i = 0; i < objects.length; i++) {
|
|
6768
|
+
scene.children.push(objects[i]);
|
|
6769
|
+
}
|
|
6770
|
+
this.processScene(scene);
|
|
6771
|
+
}
|
|
6772
|
+
/**
|
|
6773
|
+
* @param {THREE.Object3D|Array<THREE.Object3D>} input
|
|
6774
|
+
*/
|
|
6775
|
+
processInput(input) {
|
|
6776
|
+
const options = this.options;
|
|
6777
|
+
input = input instanceof Array ? input : [input];
|
|
6778
|
+
this._invokeAll(function(ext) {
|
|
6779
|
+
ext.beforeParse && ext.beforeParse(input);
|
|
6780
|
+
});
|
|
6781
|
+
const objectsWithoutScene = [];
|
|
6782
|
+
for (let i = 0; i < input.length; i++) {
|
|
6783
|
+
if (input[i] instanceof Scene3) {
|
|
6784
|
+
this.processScene(input[i]);
|
|
6785
|
+
} else {
|
|
6786
|
+
objectsWithoutScene.push(input[i]);
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6789
|
+
if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
|
|
6790
|
+
for (let i = 0; i < this.skins.length; ++i) {
|
|
6791
|
+
this.processSkin(this.skins[i]);
|
|
6792
|
+
}
|
|
6793
|
+
for (let i = 0; i < options.animations.length; ++i) {
|
|
6794
|
+
this.processAnimation(options.animations[i], input[0]);
|
|
6795
|
+
}
|
|
6796
|
+
this._invokeAll(function(ext) {
|
|
6797
|
+
ext.afterParse && ext.afterParse(input);
|
|
6798
|
+
});
|
|
6799
|
+
}
|
|
6800
|
+
_invokeAll(func) {
|
|
6801
|
+
for (let i = 0, il = this.plugins.length; i < il; i++) {
|
|
6802
|
+
func(this.plugins[i]);
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
};
|
|
6806
|
+
var GLTFLightExtension = class {
|
|
6807
|
+
constructor(writer) {
|
|
6808
|
+
this.writer = writer;
|
|
6809
|
+
this.name = "KHR_lights_punctual";
|
|
6810
|
+
}
|
|
6811
|
+
writeNode(light, nodeDef) {
|
|
6812
|
+
if (!light.isLight) return;
|
|
6813
|
+
if (!light.isDirectionalLight && !light.isPointLight && !light.isSpotLight) {
|
|
6814
|
+
console.warn("THREE.GLTFExporter: Only directional, point, and spot lights are supported.", light);
|
|
6815
|
+
return;
|
|
6816
|
+
}
|
|
6817
|
+
const writer = this.writer;
|
|
6818
|
+
const json = writer.json;
|
|
6819
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6820
|
+
const lightDef = {};
|
|
6821
|
+
if (light.name) lightDef.name = light.name;
|
|
6822
|
+
lightDef.color = light.color.toArray();
|
|
6823
|
+
lightDef.intensity = light.intensity;
|
|
6824
|
+
if (light.isDirectionalLight) {
|
|
6825
|
+
lightDef.type = "directional";
|
|
6826
|
+
} else if (light.isPointLight) {
|
|
6827
|
+
lightDef.type = "point";
|
|
6828
|
+
if (light.distance > 0) lightDef.range = light.distance;
|
|
6829
|
+
} else if (light.isSpotLight) {
|
|
6830
|
+
lightDef.type = "spot";
|
|
6831
|
+
if (light.distance > 0) lightDef.range = light.distance;
|
|
6832
|
+
lightDef.spot = {};
|
|
6833
|
+
lightDef.spot.innerConeAngle = (1 - light.penumbra) * light.angle;
|
|
6834
|
+
lightDef.spot.outerConeAngle = light.angle;
|
|
6835
|
+
}
|
|
6836
|
+
if (light.decay !== void 0 && light.decay !== 2) {
|
|
6837
|
+
console.warn("THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, and expects light.decay=2.");
|
|
6838
|
+
}
|
|
6839
|
+
if (light.target && (light.target.parent !== light || light.target.position.x !== 0 || light.target.position.y !== 0 || light.target.position.z !== -1)) {
|
|
6840
|
+
console.warn("THREE.GLTFExporter: Light direction may be lost. For best results, make light.target a child of the light with position 0,0,-1.");
|
|
6841
|
+
}
|
|
6842
|
+
if (!extensionsUsed[this.name]) {
|
|
6843
|
+
json.extensions = json.extensions || {};
|
|
6844
|
+
json.extensions[this.name] = { lights: [] };
|
|
6845
|
+
extensionsUsed[this.name] = true;
|
|
6846
|
+
}
|
|
6847
|
+
const lights = json.extensions[this.name].lights;
|
|
6848
|
+
lights.push(lightDef);
|
|
6849
|
+
nodeDef.extensions = nodeDef.extensions || {};
|
|
6850
|
+
nodeDef.extensions[this.name] = { light: lights.length - 1 };
|
|
6851
|
+
}
|
|
6852
|
+
};
|
|
6853
|
+
var GLTFMaterialsUnlitExtension = class {
|
|
6854
|
+
constructor(writer) {
|
|
6855
|
+
this.writer = writer;
|
|
6856
|
+
this.name = "KHR_materials_unlit";
|
|
6857
|
+
}
|
|
6858
|
+
writeMaterial(material, materialDef) {
|
|
6859
|
+
if (!material.isMeshBasicMaterial) return;
|
|
6860
|
+
const writer = this.writer;
|
|
6861
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6862
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6863
|
+
materialDef.extensions[this.name] = {};
|
|
6864
|
+
extensionsUsed[this.name] = true;
|
|
6865
|
+
materialDef.pbrMetallicRoughness.metallicFactor = 0;
|
|
6866
|
+
materialDef.pbrMetallicRoughness.roughnessFactor = 0.9;
|
|
6867
|
+
}
|
|
6868
|
+
};
|
|
6869
|
+
var GLTFMaterialsClearcoatExtension = class {
|
|
6870
|
+
constructor(writer) {
|
|
6871
|
+
this.writer = writer;
|
|
6872
|
+
this.name = "KHR_materials_clearcoat";
|
|
6873
|
+
}
|
|
6874
|
+
writeMaterial(material, materialDef) {
|
|
6875
|
+
if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
|
|
6876
|
+
const writer = this.writer;
|
|
6877
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6878
|
+
const extensionDef = {};
|
|
6879
|
+
extensionDef.clearcoatFactor = material.clearcoat;
|
|
6880
|
+
if (material.clearcoatMap) {
|
|
6881
|
+
const clearcoatMapDef = {
|
|
6882
|
+
index: writer.processTexture(material.clearcoatMap),
|
|
6883
|
+
texCoord: material.clearcoatMap.channel
|
|
6884
|
+
};
|
|
6885
|
+
writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
|
|
6886
|
+
extensionDef.clearcoatTexture = clearcoatMapDef;
|
|
6887
|
+
}
|
|
6888
|
+
extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
|
|
6889
|
+
if (material.clearcoatRoughnessMap) {
|
|
6890
|
+
const clearcoatRoughnessMapDef = {
|
|
6891
|
+
index: writer.processTexture(material.clearcoatRoughnessMap),
|
|
6892
|
+
texCoord: material.clearcoatRoughnessMap.channel
|
|
6893
|
+
};
|
|
6894
|
+
writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
|
|
6895
|
+
extensionDef.clearcoatRoughnessTexture = clearcoatRoughnessMapDef;
|
|
6896
|
+
}
|
|
6897
|
+
if (material.clearcoatNormalMap) {
|
|
6898
|
+
const clearcoatNormalMapDef = {
|
|
6899
|
+
index: writer.processTexture(material.clearcoatNormalMap),
|
|
6900
|
+
texCoord: material.clearcoatNormalMap.channel
|
|
6901
|
+
};
|
|
6902
|
+
writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
|
|
6903
|
+
extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
|
|
6904
|
+
}
|
|
6905
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6906
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
6907
|
+
extensionsUsed[this.name] = true;
|
|
6908
|
+
}
|
|
6909
|
+
};
|
|
6910
|
+
var GLTFMaterialsIridescenceExtension = class {
|
|
6911
|
+
constructor(writer) {
|
|
6912
|
+
this.writer = writer;
|
|
6913
|
+
this.name = "KHR_materials_iridescence";
|
|
6914
|
+
}
|
|
6915
|
+
writeMaterial(material, materialDef) {
|
|
6916
|
+
if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
|
|
6917
|
+
const writer = this.writer;
|
|
6918
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6919
|
+
const extensionDef = {};
|
|
6920
|
+
extensionDef.iridescenceFactor = material.iridescence;
|
|
6921
|
+
if (material.iridescenceMap) {
|
|
6922
|
+
const iridescenceMapDef = {
|
|
6923
|
+
index: writer.processTexture(material.iridescenceMap),
|
|
6924
|
+
texCoord: material.iridescenceMap.channel
|
|
6925
|
+
};
|
|
6926
|
+
writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
|
|
6927
|
+
extensionDef.iridescenceTexture = iridescenceMapDef;
|
|
6928
|
+
}
|
|
6929
|
+
extensionDef.iridescenceIor = material.iridescenceIOR;
|
|
6930
|
+
extensionDef.iridescenceThicknessMinimum = material.iridescenceThicknessRange[0];
|
|
6931
|
+
extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
|
|
6932
|
+
if (material.iridescenceThicknessMap) {
|
|
6933
|
+
const iridescenceThicknessMapDef = {
|
|
6934
|
+
index: writer.processTexture(material.iridescenceThicknessMap),
|
|
6935
|
+
texCoord: material.iridescenceThicknessMap.channel
|
|
6936
|
+
};
|
|
6937
|
+
writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
|
|
6938
|
+
extensionDef.iridescenceThicknessTexture = iridescenceThicknessMapDef;
|
|
6939
|
+
}
|
|
6940
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6941
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
6942
|
+
extensionsUsed[this.name] = true;
|
|
6943
|
+
}
|
|
6944
|
+
};
|
|
6945
|
+
var GLTFMaterialsTransmissionExtension = class {
|
|
6946
|
+
constructor(writer) {
|
|
6947
|
+
this.writer = writer;
|
|
6948
|
+
this.name = "KHR_materials_transmission";
|
|
6949
|
+
}
|
|
6950
|
+
writeMaterial(material, materialDef) {
|
|
6951
|
+
if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
|
|
6952
|
+
const writer = this.writer;
|
|
6953
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6954
|
+
const extensionDef = {};
|
|
6955
|
+
extensionDef.transmissionFactor = material.transmission;
|
|
6956
|
+
if (material.transmissionMap) {
|
|
6957
|
+
const transmissionMapDef = {
|
|
6958
|
+
index: writer.processTexture(material.transmissionMap),
|
|
6959
|
+
texCoord: material.transmissionMap.channel
|
|
6960
|
+
};
|
|
6961
|
+
writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
|
|
6962
|
+
extensionDef.transmissionTexture = transmissionMapDef;
|
|
6963
|
+
}
|
|
6964
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6965
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
6966
|
+
extensionsUsed[this.name] = true;
|
|
6967
|
+
}
|
|
6968
|
+
};
|
|
6969
|
+
var GLTFMaterialsVolumeExtension = class {
|
|
6970
|
+
constructor(writer) {
|
|
6971
|
+
this.writer = writer;
|
|
6972
|
+
this.name = "KHR_materials_volume";
|
|
6973
|
+
}
|
|
6974
|
+
writeMaterial(material, materialDef) {
|
|
6975
|
+
if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
|
|
6976
|
+
const writer = this.writer;
|
|
6977
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6978
|
+
const extensionDef = {};
|
|
6979
|
+
extensionDef.thicknessFactor = material.thickness;
|
|
6980
|
+
if (material.thicknessMap) {
|
|
6981
|
+
const thicknessMapDef = {
|
|
6982
|
+
index: writer.processTexture(material.thicknessMap),
|
|
6983
|
+
texCoord: material.thicknessMap.channel
|
|
6984
|
+
};
|
|
6985
|
+
writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
|
|
6986
|
+
extensionDef.thicknessTexture = thicknessMapDef;
|
|
6987
|
+
}
|
|
6988
|
+
extensionDef.attenuationDistance = material.attenuationDistance;
|
|
6989
|
+
extensionDef.attenuationColor = material.attenuationColor.toArray();
|
|
6990
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6991
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
6992
|
+
extensionsUsed[this.name] = true;
|
|
6993
|
+
}
|
|
6994
|
+
};
|
|
6995
|
+
var GLTFMaterialsIorExtension = class {
|
|
6996
|
+
constructor(writer) {
|
|
6997
|
+
this.writer = writer;
|
|
6998
|
+
this.name = "KHR_materials_ior";
|
|
6999
|
+
}
|
|
7000
|
+
writeMaterial(material, materialDef) {
|
|
7001
|
+
if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
|
|
7002
|
+
const writer = this.writer;
|
|
7003
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7004
|
+
const extensionDef = {};
|
|
7005
|
+
extensionDef.ior = material.ior;
|
|
7006
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7007
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7008
|
+
extensionsUsed[this.name] = true;
|
|
7009
|
+
}
|
|
7010
|
+
};
|
|
7011
|
+
var GLTFMaterialsSpecularExtension = class {
|
|
7012
|
+
constructor(writer) {
|
|
7013
|
+
this.writer = writer;
|
|
7014
|
+
this.name = "KHR_materials_specular";
|
|
7015
|
+
}
|
|
7016
|
+
writeMaterial(material, materialDef) {
|
|
7017
|
+
if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
|
|
7018
|
+
const writer = this.writer;
|
|
7019
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7020
|
+
const extensionDef = {};
|
|
7021
|
+
if (material.specularIntensityMap) {
|
|
7022
|
+
const specularIntensityMapDef = {
|
|
7023
|
+
index: writer.processTexture(material.specularIntensityMap),
|
|
7024
|
+
texCoord: material.specularIntensityMap.channel
|
|
7025
|
+
};
|
|
7026
|
+
writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
|
|
7027
|
+
extensionDef.specularTexture = specularIntensityMapDef;
|
|
7028
|
+
}
|
|
7029
|
+
if (material.specularColorMap) {
|
|
7030
|
+
const specularColorMapDef = {
|
|
7031
|
+
index: writer.processTexture(material.specularColorMap),
|
|
7032
|
+
texCoord: material.specularColorMap.channel
|
|
7033
|
+
};
|
|
7034
|
+
writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
|
|
7035
|
+
extensionDef.specularColorTexture = specularColorMapDef;
|
|
7036
|
+
}
|
|
7037
|
+
extensionDef.specularFactor = material.specularIntensity;
|
|
7038
|
+
extensionDef.specularColorFactor = material.specularColor.toArray();
|
|
7039
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7040
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7041
|
+
extensionsUsed[this.name] = true;
|
|
7042
|
+
}
|
|
7043
|
+
};
|
|
7044
|
+
var GLTFMaterialsSheenExtension = class {
|
|
7045
|
+
constructor(writer) {
|
|
7046
|
+
this.writer = writer;
|
|
7047
|
+
this.name = "KHR_materials_sheen";
|
|
7048
|
+
}
|
|
7049
|
+
writeMaterial(material, materialDef) {
|
|
7050
|
+
if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
|
|
7051
|
+
const writer = this.writer;
|
|
7052
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7053
|
+
const extensionDef = {};
|
|
7054
|
+
if (material.sheenRoughnessMap) {
|
|
7055
|
+
const sheenRoughnessMapDef = {
|
|
7056
|
+
index: writer.processTexture(material.sheenRoughnessMap),
|
|
7057
|
+
texCoord: material.sheenRoughnessMap.channel
|
|
7058
|
+
};
|
|
7059
|
+
writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
|
|
7060
|
+
extensionDef.sheenRoughnessTexture = sheenRoughnessMapDef;
|
|
7061
|
+
}
|
|
7062
|
+
if (material.sheenColorMap) {
|
|
7063
|
+
const sheenColorMapDef = {
|
|
7064
|
+
index: writer.processTexture(material.sheenColorMap),
|
|
7065
|
+
texCoord: material.sheenColorMap.channel
|
|
7066
|
+
};
|
|
7067
|
+
writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
|
|
7068
|
+
extensionDef.sheenColorTexture = sheenColorMapDef;
|
|
7069
|
+
}
|
|
7070
|
+
extensionDef.sheenRoughnessFactor = material.sheenRoughness;
|
|
7071
|
+
extensionDef.sheenColorFactor = material.sheenColor.toArray();
|
|
7072
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7073
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7074
|
+
extensionsUsed[this.name] = true;
|
|
7075
|
+
}
|
|
7076
|
+
};
|
|
7077
|
+
var GLTFMaterialsAnisotropyExtension = class {
|
|
7078
|
+
constructor(writer) {
|
|
7079
|
+
this.writer = writer;
|
|
7080
|
+
this.name = "KHR_materials_anisotropy";
|
|
7081
|
+
}
|
|
7082
|
+
writeMaterial(material, materialDef) {
|
|
7083
|
+
if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
|
|
7084
|
+
const writer = this.writer;
|
|
7085
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7086
|
+
const extensionDef = {};
|
|
7087
|
+
if (material.anisotropyMap) {
|
|
7088
|
+
const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
|
|
7089
|
+
writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
|
|
7090
|
+
extensionDef.anisotropyTexture = anisotropyMapDef;
|
|
7091
|
+
}
|
|
7092
|
+
extensionDef.anisotropyStrength = material.anisotropy;
|
|
7093
|
+
extensionDef.anisotropyRotation = material.anisotropyRotation;
|
|
7094
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7095
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7096
|
+
extensionsUsed[this.name] = true;
|
|
7097
|
+
}
|
|
7098
|
+
};
|
|
7099
|
+
var GLTFMaterialsEmissiveStrengthExtension = class {
|
|
7100
|
+
constructor(writer) {
|
|
7101
|
+
this.writer = writer;
|
|
7102
|
+
this.name = "KHR_materials_emissive_strength";
|
|
7103
|
+
}
|
|
7104
|
+
writeMaterial(material, materialDef) {
|
|
7105
|
+
if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
|
|
7106
|
+
const writer = this.writer;
|
|
7107
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7108
|
+
const extensionDef = {};
|
|
7109
|
+
extensionDef.emissiveStrength = material.emissiveIntensity;
|
|
7110
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7111
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7112
|
+
extensionsUsed[this.name] = true;
|
|
7113
|
+
}
|
|
7114
|
+
};
|
|
7115
|
+
var GLTFMeshGpuInstancing = class {
|
|
7116
|
+
constructor(writer) {
|
|
7117
|
+
this.writer = writer;
|
|
7118
|
+
this.name = "EXT_mesh_gpu_instancing";
|
|
7119
|
+
}
|
|
7120
|
+
writeNode(object, nodeDef) {
|
|
7121
|
+
if (!object.isInstancedMesh) return;
|
|
7122
|
+
const writer = this.writer;
|
|
7123
|
+
const mesh = object;
|
|
7124
|
+
const translationAttr = new Float32Array(mesh.count * 3);
|
|
7125
|
+
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
7126
|
+
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
7127
|
+
const matrix = new Matrix44();
|
|
7128
|
+
const position = new Vector38();
|
|
7129
|
+
const quaternion = new Quaternion4();
|
|
7130
|
+
const scale = new Vector38();
|
|
7131
|
+
for (let i = 0; i < mesh.count; i++) {
|
|
7132
|
+
mesh.getMatrixAt(i, matrix);
|
|
7133
|
+
matrix.decompose(position, quaternion, scale);
|
|
7134
|
+
position.toArray(translationAttr, i * 3);
|
|
7135
|
+
quaternion.toArray(rotationAttr, i * 4);
|
|
7136
|
+
scale.toArray(scaleAttr, i * 3);
|
|
7137
|
+
}
|
|
7138
|
+
const attributes = {
|
|
7139
|
+
TRANSLATION: writer.processAccessor(new BufferAttribute3(translationAttr, 3)),
|
|
7140
|
+
ROTATION: writer.processAccessor(new BufferAttribute3(rotationAttr, 4)),
|
|
7141
|
+
SCALE: writer.processAccessor(new BufferAttribute3(scaleAttr, 3))
|
|
7142
|
+
};
|
|
7143
|
+
if (mesh.instanceColor)
|
|
7144
|
+
attributes._COLOR_0 = writer.processAccessor(mesh.instanceColor);
|
|
7145
|
+
nodeDef.extensions = nodeDef.extensions || {};
|
|
7146
|
+
nodeDef.extensions[this.name] = { attributes };
|
|
7147
|
+
writer.extensionsUsed[this.name] = true;
|
|
7148
|
+
writer.extensionsRequired[this.name] = true;
|
|
7149
|
+
}
|
|
7150
|
+
};
|
|
7151
|
+
GLTFExporter.Utils = {
|
|
7152
|
+
insertKeyframe: function(track, time) {
|
|
7153
|
+
const tolerance = 1e-3;
|
|
7154
|
+
const valueSize = track.getValueSize();
|
|
7155
|
+
const times = new track.TimeBufferType(track.times.length + 1);
|
|
7156
|
+
const values = new track.ValueBufferType(track.values.length + valueSize);
|
|
7157
|
+
const interpolant = track.createInterpolant(new track.ValueBufferType(valueSize));
|
|
7158
|
+
let index;
|
|
7159
|
+
if (track.times.length === 0) {
|
|
7160
|
+
times[0] = time;
|
|
7161
|
+
for (let i = 0; i < valueSize; i++) {
|
|
7162
|
+
values[i] = 0;
|
|
7163
|
+
}
|
|
7164
|
+
index = 0;
|
|
7165
|
+
} else if (time < track.times[0]) {
|
|
7166
|
+
if (Math.abs(track.times[0] - time) < tolerance) return 0;
|
|
7167
|
+
times[0] = time;
|
|
7168
|
+
times.set(track.times, 1);
|
|
7169
|
+
values.set(interpolant.evaluate(time), 0);
|
|
7170
|
+
values.set(track.values, valueSize);
|
|
7171
|
+
index = 0;
|
|
7172
|
+
} else if (time > track.times[track.times.length - 1]) {
|
|
7173
|
+
if (Math.abs(track.times[track.times.length - 1] - time) < tolerance) {
|
|
7174
|
+
return track.times.length - 1;
|
|
7175
|
+
}
|
|
7176
|
+
times[times.length - 1] = time;
|
|
7177
|
+
times.set(track.times, 0);
|
|
7178
|
+
values.set(track.values, 0);
|
|
7179
|
+
values.set(interpolant.evaluate(time), track.values.length);
|
|
7180
|
+
index = times.length - 1;
|
|
7181
|
+
} else {
|
|
7182
|
+
for (let i = 0; i < track.times.length; i++) {
|
|
7183
|
+
if (Math.abs(track.times[i] - time) < tolerance) return i;
|
|
7184
|
+
if (track.times[i] < time && track.times[i + 1] > time) {
|
|
7185
|
+
times.set(track.times.slice(0, i + 1), 0);
|
|
7186
|
+
times[i + 1] = time;
|
|
7187
|
+
times.set(track.times.slice(i + 1), i + 2);
|
|
7188
|
+
values.set(track.values.slice(0, (i + 1) * valueSize), 0);
|
|
7189
|
+
values.set(interpolant.evaluate(time), (i + 1) * valueSize);
|
|
7190
|
+
values.set(track.values.slice((i + 1) * valueSize), (i + 2) * valueSize);
|
|
7191
|
+
index = i + 1;
|
|
7192
|
+
break;
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
track.times = times;
|
|
7197
|
+
track.values = values;
|
|
7198
|
+
return index;
|
|
7199
|
+
},
|
|
7200
|
+
mergeMorphTargetTracks: function(clip, root) {
|
|
7201
|
+
const tracks = [];
|
|
7202
|
+
const mergedTracks = {};
|
|
7203
|
+
const sourceTracks = clip.tracks;
|
|
7204
|
+
for (let i = 0; i < sourceTracks.length; ++i) {
|
|
7205
|
+
let sourceTrack = sourceTracks[i];
|
|
7206
|
+
const sourceTrackBinding = PropertyBinding.parseTrackName(sourceTrack.name);
|
|
7207
|
+
const sourceTrackNode = PropertyBinding.findNode(root, sourceTrackBinding.nodeName);
|
|
7208
|
+
if (sourceTrackBinding.propertyName !== "morphTargetInfluences" || sourceTrackBinding.propertyIndex === void 0) {
|
|
7209
|
+
tracks.push(sourceTrack);
|
|
7210
|
+
continue;
|
|
7211
|
+
}
|
|
7212
|
+
if (sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete && sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear) {
|
|
7213
|
+
if (sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) {
|
|
7214
|
+
throw new Error("THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.");
|
|
7215
|
+
}
|
|
7216
|
+
console.warn("THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.");
|
|
7217
|
+
sourceTrack = sourceTrack.clone();
|
|
7218
|
+
sourceTrack.setInterpolation(InterpolateLinear);
|
|
7219
|
+
}
|
|
7220
|
+
const targetCount = sourceTrackNode.morphTargetInfluences.length;
|
|
7221
|
+
const targetIndex = sourceTrackNode.morphTargetDictionary[sourceTrackBinding.propertyIndex];
|
|
7222
|
+
if (targetIndex === void 0) {
|
|
7223
|
+
throw new Error("THREE.GLTFExporter: Morph target name not found: " + sourceTrackBinding.propertyIndex);
|
|
7224
|
+
}
|
|
7225
|
+
let mergedTrack;
|
|
7226
|
+
if (mergedTracks[sourceTrackNode.uuid] === void 0) {
|
|
7227
|
+
mergedTrack = sourceTrack.clone();
|
|
7228
|
+
const values = new mergedTrack.ValueBufferType(targetCount * mergedTrack.times.length);
|
|
7229
|
+
for (let j = 0; j < mergedTrack.times.length; j++) {
|
|
7230
|
+
values[j * targetCount + targetIndex] = mergedTrack.values[j];
|
|
7231
|
+
}
|
|
7232
|
+
mergedTrack.name = (sourceTrackBinding.nodeName || "") + ".morphTargetInfluences";
|
|
7233
|
+
mergedTrack.values = values;
|
|
7234
|
+
mergedTracks[sourceTrackNode.uuid] = mergedTrack;
|
|
7235
|
+
tracks.push(mergedTrack);
|
|
7236
|
+
continue;
|
|
7237
|
+
}
|
|
7238
|
+
const sourceInterpolant = sourceTrack.createInterpolant(new sourceTrack.ValueBufferType(1));
|
|
7239
|
+
mergedTrack = mergedTracks[sourceTrackNode.uuid];
|
|
7240
|
+
for (let j = 0; j < mergedTrack.times.length; j++) {
|
|
7241
|
+
mergedTrack.values[j * targetCount + targetIndex] = sourceInterpolant.evaluate(mergedTrack.times[j]);
|
|
7242
|
+
}
|
|
7243
|
+
for (let j = 0; j < sourceTrack.times.length; j++) {
|
|
7244
|
+
const keyframeIndex = this.insertKeyframe(mergedTrack, sourceTrack.times[j]);
|
|
7245
|
+
mergedTrack.values[keyframeIndex * targetCount + targetIndex] = sourceTrack.values[j];
|
|
7246
|
+
}
|
|
7247
|
+
}
|
|
7248
|
+
clip.tracks = tracks;
|
|
7249
|
+
return clip;
|
|
7250
|
+
}
|
|
7251
|
+
};
|
|
7252
|
+
|
|
7253
|
+
// src/export/SceneExporter.ts
|
|
7254
|
+
init_MineRenderError();
|
|
7255
|
+
init_DisplayTransforms();
|
|
7256
|
+
init_CanvasCompat();
|
|
7257
|
+
var SceneExporter = class {
|
|
7258
|
+
/** Returns OBJ geometry with normals and UVs; material files and textures are not included. */
|
|
7259
|
+
static toObj(root) {
|
|
7260
|
+
const snapshot = createSnapshot(root, false);
|
|
7261
|
+
try {
|
|
7262
|
+
return new OBJExporter().parse(snapshot.scene);
|
|
7263
|
+
} finally {
|
|
7264
|
+
snapshot.dispose();
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
/** Returns PLY geometry with vertex colors and UVs; texture images are not included. */
|
|
7268
|
+
static toPLY(root, options) {
|
|
7269
|
+
const snapshot = createSnapshot(root, false, true);
|
|
7270
|
+
try {
|
|
7271
|
+
const result = new PLYExporter().parse(snapshot.scene, void 0, options);
|
|
7272
|
+
if (result === null) throw new MineRenderError("The scene could not be exported as PLY");
|
|
7273
|
+
return result;
|
|
7274
|
+
} finally {
|
|
7275
|
+
snapshot.dispose();
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
/**
|
|
7279
|
+
* Exports a static glTF/GLB snapshot in a browser. Atlas textures and vertex tints are retained;
|
|
7280
|
+
* MineRender's custom directional lighting is not baked into the exported materials.
|
|
7281
|
+
*/
|
|
7282
|
+
static async toGLTF(root, options = {}) {
|
|
7283
|
+
if (typeof document === "undefined" || typeof FileReader === "undefined") {
|
|
7284
|
+
throw new MineRenderError("glTF export requires a browser with canvas and FileReader support");
|
|
7285
|
+
}
|
|
7286
|
+
if (options.maxTextureSize !== void 0 && !(options.maxTextureSize >= 1)) {
|
|
7287
|
+
throw new MineRenderError("maxTextureSize must be at least 1 pixel");
|
|
7288
|
+
}
|
|
7289
|
+
const snapshot = createSnapshot(root, true);
|
|
7290
|
+
try {
|
|
7291
|
+
return await new GLTFExporter().parseAsync(snapshot.scene, {
|
|
7292
|
+
binary: options.binary ?? false,
|
|
7293
|
+
maxTextureSize: options.maxTextureSize ?? Infinity
|
|
7294
|
+
});
|
|
7295
|
+
} finally {
|
|
7296
|
+
snapshot.dispose();
|
|
7297
|
+
}
|
|
7298
|
+
}
|
|
7299
|
+
};
|
|
7300
|
+
function localMatrix(object) {
|
|
7301
|
+
return object.matrixAutoUpdate ? new Matrix45().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
|
|
7302
|
+
}
|
|
7303
|
+
function createSnapshot(root, gltf, bakeColors = false) {
|
|
7304
|
+
const scene = new Scene4();
|
|
7305
|
+
const geometries = [];
|
|
7306
|
+
const materials = [];
|
|
7307
|
+
const textures = [];
|
|
7308
|
+
const textureCopies = /* @__PURE__ */ new Map();
|
|
7309
|
+
const dispose = () => {
|
|
7310
|
+
for (const geometry of geometries) geometry.dispose();
|
|
7311
|
+
for (const material of materials) material.dispose();
|
|
7312
|
+
for (const texture of textures) texture.dispose();
|
|
7313
|
+
};
|
|
7314
|
+
const copyMaterial = (source, geometry) => {
|
|
7315
|
+
let material;
|
|
7316
|
+
const shader = source;
|
|
7317
|
+
if (shader.isShaderMaterial && gltf) {
|
|
7318
|
+
const uniforms = shader.uniforms;
|
|
7319
|
+
if (!uniforms.map?.value?.isTexture || !uniforms.SHADE || !uniforms.BRIGHTNESS || !uniforms.EMISSIVE) {
|
|
7320
|
+
throw new MineRenderError("glTF export does not support this custom ShaderMaterial");
|
|
7321
|
+
}
|
|
7322
|
+
material = new MeshBasicMaterial2({
|
|
7323
|
+
map: uniforms.map.value,
|
|
7324
|
+
vertexColors: source.vertexColors,
|
|
7325
|
+
transparent: source.transparent,
|
|
7326
|
+
side: source.side,
|
|
7327
|
+
alphaTest: 0.01,
|
|
7328
|
+
depthWrite: source.depthWrite
|
|
7329
|
+
});
|
|
7330
|
+
material.name = source.name;
|
|
7331
|
+
} else if (shader.isShaderMaterial) {
|
|
7332
|
+
material = new MeshBasicMaterial2({ vertexColors: source.vertexColors });
|
|
7333
|
+
material.name = source.name;
|
|
7334
|
+
} else {
|
|
7335
|
+
const copySource = Object.create(source);
|
|
7336
|
+
copySource.userData = {};
|
|
7337
|
+
material = source.clone.call(copySource);
|
|
7338
|
+
}
|
|
7339
|
+
materials.push(material);
|
|
7340
|
+
if (gltf) {
|
|
7341
|
+
selectAlphaMode(material, geometry);
|
|
7342
|
+
for (const [key, value] of Object.entries(material)) {
|
|
7343
|
+
if (value?.isDataTexture) {
|
|
7344
|
+
let texture = textureCopies.get(value);
|
|
7345
|
+
if (!texture) {
|
|
7346
|
+
texture = copyDataTexture(value);
|
|
7347
|
+
textureCopies.set(value, texture);
|
|
7348
|
+
textures.push(texture);
|
|
7349
|
+
}
|
|
7350
|
+
material[key] = texture;
|
|
7351
|
+
}
|
|
7352
|
+
}
|
|
7353
|
+
}
|
|
7354
|
+
return material;
|
|
7355
|
+
};
|
|
7356
|
+
const addMesh = (mesh, world, instanceColor) => {
|
|
7357
|
+
if (world.determinant() === 0 || !mesh.geometry.getAttribute("position")) return;
|
|
7358
|
+
const source = mesh.geometry;
|
|
7359
|
+
const count = source.index?.count ?? source.getAttribute("position").count;
|
|
7360
|
+
const groups = Array.isArray(mesh.material) ? source.groups : [{ start: 0, count, materialIndex: 0 }];
|
|
7361
|
+
for (const group of groups) {
|
|
7362
|
+
const sourceMaterial = Array.isArray(mesh.material) ? mesh.material[group.materialIndex ?? 0] : mesh.material;
|
|
7363
|
+
if (!sourceMaterial?.visible) continue;
|
|
7364
|
+
const start = Math.max(group.start, source.drawRange.start);
|
|
7365
|
+
const end = Math.min(count, group.start + group.count, source.drawRange.start + source.drawRange.count);
|
|
7366
|
+
const indices = [];
|
|
7367
|
+
for (let i = start; i + 2 < end; i += 3) {
|
|
7368
|
+
for (let corner = 0; corner < 3; corner++) indices.push(source.index?.getX(i + corner) ?? i + corner);
|
|
7369
|
+
}
|
|
7370
|
+
if (!indices.length) continue;
|
|
7371
|
+
let geometry = source.clone();
|
|
7372
|
+
geometry.setIndex(indices);
|
|
7373
|
+
if (new Set(indices).size < geometry.getAttribute("position").count) {
|
|
7374
|
+
const compact = geometry.toNonIndexed();
|
|
7375
|
+
geometry.dispose();
|
|
7376
|
+
geometry = compact;
|
|
7377
|
+
}
|
|
7378
|
+
geometries.push(geometry);
|
|
7379
|
+
geometry.userData = {};
|
|
7380
|
+
geometry.clearGroups();
|
|
7381
|
+
geometry.setDrawRange(0, Infinity);
|
|
7382
|
+
DisplayTransforms.apply(geometry, world);
|
|
7383
|
+
const material = copyMaterial(sourceMaterial, geometry);
|
|
7384
|
+
if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
|
|
7385
|
+
if (bakeColors || instanceColor) {
|
|
7386
|
+
const tint = (material.color ?? new Color6()).clone();
|
|
7387
|
+
if (instanceColor) tint.multiply(instanceColor);
|
|
7388
|
+
if (bakeColors) {
|
|
7389
|
+
const original = geometry.getAttribute("color");
|
|
7390
|
+
const colors = new Float32BufferAttribute3(new Float32Array(geometry.getAttribute("position").count * 3), 3);
|
|
7391
|
+
for (let i = 0; i < colors.count; i++) {
|
|
7392
|
+
colors.setXYZ(i, (original?.getX(i) ?? 1) * tint.r, (original?.getY(i) ?? 1) * tint.g, (original?.getZ(i) ?? 1) * tint.b);
|
|
7393
|
+
}
|
|
7394
|
+
geometry.setAttribute("color", colors);
|
|
7395
|
+
} else if (material.color) {
|
|
7396
|
+
material.color.copy(tint);
|
|
7397
|
+
}
|
|
7398
|
+
}
|
|
7399
|
+
const copy = new Mesh5(geometry, material);
|
|
7400
|
+
copy.name = mesh.name;
|
|
7401
|
+
copy.renderOrder = mesh.renderOrder;
|
|
7402
|
+
scene.add(copy);
|
|
7403
|
+
}
|
|
7404
|
+
};
|
|
7405
|
+
const visit = (object, parentWorld) => {
|
|
7406
|
+
if (!object.visible) return;
|
|
7407
|
+
const world = parentWorld.clone().multiply(localMatrix(object));
|
|
7408
|
+
const mesh = object;
|
|
7409
|
+
if (mesh.isMesh) {
|
|
7410
|
+
const instanced = mesh;
|
|
7411
|
+
if (instanced.isInstancedMesh) {
|
|
7412
|
+
for (let i = 0; i < instanced.count; i++) {
|
|
7413
|
+
const matrix = new Matrix45();
|
|
7414
|
+
instanced.getMatrixAt(i, matrix);
|
|
7415
|
+
const color = instanced.instanceColor ? new Color6().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
7416
|
+
addMesh(mesh, world.clone().multiply(matrix), color);
|
|
7417
|
+
}
|
|
7418
|
+
} else {
|
|
7419
|
+
addMesh(mesh, world);
|
|
7420
|
+
}
|
|
7421
|
+
}
|
|
7422
|
+
for (const child of object.children) visit(child, world);
|
|
7423
|
+
};
|
|
7424
|
+
try {
|
|
7425
|
+
const ancestors = [];
|
|
7426
|
+
for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
|
|
7427
|
+
const world = new Matrix45();
|
|
7428
|
+
for (const ancestor of ancestors) {
|
|
7429
|
+
if (!ancestor.visible) return { scene, dispose };
|
|
7430
|
+
world.multiply(localMatrix(ancestor));
|
|
7431
|
+
}
|
|
7432
|
+
visit(root, world);
|
|
7433
|
+
return { scene, dispose };
|
|
7434
|
+
} catch (error) {
|
|
7435
|
+
dispose();
|
|
7436
|
+
throw error;
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
function selectAlphaMode(material, geometry) {
|
|
7440
|
+
const texture = material.map;
|
|
7441
|
+
if (material.type !== "MeshBasicMaterial" || !material.transparent || !material.depthWrite || material.opacity !== 1 || material.alphaMap || !texture?.isDataTexture || texture.format !== RGBAFormat3 || texture.type !== UnsignedByteType || texture.wrapS !== ClampToEdgeWrapping2 || texture.wrapT !== ClampToEdgeWrapping2 || texture.magFilter !== NearestFilter3 || texture.minFilter !== NearestFilter3 || texture.anisotropy > 1 || texture.offset.x !== 0 || texture.offset.y !== 0 || texture.repeat.x !== 1 || texture.repeat.y !== 1 || texture.rotation !== 0 || !texture.matrixAutoUpdate && !texture.matrix.elements.every((value, i) => value === (i % 4 === 0 ? 1 : 0))) return;
|
|
7442
|
+
const uv = geometry.getAttribute(texture.channel === 0 ? "uv" : `uv${texture.channel}`);
|
|
7443
|
+
const colors = geometry.getAttribute("color");
|
|
7444
|
+
if (!uv || material.vertexColors && colors?.itemSize === 4) return;
|
|
7445
|
+
const { data, width, height } = texture.image;
|
|
7446
|
+
if (!data || width < 1 || height < 1 || data.length < width * height * 4) return;
|
|
7447
|
+
const count = geometry.index?.count ?? uv.count;
|
|
7448
|
+
let holes = false;
|
|
7449
|
+
for (let i = 0; i + 2 < count; i += 3) {
|
|
7450
|
+
let minU = Infinity, maxU = -Infinity, minV = Infinity, maxV = -Infinity;
|
|
7451
|
+
for (let corner = 0; corner < 3; corner++) {
|
|
7452
|
+
const index = geometry.index?.getX(i + corner) ?? i + corner;
|
|
7453
|
+
const u = uv.getX(index), v = texture.flipY ? 1 - uv.getY(index) : uv.getY(index);
|
|
7454
|
+
if (!Number.isFinite(u) || !Number.isFinite(v)) return;
|
|
7455
|
+
minU = Math.min(minU, u);
|
|
7456
|
+
maxU = Math.max(maxU, u);
|
|
7457
|
+
minV = Math.min(minV, v);
|
|
7458
|
+
maxV = Math.max(maxV, v);
|
|
7459
|
+
}
|
|
7460
|
+
const minX = Math.max(0, Math.min(width - 1, Math.floor(minU * width)));
|
|
7461
|
+
const maxX = Math.max(minX, Math.min(width - 1, Math.ceil(maxU * width) - 1));
|
|
7462
|
+
const minY = Math.max(0, Math.min(height - 1, Math.floor(minV * height)));
|
|
7463
|
+
const maxY = Math.max(minY, Math.min(height - 1, Math.ceil(maxV * height) - 1));
|
|
7464
|
+
for (let y = minY; y <= maxY; y++) {
|
|
7465
|
+
for (let x = minX; x <= maxX; x++) {
|
|
7466
|
+
const alpha = data[(y * width + x) * 4 + 3];
|
|
7467
|
+
if (alpha === 255) continue;
|
|
7468
|
+
if (alpha !== 0 && alpha / 255 >= material.alphaTest) return;
|
|
7469
|
+
holes = true;
|
|
7470
|
+
}
|
|
7471
|
+
}
|
|
7472
|
+
}
|
|
7473
|
+
material.transparent = false;
|
|
7474
|
+
if (holes && material.alphaTest === 0) material.alphaTest = 1 / 255;
|
|
7475
|
+
}
|
|
7476
|
+
function copyDataTexture(source) {
|
|
7477
|
+
const image = source.image;
|
|
7478
|
+
if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
|
|
7479
|
+
throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
|
|
7480
|
+
}
|
|
7481
|
+
const canvas = createCanvas(image.width, image.height);
|
|
7482
|
+
const context = canvas.getContext("2d");
|
|
7483
|
+
if (!context) throw new MineRenderError("glTF export could not create a 2D canvas context");
|
|
7484
|
+
const pixels = context.createImageData(image.width, image.height);
|
|
7485
|
+
pixels.data.set(image.data);
|
|
7486
|
+
context.putImageData(pixels, 0, 0);
|
|
7487
|
+
const copySource = Object.create(source);
|
|
7488
|
+
copySource.userData = {};
|
|
7489
|
+
copySource.source = new Source2(canvas);
|
|
7490
|
+
return new Texture4().copy(copySource);
|
|
7491
|
+
}
|
|
7492
|
+
|
|
4913
7493
|
// src/gui/GuiHelper.ts
|
|
4914
7494
|
var GuiHelper = class {
|
|
4915
7495
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
@@ -4924,7 +7504,7 @@ init_ModelTextures();
|
|
|
4924
7504
|
init_Caching();
|
|
4925
7505
|
init_SceneObject();
|
|
4926
7506
|
init_Materials();
|
|
4927
|
-
import { Box2, Mesh as
|
|
7507
|
+
import { Box2, Mesh as Mesh6, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
|
|
4928
7508
|
var GuiObject = class extends SceneObject {
|
|
4929
7509
|
constructor(textureLayers, options) {
|
|
4930
7510
|
super({ ...options, instanceMeshes: false, mergeMeshes: false });
|
|
@@ -4946,7 +7526,7 @@ var GuiObject = class extends SceneObject {
|
|
|
4946
7526
|
const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
|
|
4947
7527
|
const [width, height] = layer.size ?? [cropWidth, cropHeight];
|
|
4948
7528
|
const [x, y] = layer.position ?? [0, 0];
|
|
4949
|
-
const geometry = new
|
|
7529
|
+
const geometry = new PlaneGeometry2(width, height);
|
|
4950
7530
|
this.geometries.add(geometry);
|
|
4951
7531
|
const uv = geometry.getAttribute("uv");
|
|
4952
7532
|
for (let i = 0; i < uv.count; i++) {
|
|
@@ -4956,13 +7536,13 @@ var GuiObject = class extends SceneObject {
|
|
|
4956
7536
|
1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
|
|
4957
7537
|
);
|
|
4958
7538
|
}
|
|
4959
|
-
const mesh = new
|
|
7539
|
+
const mesh = new Mesh6(geometry, material);
|
|
4960
7540
|
mesh.name = `mesh:${layer.name ?? index}`;
|
|
4961
7541
|
mesh.position.set(x + width / 2, -y - height / 2, 0);
|
|
4962
7542
|
mesh.renderOrder = index;
|
|
4963
7543
|
this.add(mesh);
|
|
4964
|
-
this.bounds.expandByPoint(new
|
|
4965
|
-
this.bounds.expandByPoint(new
|
|
7544
|
+
this.bounds.expandByPoint(new Vector23(x, y));
|
|
7545
|
+
this.bounds.expandByPoint(new Vector23(x + width, y + height));
|
|
4966
7546
|
}
|
|
4967
7547
|
this.initialized = true;
|
|
4968
7548
|
this.notifyDirty();
|
|
@@ -5011,7 +7591,7 @@ init_image();
|
|
|
5011
7591
|
// src/inspector/SceneInspector.ts
|
|
5012
7592
|
init_SceneObject();
|
|
5013
7593
|
init_util();
|
|
5014
|
-
import { Raycaster, Vector2 as
|
|
7594
|
+
import { Raycaster, Vector2 as Vector24 } from "three";
|
|
5015
7595
|
init_log();
|
|
5016
7596
|
init_three();
|
|
5017
7597
|
var p7 = prefix("SceneInspector");
|
|
@@ -5019,7 +7599,7 @@ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
|
|
|
5019
7599
|
var SceneInspector = class {
|
|
5020
7600
|
constructor(renderer) {
|
|
5021
7601
|
this.renderer = renderer;
|
|
5022
|
-
this.mouse = new
|
|
7602
|
+
this.mouse = new Vector24();
|
|
5023
7603
|
this.listeners = new AbortController();
|
|
5024
7604
|
this.objectInfoContainer = document.createElement("div");
|
|
5025
7605
|
this.objectControlsContainer = document.createElement("div");
|
|
@@ -5627,7 +8207,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
|
|
|
5627
8207
|
init_MineRenderError();
|
|
5628
8208
|
init_InstanceReference();
|
|
5629
8209
|
init_AssetKey();
|
|
5630
|
-
import { Euler as Euler7, Matrix4 as
|
|
8210
|
+
import { Euler as Euler7, Matrix4 as Matrix47, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
|
|
5631
8211
|
init_ModelCulling();
|
|
5632
8212
|
init_FluidGeometry();
|
|
5633
8213
|
var _BlockObject = class _BlockObject extends SceneObject {
|
|
@@ -5688,11 +8268,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
5688
8268
|
getModelCullMask(model, worldMask) {
|
|
5689
8269
|
const object = isInstanceReference(model) ? model.instanceable : model;
|
|
5690
8270
|
if (object.options.displayPosition) return 0;
|
|
5691
|
-
const position = new
|
|
5692
|
-
const rotation = new
|
|
5693
|
-
const scale = new
|
|
8271
|
+
const position = new Vector311();
|
|
8272
|
+
const rotation = new Quaternion5();
|
|
8273
|
+
const scale = new Vector311();
|
|
5694
8274
|
this.getModelMatrix(model).decompose(position, rotation, scale);
|
|
5695
|
-
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new
|
|
8275
|
+
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
|
|
5696
8276
|
return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
|
|
5697
8277
|
}
|
|
5698
8278
|
async setCullMask(worldMask) {
|
|
@@ -5755,7 +8335,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
5755
8335
|
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
|
|
5756
8336
|
);
|
|
5757
8337
|
const previous = this._fluidModel;
|
|
5758
|
-
const matrix = previous ? this.getModelMatrix(previous) : new
|
|
8338
|
+
const matrix = previous ? this.getModelMatrix(previous) : new Matrix47().makeTranslation(...this.position.toArray());
|
|
5759
8339
|
if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
|
|
5760
8340
|
else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
5761
8341
|
this._models = this._models.filter((model) => model !== previous);
|
|
@@ -5886,7 +8466,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
5886
8466
|
setPositionRotationScaleAt(index, position, rotation, scale) {
|
|
5887
8467
|
super.setPositionRotationScaleAt(index, position, rotation, scale);
|
|
5888
8468
|
}
|
|
5889
|
-
getMatrixAt(index, matrix = new
|
|
8469
|
+
getMatrixAt(index, matrix = new Matrix47()) {
|
|
5890
8470
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
5891
8471
|
const child = this._models[0];
|
|
5892
8472
|
if (child && isModelObject(child)) {
|
|
@@ -7759,7 +10339,7 @@ init_nbt();
|
|
|
7759
10339
|
init_SceneObject();
|
|
7760
10340
|
var import_ts_deepmerge8 = __toESM(require_dist());
|
|
7761
10341
|
init_ModelObject();
|
|
7762
|
-
import { Scene as
|
|
10342
|
+
import { Scene as Scene5 } from "three";
|
|
7763
10343
|
|
|
7764
10344
|
// src/skin/scene/SkinObject.ts
|
|
7765
10345
|
init_SceneObject();
|
|
@@ -8492,7 +11072,7 @@ init_util();
|
|
|
8492
11072
|
init_Caching();
|
|
8493
11073
|
init_CacheKey();
|
|
8494
11074
|
init_MineRenderError();
|
|
8495
|
-
import { DataTexture, DoubleSide as
|
|
11075
|
+
import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial5, SRGBColorSpace as SRGBColorSpace5 } from "three";
|
|
8496
11076
|
|
|
8497
11077
|
// src/skin/SkinImage.ts
|
|
8498
11078
|
init_Caching();
|
|
@@ -8573,11 +11153,11 @@ var SkinTextures = class {
|
|
|
8573
11153
|
});
|
|
8574
11154
|
}
|
|
8575
11155
|
static createMaterial(pixels, width, height, transparent = true) {
|
|
8576
|
-
const texture = Textures.initTextureProps(new
|
|
8577
|
-
texture.colorSpace =
|
|
11156
|
+
const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
|
|
11157
|
+
texture.colorSpace = SRGBColorSpace5;
|
|
8578
11158
|
texture.flipY = true;
|
|
8579
11159
|
texture.needsUpdate = true;
|
|
8580
|
-
return new
|
|
11160
|
+
return new MeshBasicMaterial5({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
|
|
8581
11161
|
}
|
|
8582
11162
|
static isSlim(image, scale) {
|
|
8583
11163
|
for (const [x, y] of [[46, 52], [54, 20]]) {
|
|
@@ -8804,7 +11384,7 @@ var SkinObject = class extends SceneObject {
|
|
|
8804
11384
|
};
|
|
8805
11385
|
|
|
8806
11386
|
// src/renderer/MineRenderScene.ts
|
|
8807
|
-
var _MineRenderScene = class _MineRenderScene extends
|
|
11387
|
+
var _MineRenderScene = class _MineRenderScene extends Scene5 {
|
|
8808
11388
|
constructor(options) {
|
|
8809
11389
|
super();
|
|
8810
11390
|
this.isMineRenderScene = true;
|
|
@@ -8936,7 +11516,7 @@ function isMineRenderScene(obj) {
|
|
|
8936
11516
|
}
|
|
8937
11517
|
|
|
8938
11518
|
// src/renderer/Renderer.ts
|
|
8939
|
-
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as
|
|
11519
|
+
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector313, WebGLRenderer as WebGLRenderer2 } from "three";
|
|
8940
11520
|
var import_ts_deepmerge9 = __toESM(require_dist());
|
|
8941
11521
|
init_util();
|
|
8942
11522
|
import Stats from "stats.js";
|
|
@@ -8947,11 +11527,11 @@ init_three();
|
|
|
8947
11527
|
import {
|
|
8948
11528
|
EventDispatcher,
|
|
8949
11529
|
MOUSE,
|
|
8950
|
-
Quaternion as
|
|
11530
|
+
Quaternion as Quaternion6,
|
|
8951
11531
|
Spherical,
|
|
8952
11532
|
TOUCH,
|
|
8953
|
-
Vector2 as
|
|
8954
|
-
Vector3 as
|
|
11533
|
+
Vector2 as Vector25,
|
|
11534
|
+
Vector3 as Vector312
|
|
8955
11535
|
} from "three";
|
|
8956
11536
|
var _changeEvent = { type: "change" };
|
|
8957
11537
|
var _startEvent = { type: "start" };
|
|
@@ -8965,7 +11545,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
8965
11545
|
this.domElement = domElement;
|
|
8966
11546
|
this.domElement.style.touchAction = "none";
|
|
8967
11547
|
this.enabled = true;
|
|
8968
|
-
this.target = new
|
|
11548
|
+
this.target = new Vector312();
|
|
8969
11549
|
this.minDistance = 0;
|
|
8970
11550
|
this.maxDistance = Infinity;
|
|
8971
11551
|
this.minZoom = 0;
|
|
@@ -9017,11 +11597,11 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9017
11597
|
state = STATE.NONE;
|
|
9018
11598
|
};
|
|
9019
11599
|
this.update = function() {
|
|
9020
|
-
const offset = new
|
|
9021
|
-
const quat = new
|
|
11600
|
+
const offset = new Vector312();
|
|
11601
|
+
const quat = new Quaternion6().setFromUnitVectors(object.up, new Vector312(0, 1, 0));
|
|
9022
11602
|
const quatInverse = quat.clone().invert();
|
|
9023
|
-
const lastPosition = new
|
|
9024
|
-
const lastQuaternion = new
|
|
11603
|
+
const lastPosition = new Vector312();
|
|
11604
|
+
const lastQuaternion = new Quaternion6();
|
|
9025
11605
|
const twoPI = 2 * Math.PI;
|
|
9026
11606
|
return function update() {
|
|
9027
11607
|
const position = scope.object.position;
|
|
@@ -9110,17 +11690,17 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9110
11690
|
const spherical = new Spherical();
|
|
9111
11691
|
const sphericalDelta = new Spherical();
|
|
9112
11692
|
let scale = 1;
|
|
9113
|
-
const panOffset = new
|
|
11693
|
+
const panOffset = new Vector312();
|
|
9114
11694
|
let zoomChanged = false;
|
|
9115
|
-
const rotateStart = new
|
|
9116
|
-
const rotateEnd = new
|
|
9117
|
-
const rotateDelta = new
|
|
9118
|
-
const panStart = new
|
|
9119
|
-
const panEnd = new
|
|
9120
|
-
const panDelta = new
|
|
9121
|
-
const dollyStart = new
|
|
9122
|
-
const dollyEnd = new
|
|
9123
|
-
const dollyDelta = new
|
|
11695
|
+
const rotateStart = new Vector25();
|
|
11696
|
+
const rotateEnd = new Vector25();
|
|
11697
|
+
const rotateDelta = new Vector25();
|
|
11698
|
+
const panStart = new Vector25();
|
|
11699
|
+
const panEnd = new Vector25();
|
|
11700
|
+
const panDelta = new Vector25();
|
|
11701
|
+
const dollyStart = new Vector25();
|
|
11702
|
+
const dollyEnd = new Vector25();
|
|
11703
|
+
const dollyDelta = new Vector25();
|
|
9124
11704
|
const pointers = [];
|
|
9125
11705
|
const pointerPositions = {};
|
|
9126
11706
|
function getAutoRotationAngle() {
|
|
@@ -9136,7 +11716,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9136
11716
|
sphericalDelta.phi -= angle;
|
|
9137
11717
|
}
|
|
9138
11718
|
const panLeft = function() {
|
|
9139
|
-
const v = new
|
|
11719
|
+
const v = new Vector312();
|
|
9140
11720
|
return function panLeft2(distance, objectMatrix) {
|
|
9141
11721
|
v.setFromMatrixColumn(objectMatrix, 0);
|
|
9142
11722
|
v.multiplyScalar(-distance);
|
|
@@ -9144,7 +11724,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9144
11724
|
};
|
|
9145
11725
|
}();
|
|
9146
11726
|
const panUp = function() {
|
|
9147
|
-
const v = new
|
|
11727
|
+
const v = new Vector312();
|
|
9148
11728
|
return function panUp2(distance, objectMatrix) {
|
|
9149
11729
|
if (scope.screenSpacePanning === true) {
|
|
9150
11730
|
v.setFromMatrixColumn(objectMatrix, 1);
|
|
@@ -9157,7 +11737,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9157
11737
|
};
|
|
9158
11738
|
}();
|
|
9159
11739
|
const pan = function() {
|
|
9160
|
-
const offset = new
|
|
11740
|
+
const offset = new Vector312();
|
|
9161
11741
|
return function pan2(deltaX, deltaY) {
|
|
9162
11742
|
const element = scope.domElement;
|
|
9163
11743
|
if (scope.object.isPerspectiveCamera) {
|
|
@@ -9566,7 +12146,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9566
12146
|
function trackPointer(event) {
|
|
9567
12147
|
let position = pointerPositions[event.pointerId];
|
|
9568
12148
|
if (position === void 0) {
|
|
9569
|
-
position = new
|
|
12149
|
+
position = new Vector25();
|
|
9570
12150
|
pointerPositions[event.pointerId] = position;
|
|
9571
12151
|
}
|
|
9572
12152
|
position.set(event.pageX, event.pageY);
|
|
@@ -9630,7 +12210,7 @@ var _Renderer = class _Renderer {
|
|
|
9630
12210
|
switch (this.options.camera.type) {
|
|
9631
12211
|
case "perspective":
|
|
9632
12212
|
default:
|
|
9633
|
-
return new
|
|
12213
|
+
return new PerspectiveCamera2(
|
|
9634
12214
|
this.options.camera.perspective.fov,
|
|
9635
12215
|
this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
|
|
9636
12216
|
this.options.camera.near,
|
|
@@ -9648,7 +12228,7 @@ var _Renderer = class _Renderer {
|
|
|
9648
12228
|
}
|
|
9649
12229
|
}
|
|
9650
12230
|
createRenderer() {
|
|
9651
|
-
const renderer = new
|
|
12231
|
+
const renderer = new WebGLRenderer2({
|
|
9652
12232
|
antialias: this.options.render.antialias,
|
|
9653
12233
|
alpha: true,
|
|
9654
12234
|
powerPreference: "high-performance",
|
|
@@ -9657,7 +12237,7 @@ var _Renderer = class _Renderer {
|
|
|
9657
12237
|
renderer.setClearColor(0, 0);
|
|
9658
12238
|
renderer.shadowMap.enabled = true;
|
|
9659
12239
|
renderer.shadowMap.type = PCFSoftShadowMap;
|
|
9660
|
-
renderer.outputColorSpace =
|
|
12240
|
+
renderer.outputColorSpace = SRGBColorSpace6;
|
|
9661
12241
|
renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
|
|
9662
12242
|
renderer.setSize(this.viewWidth, this.viewHeight);
|
|
9663
12243
|
return renderer;
|
|
@@ -9849,6 +12429,9 @@ var _Renderer = class _Renderer {
|
|
|
9849
12429
|
if (next !== void 0 && t + 0.1 < next) return;
|
|
9850
12430
|
this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
|
|
9851
12431
|
}
|
|
12432
|
+
this.drawFrame();
|
|
12433
|
+
}
|
|
12434
|
+
drawFrame() {
|
|
9852
12435
|
if (this._stats) {
|
|
9853
12436
|
this._stats.begin();
|
|
9854
12437
|
}
|
|
@@ -9863,8 +12446,28 @@ var _Renderer = class _Renderer {
|
|
|
9863
12446
|
}
|
|
9864
12447
|
}
|
|
9865
12448
|
//</editor-fold>
|
|
9866
|
-
|
|
9867
|
-
|
|
12449
|
+
/**
|
|
12450
|
+
* Renders a fresh frame and returns an image data URL, including while the animation loop is stopped.
|
|
12451
|
+
* Trimming removes transparent borders; an empty image becomes one transparent pixel.
|
|
12452
|
+
* MIME type support and lossy quality (0–1) follow the canvas encoder.
|
|
12453
|
+
*/
|
|
12454
|
+
toImage(trim = false, mime = "image/png", quality) {
|
|
12455
|
+
if (this._disposed) throw new Error("Cannot export an image from a disposed renderer");
|
|
12456
|
+
if (this._controls?.enabled) {
|
|
12457
|
+
this._controls.update();
|
|
12458
|
+
}
|
|
12459
|
+
this.drawFrame();
|
|
12460
|
+
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
12461
|
+
return canvas.toDataURL(mime, quality);
|
|
12462
|
+
}
|
|
12463
|
+
toObj() {
|
|
12464
|
+
return SceneExporter.toObj(this.scene);
|
|
12465
|
+
}
|
|
12466
|
+
toPLY(options) {
|
|
12467
|
+
return SceneExporter.toPLY(this.scene, options);
|
|
12468
|
+
}
|
|
12469
|
+
toGLTF(options) {
|
|
12470
|
+
return SceneExporter.toGLTF(this.scene, options);
|
|
9868
12471
|
}
|
|
9869
12472
|
///
|
|
9870
12473
|
get attachedToBody() {
|
|
@@ -9909,8 +12512,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
|
9909
12512
|
top: void 0,
|
|
9910
12513
|
bottom: void 0
|
|
9911
12514
|
},
|
|
9912
|
-
position: new
|
|
9913
|
-
lookingAt: new
|
|
12515
|
+
position: new Vector313(50, 50, 50),
|
|
12516
|
+
lookingAt: new Vector313(0, 0, 0)
|
|
9914
12517
|
},
|
|
9915
12518
|
render: {
|
|
9916
12519
|
fpsLimit: 60,
|
|
@@ -10374,12 +12977,12 @@ var AnvilParser = class {
|
|
|
10374
12977
|
};
|
|
10375
12978
|
|
|
10376
12979
|
// src/world/Chunk.ts
|
|
10377
|
-
import { Vector3 as
|
|
12980
|
+
import { Vector3 as Vector316 } from "three";
|
|
10378
12981
|
init_BlockStates();
|
|
10379
12982
|
init_AssetKey();
|
|
10380
12983
|
|
|
10381
12984
|
// src/world/MineRenderWorld.ts
|
|
10382
|
-
import { Vector3 as
|
|
12985
|
+
import { Vector3 as Vector315 } from "three";
|
|
10383
12986
|
init_BatchedExecutor();
|
|
10384
12987
|
init_AssetKey();
|
|
10385
12988
|
init_BlockStates();
|
|
@@ -10389,7 +12992,7 @@ init_CubeFace();
|
|
|
10389
12992
|
init_AssetKey();
|
|
10390
12993
|
init_Models();
|
|
10391
12994
|
init_CubeFace();
|
|
10392
|
-
import { Matrix4 as
|
|
12995
|
+
import { Matrix4 as Matrix48, Vector3 as Vector314 } from "three";
|
|
10393
12996
|
init_ModelCulling();
|
|
10394
12997
|
init_ModelObject();
|
|
10395
12998
|
init_UVMapper();
|
|
@@ -10452,12 +13055,12 @@ var SectionModels = class {
|
|
|
10452
13055
|
});
|
|
10453
13056
|
await object.init();
|
|
10454
13057
|
const geometry = object.children[0].geometry;
|
|
10455
|
-
geometry.applyMatrix4(new
|
|
13058
|
+
geometry.applyMatrix4(new Matrix48().makeRotationFromEuler(rotation));
|
|
10456
13059
|
object.clear();
|
|
10457
13060
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
10458
13061
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
10459
13062
|
if (local < 0) return 0;
|
|
10460
|
-
const normal = new
|
|
13063
|
+
const normal = new Vector314(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
10461
13064
|
const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
10462
13065
|
return 1 << world;
|
|
10463
13066
|
});
|
|
@@ -10487,20 +13090,20 @@ var MineRenderWorld = class {
|
|
|
10487
13090
|
}
|
|
10488
13091
|
getBlockAt(posOrX, y, z) {
|
|
10489
13092
|
if (typeof posOrX == "number") {
|
|
10490
|
-
return this.getBlockAt(new
|
|
13093
|
+
return this.getBlockAt(new Vector315(posOrX, y, z));
|
|
10491
13094
|
}
|
|
10492
13095
|
if (isTripleArray(posOrX)) {
|
|
10493
|
-
return this.getBlockAt(new
|
|
13096
|
+
return this.getBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]));
|
|
10494
13097
|
}
|
|
10495
13098
|
this.validatePosBounds(posOrX);
|
|
10496
13099
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
10497
13100
|
}
|
|
10498
13101
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
10499
13102
|
if (typeof posOrX == "number") {
|
|
10500
|
-
return this.setBlockAt(new
|
|
13103
|
+
return this.setBlockAt(new Vector315(posOrX, yOrBlock, z), block);
|
|
10501
13104
|
}
|
|
10502
13105
|
if (isTripleArray(posOrX)) {
|
|
10503
|
-
return this.setBlockAt(new
|
|
13106
|
+
return this.setBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
10504
13107
|
}
|
|
10505
13108
|
return this.placeBlock(posOrX, yOrBlock);
|
|
10506
13109
|
}
|
|
@@ -10521,7 +13124,7 @@ var MineRenderWorld = class {
|
|
|
10521
13124
|
const collect = async (positions2) => {
|
|
10522
13125
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
10523
13126
|
};
|
|
10524
|
-
const place = (block) => this.placeBlock(new
|
|
13127
|
+
const place = (block) => this.placeBlock(new Vector315(...block.position), block, collect);
|
|
10525
13128
|
const keys = /* @__PURE__ */ new Map();
|
|
10526
13129
|
for (const block of multiblock.blocks) {
|
|
10527
13130
|
if (Chunk.isAir(block)) continue;
|
|
@@ -10599,13 +13202,13 @@ var MineRenderWorld = class {
|
|
|
10599
13202
|
for (const pos of positions) {
|
|
10600
13203
|
this.pendingCulling.set(pos.toArray().join(","), pos.clone());
|
|
10601
13204
|
for (const offset of CUBE_FACE_OFFSETS) {
|
|
10602
|
-
const neighbor = pos.clone().add(new
|
|
13205
|
+
const neighbor = pos.clone().add(new Vector315(...offset));
|
|
10603
13206
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
10604
13207
|
}
|
|
10605
13208
|
for (let y = -1; y <= 1; y++) {
|
|
10606
13209
|
for (let z = -1; z <= 1; z++) {
|
|
10607
13210
|
for (let x = -1; x <= 1; x++) {
|
|
10608
|
-
const neighbor = pos.clone().add(new
|
|
13211
|
+
const neighbor = pos.clone().add(new Vector315(x, y, z));
|
|
10609
13212
|
if (this.getBlockAt(neighbor)?.object?.fluidKind) {
|
|
10610
13213
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
10611
13214
|
}
|
|
@@ -10627,7 +13230,7 @@ var MineRenderWorld = class {
|
|
|
10627
13230
|
if (!block) continue;
|
|
10628
13231
|
if (block.object?.fluidKind) {
|
|
10629
13232
|
await block.object.updateFluid((x, y, z) => {
|
|
10630
|
-
const neighbor = pos.clone().add(new
|
|
13233
|
+
const neighbor = pos.clone().add(new Vector315(x, y, z));
|
|
10631
13234
|
const section = this.getChunkAt(neighbor);
|
|
10632
13235
|
const object = section?.getBlockAt(neighbor)?.object;
|
|
10633
13236
|
return {
|
|
@@ -10639,7 +13242,7 @@ var MineRenderWorld = class {
|
|
|
10639
13242
|
}
|
|
10640
13243
|
let mask = 0;
|
|
10641
13244
|
for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
10642
|
-
const neighbor = pos.clone().add(new
|
|
13245
|
+
const neighbor = pos.clone().add(new Vector315(...offset));
|
|
10643
13246
|
if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
|
|
10644
13247
|
mask |= 1 << face;
|
|
10645
13248
|
}
|
|
@@ -10673,14 +13276,14 @@ var MineRenderWorld = class {
|
|
|
10673
13276
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
10674
13277
|
}
|
|
10675
13278
|
static worldToScenePosition(pos) {
|
|
10676
|
-
return new
|
|
13279
|
+
return new Vector315(
|
|
10677
13280
|
pos.x * 16,
|
|
10678
13281
|
pos.y * 16,
|
|
10679
13282
|
pos.z * 16
|
|
10680
13283
|
);
|
|
10681
13284
|
}
|
|
10682
13285
|
static sceneToWorldPosition(pos) {
|
|
10683
|
-
return new
|
|
13286
|
+
return new Vector315(
|
|
10684
13287
|
pos.x / 16,
|
|
10685
13288
|
pos.y / 16,
|
|
10686
13289
|
pos.z / 16
|
|
@@ -10702,7 +13305,7 @@ var MineRenderWorld = class {
|
|
|
10702
13305
|
// src/world/SectionMesh.ts
|
|
10703
13306
|
init_CanvasCompat();
|
|
10704
13307
|
init_Materials();
|
|
10705
|
-
import { BufferGeometry as
|
|
13308
|
+
import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
|
|
10706
13309
|
var SectionMesh = class _SectionMesh extends Group {
|
|
10707
13310
|
constructor() {
|
|
10708
13311
|
super(...arguments);
|
|
@@ -10776,18 +13379,18 @@ var SectionMesh = class _SectionMesh extends Group {
|
|
|
10776
13379
|
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
10777
13380
|
}
|
|
10778
13381
|
}
|
|
10779
|
-
const geometry = new
|
|
10780
|
-
geometry.setAttribute("position", new
|
|
10781
|
-
geometry.setAttribute("normal", new
|
|
10782
|
-
geometry.setAttribute("uv", new
|
|
10783
|
-
geometry.setAttribute("color", new
|
|
13382
|
+
const geometry = new BufferGeometry5();
|
|
13383
|
+
geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
|
|
13384
|
+
geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
|
|
13385
|
+
geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
|
|
13386
|
+
geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
|
|
10784
13387
|
geometry.setIndex(indices);
|
|
10785
13388
|
geometry.computeBoundingBox();
|
|
10786
13389
|
geometry.computeBoundingSphere();
|
|
10787
13390
|
const material = Materials.createShadedCanvasMaterial(canvas, false);
|
|
10788
13391
|
material.vertexColors = true;
|
|
10789
13392
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
10790
|
-
const mesh = new
|
|
13393
|
+
const mesh = new Mesh10(geometry, material);
|
|
10791
13394
|
section.add(mesh);
|
|
10792
13395
|
section.ownedMeshes.push({ mesh, texture });
|
|
10793
13396
|
}
|
|
@@ -10821,10 +13424,10 @@ var Chunk = class _Chunk {
|
|
|
10821
13424
|
}
|
|
10822
13425
|
getBlockAt(posOrX, y, z) {
|
|
10823
13426
|
if (typeof posOrX == "number") {
|
|
10824
|
-
return this.getBlockAt(new
|
|
13427
|
+
return this.getBlockAt(new Vector316(posOrX, y, z));
|
|
10825
13428
|
}
|
|
10826
13429
|
if (isTripleArray(posOrX)) {
|
|
10827
|
-
return this.getBlockAt(new
|
|
13430
|
+
return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
|
|
10828
13431
|
}
|
|
10829
13432
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
10830
13433
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
@@ -10832,10 +13435,10 @@ var Chunk = class _Chunk {
|
|
|
10832
13435
|
}
|
|
10833
13436
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
10834
13437
|
if (typeof posOrX == "number") {
|
|
10835
|
-
return this.setBlockAt(new
|
|
13438
|
+
return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
|
|
10836
13439
|
}
|
|
10837
13440
|
if (isTripleArray(posOrX)) {
|
|
10838
|
-
return this.setBlockAt(new
|
|
13441
|
+
return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
10839
13442
|
}
|
|
10840
13443
|
const worldPos = posOrX;
|
|
10841
13444
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -10920,7 +13523,7 @@ var Chunk = class _Chunk {
|
|
|
10920
13523
|
}
|
|
10921
13524
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
10922
13525
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
10923
|
-
new
|
|
13526
|
+
new Vector316(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
10924
13527
|
));
|
|
10925
13528
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
10926
13529
|
this.sectionBlocks.clear();
|
|
@@ -10944,14 +13547,14 @@ var Chunk = class _Chunk {
|
|
|
10944
13547
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
10945
13548
|
}
|
|
10946
13549
|
worldPosToChunkPos(pos) {
|
|
10947
|
-
return new
|
|
13550
|
+
return new Vector316(
|
|
10948
13551
|
pos.x - this.x * 16,
|
|
10949
13552
|
pos.y - this.y * 16,
|
|
10950
13553
|
pos.z - this.z * 16
|
|
10951
13554
|
);
|
|
10952
13555
|
}
|
|
10953
13556
|
chunkPosToWorldPos(pos) {
|
|
10954
|
-
return new
|
|
13557
|
+
return new Vector316(
|
|
10955
13558
|
this.x * 16 + pos.x,
|
|
10956
13559
|
this.y * 16 + pos.y,
|
|
10957
13560
|
this.z * 16 + pos.z
|
|
@@ -11030,6 +13633,7 @@ export {
|
|
|
11030
13633
|
RequestError,
|
|
11031
13634
|
Requests,
|
|
11032
13635
|
SKIN_PARTS,
|
|
13636
|
+
SceneExporter,
|
|
11033
13637
|
SceneInspector,
|
|
11034
13638
|
SceneObject,
|
|
11035
13639
|
SceneStats,
|
|
@@ -11119,6 +13723,7 @@ export {
|
|
|
11119
13723
|
timingStart,
|
|
11120
13724
|
toDegrees,
|
|
11121
13725
|
toRadians,
|
|
11122
|
-
toTrianglesDrawMode
|
|
13726
|
+
toTrianglesDrawMode,
|
|
13727
|
+
trimCanvas
|
|
11123
13728
|
};
|
|
11124
13729
|
//# sourceMappingURL=index.mjs.map
|