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/node/index.mjs
CHANGED
|
@@ -3487,7 +3487,7 @@ var init_SceneObject = __esm({
|
|
|
3487
3487
|
});
|
|
3488
3488
|
|
|
3489
3489
|
// src/model/ModelCulling.ts
|
|
3490
|
-
import { Vector3 as
|
|
3490
|
+
import { Vector3 as Vector39 } from "three";
|
|
3491
3491
|
var ModelCulling;
|
|
3492
3492
|
var init_ModelCulling = __esm({
|
|
3493
3493
|
"src/model/ModelCulling.ts"() {
|
|
@@ -3496,7 +3496,7 @@ var init_ModelCulling = __esm({
|
|
|
3496
3496
|
static toLocalMask(worldMask, rotation) {
|
|
3497
3497
|
let localMask = 0;
|
|
3498
3498
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
3499
|
-
const normal = new
|
|
3499
|
+
const normal = new Vector39(...offset).applyEuler(rotation);
|
|
3500
3500
|
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);
|
|
3501
3501
|
if (worldFace < 0) return 0;
|
|
3502
3502
|
if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
|
|
@@ -3530,15 +3530,15 @@ var init_ModelCulling = __esm({
|
|
|
3530
3530
|
|
|
3531
3531
|
// src/three/BufferGeometryUtils.js
|
|
3532
3532
|
import {
|
|
3533
|
-
BufferAttribute as
|
|
3534
|
-
BufferGeometry,
|
|
3535
|
-
Float32BufferAttribute as
|
|
3533
|
+
BufferAttribute as BufferAttribute4,
|
|
3534
|
+
BufferGeometry as BufferGeometry2,
|
|
3535
|
+
Float32BufferAttribute as Float32BufferAttribute4,
|
|
3536
3536
|
InterleavedBuffer,
|
|
3537
3537
|
InterleavedBufferAttribute,
|
|
3538
3538
|
TriangleFanDrawMode,
|
|
3539
3539
|
TriangleStripDrawMode,
|
|
3540
3540
|
TrianglesDrawMode,
|
|
3541
|
-
Vector3 as
|
|
3541
|
+
Vector3 as Vector310
|
|
3542
3542
|
} from "three";
|
|
3543
3543
|
function computeTangents(geometry) {
|
|
3544
3544
|
geometry.computeTangents();
|
|
@@ -3551,7 +3551,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
|
|
|
3551
3551
|
const attributes = {};
|
|
3552
3552
|
const morphAttributes = {};
|
|
3553
3553
|
const morphTargetsRelative = geometries[0].morphTargetsRelative;
|
|
3554
|
-
const mergedGeometry = new
|
|
3554
|
+
const mergedGeometry = new BufferGeometry2();
|
|
3555
3555
|
let offset = 0;
|
|
3556
3556
|
for (let i = 0; i < geometries.length; ++i) {
|
|
3557
3557
|
const geometry = geometries[i];
|
|
@@ -3675,7 +3675,7 @@ function mergeBufferAttributes(attributes) {
|
|
|
3675
3675
|
array.set(attributes[i].array, offset);
|
|
3676
3676
|
offset += attributes[i].array.length;
|
|
3677
3677
|
}
|
|
3678
|
-
return new
|
|
3678
|
+
return new BufferAttribute4(array, itemSize, normalized);
|
|
3679
3679
|
}
|
|
3680
3680
|
function interleaveAttributes(attributes) {
|
|
3681
3681
|
let TypedArray;
|
|
@@ -3784,13 +3784,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
|
|
|
3784
3784
|
const name = attributeNames[i];
|
|
3785
3785
|
const oldAttribute = geometry.getAttribute(name);
|
|
3786
3786
|
const buffer = new oldAttribute.array.constructor(attrArrays[name]);
|
|
3787
|
-
const attribute = new
|
|
3787
|
+
const attribute = new BufferAttribute4(buffer, oldAttribute.itemSize, oldAttribute.normalized);
|
|
3788
3788
|
result.setAttribute(name, attribute);
|
|
3789
3789
|
if (name in morphAttrsArrays) {
|
|
3790
3790
|
for (let j = 0; j < morphAttrsArrays[name].length; j++) {
|
|
3791
3791
|
const oldMorphAttribute = geometry.morphAttributes[name][j];
|
|
3792
3792
|
const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
|
|
3793
|
-
const morphAttribute = new
|
|
3793
|
+
const morphAttribute = new BufferAttribute4(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
|
|
3794
3794
|
result.morphAttributes[name][j] = morphAttribute;
|
|
3795
3795
|
}
|
|
3796
3796
|
}
|
|
@@ -3857,15 +3857,15 @@ function computeMorphedAttributes(object) {
|
|
|
3857
3857
|
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
|
|
3858
3858
|
return null;
|
|
3859
3859
|
}
|
|
3860
|
-
const _vA = new
|
|
3861
|
-
const _vB = new
|
|
3862
|
-
const _vC = new
|
|
3863
|
-
const _tempA = new
|
|
3864
|
-
const _tempB = new
|
|
3865
|
-
const _tempC = new
|
|
3866
|
-
const _morphA = new
|
|
3867
|
-
const _morphB = new
|
|
3868
|
-
const _morphC = new
|
|
3860
|
+
const _vA = new Vector310();
|
|
3861
|
+
const _vB = new Vector310();
|
|
3862
|
+
const _vC = new Vector310();
|
|
3863
|
+
const _tempA = new Vector310();
|
|
3864
|
+
const _tempB = new Vector310();
|
|
3865
|
+
const _tempC = new Vector310();
|
|
3866
|
+
const _morphA = new Vector310();
|
|
3867
|
+
const _morphB = new Vector310();
|
|
3868
|
+
const _morphC = new Vector310();
|
|
3869
3869
|
function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
|
|
3870
3870
|
_vA.fromBufferAttribute(attribute, a2);
|
|
3871
3871
|
_vB.fromBufferAttribute(attribute, b2);
|
|
@@ -4060,8 +4060,8 @@ function computeMorphedAttributes(object) {
|
|
|
4060
4060
|
}
|
|
4061
4061
|
}
|
|
4062
4062
|
}
|
|
4063
|
-
const morphedPositionAttribute = new
|
|
4064
|
-
const morphedNormalAttribute = new
|
|
4063
|
+
const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
|
|
4064
|
+
const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
|
|
4065
4065
|
return {
|
|
4066
4066
|
positionAttribute,
|
|
4067
4067
|
normalAttribute,
|
|
@@ -4075,7 +4075,7 @@ var init_BufferGeometryUtils = __esm({
|
|
|
4075
4075
|
});
|
|
4076
4076
|
|
|
4077
4077
|
// src/model/scene/ModelObject.ts
|
|
4078
|
-
import { BoxGeometry as BoxGeometry5, BufferAttribute as
|
|
4078
|
+
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color7, Euler as Euler6, Matrix4 as Matrix46 } from "three";
|
|
4079
4079
|
function isModelObject(obj) {
|
|
4080
4080
|
return obj.isModelObject;
|
|
4081
4081
|
}
|
|
@@ -4151,19 +4151,19 @@ var init_ModelObject = __esm({
|
|
|
4151
4151
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
4152
4152
|
const tint = this.options.tints[tintIndex];
|
|
4153
4153
|
if (tint === void 0) continue;
|
|
4154
|
-
const color = new
|
|
4154
|
+
const color = new Color7(tint);
|
|
4155
4155
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
4156
4156
|
color.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
4157
4157
|
}
|
|
4158
4158
|
}
|
|
4159
|
-
elGeo.setAttribute("color", new
|
|
4159
|
+
elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
|
|
4160
4160
|
}
|
|
4161
|
-
elGeo.applyMatrix4(new
|
|
4162
|
-
elGeo.applyMatrix4(new
|
|
4161
|
+
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));
|
|
4162
|
+
elGeo.applyMatrix4(new Matrix46().makeTranslation(el.from[0], el.from[1], el.from[2]));
|
|
4163
4163
|
if (el.rotation) {
|
|
4164
4164
|
applyElementRotation(el.rotation, elGeo);
|
|
4165
4165
|
}
|
|
4166
|
-
elGeo.applyMatrix4(new
|
|
4166
|
+
elGeo.applyMatrix4(new Matrix46().makeTranslation(-8, -8, -8));
|
|
4167
4167
|
if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
|
|
4168
4168
|
if (this.options.mergeMeshes) {
|
|
4169
4169
|
allGeos.push(elGeo);
|
|
@@ -4276,7 +4276,7 @@ var init_fluidBlocks = __esm({
|
|
|
4276
4276
|
});
|
|
4277
4277
|
|
|
4278
4278
|
// src/model/fluid/FluidGeometry.ts
|
|
4279
|
-
import { BufferGeometry as
|
|
4279
|
+
import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
|
|
4280
4280
|
function getBlockFluidState(key, state) {
|
|
4281
4281
|
const rule = key && fluidRules[key.toNamespacedString()];
|
|
4282
4282
|
if (rule) return {
|
|
@@ -4294,7 +4294,7 @@ function ownHeight(sample) {
|
|
|
4294
4294
|
return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
|
|
4295
4295
|
}
|
|
4296
4296
|
function createFluidGeometry(kind, sample) {
|
|
4297
|
-
const geometry = new
|
|
4297
|
+
const geometry = new BufferGeometry3();
|
|
4298
4298
|
const positions = [], normals = [], uvs = [], indices = [];
|
|
4299
4299
|
const self = sample(0, 0, 0);
|
|
4300
4300
|
const height = (x, z) => {
|
|
@@ -4393,9 +4393,9 @@ function createFluidGeometry(kind, sample) {
|
|
|
4393
4393
|
1
|
|
4394
4394
|
);
|
|
4395
4395
|
}
|
|
4396
|
-
geometry.setAttribute("position", new
|
|
4397
|
-
geometry.setAttribute("normal", new
|
|
4398
|
-
geometry.setAttribute("uv", new
|
|
4396
|
+
geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
|
|
4397
|
+
geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
|
|
4398
|
+
geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
|
|
4399
4399
|
geometry.setIndex(indices);
|
|
4400
4400
|
return geometry;
|
|
4401
4401
|
}
|
|
@@ -4415,7 +4415,7 @@ __export(FluidModelObject_exports, {
|
|
|
4415
4415
|
FluidModelObject: () => FluidModelObject,
|
|
4416
4416
|
sampleFluid: () => sampleFluid
|
|
4417
4417
|
});
|
|
4418
|
-
import { BufferAttribute as
|
|
4418
|
+
import { BufferAttribute as BufferAttribute6, Color as Color8, DoubleSide as DoubleSide3 } from "three";
|
|
4419
4419
|
function sampleFluid(kind, sample) {
|
|
4420
4420
|
const cells = [];
|
|
4421
4421
|
const key = [];
|
|
@@ -4466,10 +4466,10 @@ var init_FluidModelObject = __esm({
|
|
|
4466
4466
|
}
|
|
4467
4467
|
}
|
|
4468
4468
|
geometry.clearGroups();
|
|
4469
|
-
const color = new
|
|
4469
|
+
const color = new Color8(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
4470
4470
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
4471
4471
|
for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
|
|
4472
|
-
geometry.setAttribute("color", new
|
|
4472
|
+
geometry.setAttribute("color", new BufferAttribute6(colors, 3));
|
|
4473
4473
|
geometry.computeBoundingBox();
|
|
4474
4474
|
geometry.computeBoundingSphere();
|
|
4475
4475
|
if (this.options.instanceMeshes) {
|
|
@@ -4483,7 +4483,7 @@ var init_FluidModelObject = __esm({
|
|
|
4483
4483
|
super.applyTextures();
|
|
4484
4484
|
this.iterateAllMeshes((mesh) => {
|
|
4485
4485
|
const material = mesh.material;
|
|
4486
|
-
material.side =
|
|
4486
|
+
material.side = DoubleSide3;
|
|
4487
4487
|
material.forceSinglePass = true;
|
|
4488
4488
|
material.depthWrite = !material.transparent;
|
|
4489
4489
|
});
|
|
@@ -4835,6 +4835,37 @@ init_PersistentCache();
|
|
|
4835
4835
|
init_CanvasCompat();
|
|
4836
4836
|
init_CanvasImage();
|
|
4837
4837
|
|
|
4838
|
+
// src/canvas/trimCanvas.ts
|
|
4839
|
+
init_CanvasCompat();
|
|
4840
|
+
function trimCanvas(source) {
|
|
4841
|
+
if (source.width === 0 || source.height === 0) return createCanvas2(1, 1);
|
|
4842
|
+
const canvas = createCanvas2(source.width, source.height);
|
|
4843
|
+
const context = canvas.getContext("2d");
|
|
4844
|
+
if (!context) throw new Error("Image export requires a 2D canvas context");
|
|
4845
|
+
context.drawImage(source, 0, 0);
|
|
4846
|
+
const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;
|
|
4847
|
+
let left = canvas.width, top = canvas.height, right = -1, bottom = -1;
|
|
4848
|
+
for (let y = 0; y < canvas.height; y++) {
|
|
4849
|
+
for (let x = 0; x < canvas.width; x++) {
|
|
4850
|
+
if (pixels[(y * canvas.width + x) * 4 + 3] === 0) continue;
|
|
4851
|
+
left = Math.min(left, x);
|
|
4852
|
+
top = Math.min(top, y);
|
|
4853
|
+
right = Math.max(right, x);
|
|
4854
|
+
bottom = Math.max(bottom, y);
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
if (right < left) {
|
|
4858
|
+
canvas.width = canvas.height = 1;
|
|
4859
|
+
return canvas;
|
|
4860
|
+
}
|
|
4861
|
+
const width = right - left + 1, height = bottom - top + 1;
|
|
4862
|
+
const cropped = context.getImageData(left, top, width, height);
|
|
4863
|
+
canvas.width = width;
|
|
4864
|
+
canvas.height = height;
|
|
4865
|
+
context.putImageData(cropped, 0, 0);
|
|
4866
|
+
return canvas;
|
|
4867
|
+
}
|
|
4868
|
+
|
|
4838
4869
|
// src/entity/scene/EntityObject.ts
|
|
4839
4870
|
init_SceneObject();
|
|
4840
4871
|
init_Caching();
|
|
@@ -4957,6 +4988,2555 @@ function isEntityObject(obj) {
|
|
|
4957
4988
|
// src/error/index.ts
|
|
4958
4989
|
init_MineRenderError();
|
|
4959
4990
|
|
|
4991
|
+
// src/export/SceneExporter.ts
|
|
4992
|
+
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";
|
|
4993
|
+
|
|
4994
|
+
// ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
|
|
4995
|
+
import {
|
|
4996
|
+
Color as Color3,
|
|
4997
|
+
Matrix3,
|
|
4998
|
+
Vector2 as Vector22,
|
|
4999
|
+
Vector3 as Vector36
|
|
5000
|
+
} from "three";
|
|
5001
|
+
var OBJExporter = class {
|
|
5002
|
+
parse(object) {
|
|
5003
|
+
let output = "";
|
|
5004
|
+
let indexVertex = 0;
|
|
5005
|
+
let indexVertexUvs = 0;
|
|
5006
|
+
let indexNormals = 0;
|
|
5007
|
+
const vertex = new Vector36();
|
|
5008
|
+
const color = new Color3();
|
|
5009
|
+
const normal = new Vector36();
|
|
5010
|
+
const uv = new Vector22();
|
|
5011
|
+
const face = [];
|
|
5012
|
+
function parseMesh(mesh) {
|
|
5013
|
+
let nbVertex = 0;
|
|
5014
|
+
let nbNormals = 0;
|
|
5015
|
+
let nbVertexUvs = 0;
|
|
5016
|
+
const geometry = mesh.geometry;
|
|
5017
|
+
const normalMatrixWorld = new Matrix3();
|
|
5018
|
+
const vertices = geometry.getAttribute("position");
|
|
5019
|
+
const normals = geometry.getAttribute("normal");
|
|
5020
|
+
const uvs = geometry.getAttribute("uv");
|
|
5021
|
+
const indices = geometry.getIndex();
|
|
5022
|
+
output += "o " + mesh.name + "\n";
|
|
5023
|
+
if (mesh.material && mesh.material.name) {
|
|
5024
|
+
output += "usemtl " + mesh.material.name + "\n";
|
|
5025
|
+
}
|
|
5026
|
+
if (vertices !== void 0) {
|
|
5027
|
+
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
|
|
5028
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5029
|
+
vertex.applyMatrix4(mesh.matrixWorld);
|
|
5030
|
+
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
if (uvs !== void 0) {
|
|
5034
|
+
for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
|
|
5035
|
+
uv.fromBufferAttribute(uvs, i);
|
|
5036
|
+
output += "vt " + uv.x + " " + uv.y + "\n";
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
if (normals !== void 0) {
|
|
5040
|
+
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
|
|
5041
|
+
for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
|
|
5042
|
+
normal.fromBufferAttribute(normals, i);
|
|
5043
|
+
normal.applyMatrix3(normalMatrixWorld).normalize();
|
|
5044
|
+
output += "vn " + normal.x + " " + normal.y + " " + normal.z + "\n";
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
5047
|
+
if (indices !== null) {
|
|
5048
|
+
for (let i = 0, l = indices.count; i < l; i += 3) {
|
|
5049
|
+
for (let m = 0; m < 3; m++) {
|
|
5050
|
+
const j = indices.getX(i + m) + 1;
|
|
5051
|
+
face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
|
|
5052
|
+
}
|
|
5053
|
+
output += "f " + face.join(" ") + "\n";
|
|
5054
|
+
}
|
|
5055
|
+
} else {
|
|
5056
|
+
for (let i = 0, l = vertices.count; i < l; i += 3) {
|
|
5057
|
+
for (let m = 0; m < 3; m++) {
|
|
5058
|
+
const j = i + m + 1;
|
|
5059
|
+
face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
|
|
5060
|
+
}
|
|
5061
|
+
output += "f " + face.join(" ") + "\n";
|
|
5062
|
+
}
|
|
5063
|
+
}
|
|
5064
|
+
indexVertex += nbVertex;
|
|
5065
|
+
indexVertexUvs += nbVertexUvs;
|
|
5066
|
+
indexNormals += nbNormals;
|
|
5067
|
+
}
|
|
5068
|
+
function parseLine(line) {
|
|
5069
|
+
let nbVertex = 0;
|
|
5070
|
+
const geometry = line.geometry;
|
|
5071
|
+
const type = line.type;
|
|
5072
|
+
const vertices = geometry.getAttribute("position");
|
|
5073
|
+
output += "o " + line.name + "\n";
|
|
5074
|
+
if (vertices !== void 0) {
|
|
5075
|
+
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
|
|
5076
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5077
|
+
vertex.applyMatrix4(line.matrixWorld);
|
|
5078
|
+
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
|
|
5079
|
+
}
|
|
5080
|
+
}
|
|
5081
|
+
if (type === "Line") {
|
|
5082
|
+
output += "l ";
|
|
5083
|
+
for (let j = 1, l = vertices.count; j <= l; j++) {
|
|
5084
|
+
output += indexVertex + j + " ";
|
|
5085
|
+
}
|
|
5086
|
+
output += "\n";
|
|
5087
|
+
}
|
|
5088
|
+
if (type === "LineSegments") {
|
|
5089
|
+
for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
|
|
5090
|
+
output += "l " + (indexVertex + j) + " " + (indexVertex + k) + "\n";
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
indexVertex += nbVertex;
|
|
5094
|
+
}
|
|
5095
|
+
function parsePoints(points) {
|
|
5096
|
+
let nbVertex = 0;
|
|
5097
|
+
const geometry = points.geometry;
|
|
5098
|
+
const vertices = geometry.getAttribute("position");
|
|
5099
|
+
const colors = geometry.getAttribute("color");
|
|
5100
|
+
output += "o " + points.name + "\n";
|
|
5101
|
+
if (vertices !== void 0) {
|
|
5102
|
+
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
|
|
5103
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5104
|
+
vertex.applyMatrix4(points.matrixWorld);
|
|
5105
|
+
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
5106
|
+
if (colors !== void 0) {
|
|
5107
|
+
color.fromBufferAttribute(colors, i).convertLinearToSRGB();
|
|
5108
|
+
output += " " + color.r + " " + color.g + " " + color.b;
|
|
5109
|
+
}
|
|
5110
|
+
output += "\n";
|
|
5111
|
+
}
|
|
5112
|
+
output += "p ";
|
|
5113
|
+
for (let j = 1, l = vertices.count; j <= l; j++) {
|
|
5114
|
+
output += indexVertex + j + " ";
|
|
5115
|
+
}
|
|
5116
|
+
output += "\n";
|
|
5117
|
+
}
|
|
5118
|
+
indexVertex += nbVertex;
|
|
5119
|
+
}
|
|
5120
|
+
object.traverse(function(child) {
|
|
5121
|
+
if (child.isMesh === true) {
|
|
5122
|
+
parseMesh(child);
|
|
5123
|
+
}
|
|
5124
|
+
if (child.isLine === true) {
|
|
5125
|
+
parseLine(child);
|
|
5126
|
+
}
|
|
5127
|
+
if (child.isPoints === true) {
|
|
5128
|
+
parsePoints(child);
|
|
5129
|
+
}
|
|
5130
|
+
});
|
|
5131
|
+
return output;
|
|
5132
|
+
}
|
|
5133
|
+
};
|
|
5134
|
+
|
|
5135
|
+
// ../../node_modules/three/examples/jsm/exporters/PLYExporter.js
|
|
5136
|
+
import {
|
|
5137
|
+
Matrix3 as Matrix32,
|
|
5138
|
+
Vector3 as Vector37,
|
|
5139
|
+
Color as Color4
|
|
5140
|
+
} from "three";
|
|
5141
|
+
var PLYExporter = class {
|
|
5142
|
+
parse(object, onDone, options = {}) {
|
|
5143
|
+
function traverseMeshes(cb) {
|
|
5144
|
+
object.traverse(function(child) {
|
|
5145
|
+
if (child.isMesh === true || child.isPoints) {
|
|
5146
|
+
const mesh = child;
|
|
5147
|
+
const geometry = mesh.geometry;
|
|
5148
|
+
if (geometry.hasAttribute("position") === true) {
|
|
5149
|
+
cb(mesh, geometry);
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
});
|
|
5153
|
+
}
|
|
5154
|
+
const defaultOptions = {
|
|
5155
|
+
binary: false,
|
|
5156
|
+
excludeAttributes: [],
|
|
5157
|
+
// normal, uv, color, index
|
|
5158
|
+
littleEndian: false
|
|
5159
|
+
};
|
|
5160
|
+
options = Object.assign(defaultOptions, options);
|
|
5161
|
+
const excludeAttributes = options.excludeAttributes;
|
|
5162
|
+
let includeIndices = true;
|
|
5163
|
+
let includeNormals = false;
|
|
5164
|
+
let includeColors = false;
|
|
5165
|
+
let includeUVs = false;
|
|
5166
|
+
let vertexCount = 0;
|
|
5167
|
+
let faceCount = 0;
|
|
5168
|
+
object.traverse(function(child) {
|
|
5169
|
+
if (child.isMesh === true) {
|
|
5170
|
+
const mesh = child;
|
|
5171
|
+
const geometry = mesh.geometry;
|
|
5172
|
+
const vertices = geometry.getAttribute("position");
|
|
5173
|
+
const normals = geometry.getAttribute("normal");
|
|
5174
|
+
const uvs = geometry.getAttribute("uv");
|
|
5175
|
+
const colors = geometry.getAttribute("color");
|
|
5176
|
+
const indices = geometry.getIndex();
|
|
5177
|
+
if (vertices === void 0) {
|
|
5178
|
+
return;
|
|
5179
|
+
}
|
|
5180
|
+
vertexCount += vertices.count;
|
|
5181
|
+
faceCount += indices ? indices.count / 3 : vertices.count / 3;
|
|
5182
|
+
if (normals !== void 0) includeNormals = true;
|
|
5183
|
+
if (uvs !== void 0) includeUVs = true;
|
|
5184
|
+
if (colors !== void 0) includeColors = true;
|
|
5185
|
+
} else if (child.isPoints) {
|
|
5186
|
+
const mesh = child;
|
|
5187
|
+
const geometry = mesh.geometry;
|
|
5188
|
+
const vertices = geometry.getAttribute("position");
|
|
5189
|
+
const normals = geometry.getAttribute("normal");
|
|
5190
|
+
const colors = geometry.getAttribute("color");
|
|
5191
|
+
vertexCount += vertices.count;
|
|
5192
|
+
if (normals !== void 0) includeNormals = true;
|
|
5193
|
+
if (colors !== void 0) includeColors = true;
|
|
5194
|
+
includeIndices = false;
|
|
5195
|
+
}
|
|
5196
|
+
});
|
|
5197
|
+
const tempColor = new Color4();
|
|
5198
|
+
includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
|
|
5199
|
+
includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
|
|
5200
|
+
includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
|
|
5201
|
+
includeUVs = includeUVs && excludeAttributes.indexOf("uv") === -1;
|
|
5202
|
+
if (includeIndices && faceCount !== Math.floor(faceCount)) {
|
|
5203
|
+
console.error(
|
|
5204
|
+
"PLYExporter: Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3."
|
|
5205
|
+
);
|
|
5206
|
+
return null;
|
|
5207
|
+
}
|
|
5208
|
+
const indexByteCount = 4;
|
|
5209
|
+
let header = `ply
|
|
5210
|
+
format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
|
|
5211
|
+
element vertex ${vertexCount}
|
|
5212
|
+
property float x
|
|
5213
|
+
property float y
|
|
5214
|
+
property float z
|
|
5215
|
+
`;
|
|
5216
|
+
if (includeNormals === true) {
|
|
5217
|
+
header += "property float nx\nproperty float ny\nproperty float nz\n";
|
|
5218
|
+
}
|
|
5219
|
+
if (includeUVs === true) {
|
|
5220
|
+
header += "property float s\nproperty float t\n";
|
|
5221
|
+
}
|
|
5222
|
+
if (includeColors === true) {
|
|
5223
|
+
header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
|
|
5224
|
+
}
|
|
5225
|
+
if (includeIndices === true) {
|
|
5226
|
+
header += `element face ${faceCount}
|
|
5227
|
+
property list uchar int vertex_index
|
|
5228
|
+
`;
|
|
5229
|
+
}
|
|
5230
|
+
header += "end_header\n";
|
|
5231
|
+
const vertex = new Vector37();
|
|
5232
|
+
const normalMatrixWorld = new Matrix32();
|
|
5233
|
+
let result = null;
|
|
5234
|
+
if (options.binary === true) {
|
|
5235
|
+
const headerBin = new TextEncoder().encode(header);
|
|
5236
|
+
const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
|
|
5237
|
+
const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
|
|
5238
|
+
const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
|
|
5239
|
+
new Uint8Array(output.buffer).set(headerBin, 0);
|
|
5240
|
+
let vOffset = headerBin.length;
|
|
5241
|
+
let fOffset = headerBin.length + vertexListLength;
|
|
5242
|
+
let writtenVertices = 0;
|
|
5243
|
+
traverseMeshes(function(mesh, geometry) {
|
|
5244
|
+
const vertices = geometry.getAttribute("position");
|
|
5245
|
+
const normals = geometry.getAttribute("normal");
|
|
5246
|
+
const uvs = geometry.getAttribute("uv");
|
|
5247
|
+
const colors = geometry.getAttribute("color");
|
|
5248
|
+
const indices = geometry.getIndex();
|
|
5249
|
+
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
|
|
5250
|
+
for (let i = 0, l = vertices.count; i < l; i++) {
|
|
5251
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5252
|
+
vertex.applyMatrix4(mesh.matrixWorld);
|
|
5253
|
+
output.setFloat32(vOffset, vertex.x, options.littleEndian);
|
|
5254
|
+
vOffset += 4;
|
|
5255
|
+
output.setFloat32(vOffset, vertex.y, options.littleEndian);
|
|
5256
|
+
vOffset += 4;
|
|
5257
|
+
output.setFloat32(vOffset, vertex.z, options.littleEndian);
|
|
5258
|
+
vOffset += 4;
|
|
5259
|
+
if (includeNormals === true) {
|
|
5260
|
+
if (normals != null) {
|
|
5261
|
+
vertex.fromBufferAttribute(normals, i);
|
|
5262
|
+
vertex.applyMatrix3(normalMatrixWorld).normalize();
|
|
5263
|
+
output.setFloat32(vOffset, vertex.x, options.littleEndian);
|
|
5264
|
+
vOffset += 4;
|
|
5265
|
+
output.setFloat32(vOffset, vertex.y, options.littleEndian);
|
|
5266
|
+
vOffset += 4;
|
|
5267
|
+
output.setFloat32(vOffset, vertex.z, options.littleEndian);
|
|
5268
|
+
vOffset += 4;
|
|
5269
|
+
} else {
|
|
5270
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5271
|
+
vOffset += 4;
|
|
5272
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5273
|
+
vOffset += 4;
|
|
5274
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5275
|
+
vOffset += 4;
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5278
|
+
if (includeUVs === true) {
|
|
5279
|
+
if (uvs != null) {
|
|
5280
|
+
output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
|
|
5281
|
+
vOffset += 4;
|
|
5282
|
+
output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
|
|
5283
|
+
vOffset += 4;
|
|
5284
|
+
} else {
|
|
5285
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5286
|
+
vOffset += 4;
|
|
5287
|
+
output.setFloat32(vOffset, 0, options.littleEndian);
|
|
5288
|
+
vOffset += 4;
|
|
5289
|
+
}
|
|
5290
|
+
}
|
|
5291
|
+
if (includeColors === true) {
|
|
5292
|
+
if (colors != null) {
|
|
5293
|
+
tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
|
|
5294
|
+
output.setUint8(vOffset, Math.floor(tempColor.r * 255));
|
|
5295
|
+
vOffset += 1;
|
|
5296
|
+
output.setUint8(vOffset, Math.floor(tempColor.g * 255));
|
|
5297
|
+
vOffset += 1;
|
|
5298
|
+
output.setUint8(vOffset, Math.floor(tempColor.b * 255));
|
|
5299
|
+
vOffset += 1;
|
|
5300
|
+
} else {
|
|
5301
|
+
output.setUint8(vOffset, 255);
|
|
5302
|
+
vOffset += 1;
|
|
5303
|
+
output.setUint8(vOffset, 255);
|
|
5304
|
+
vOffset += 1;
|
|
5305
|
+
output.setUint8(vOffset, 255);
|
|
5306
|
+
vOffset += 1;
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
if (includeIndices === true) {
|
|
5311
|
+
if (indices !== null) {
|
|
5312
|
+
for (let i = 0, l = indices.count; i < l; i += 3) {
|
|
5313
|
+
output.setUint8(fOffset, 3);
|
|
5314
|
+
fOffset += 1;
|
|
5315
|
+
output.setUint32(fOffset, indices.getX(i + 0) + writtenVertices, options.littleEndian);
|
|
5316
|
+
fOffset += indexByteCount;
|
|
5317
|
+
output.setUint32(fOffset, indices.getX(i + 1) + writtenVertices, options.littleEndian);
|
|
5318
|
+
fOffset += indexByteCount;
|
|
5319
|
+
output.setUint32(fOffset, indices.getX(i + 2) + writtenVertices, options.littleEndian);
|
|
5320
|
+
fOffset += indexByteCount;
|
|
5321
|
+
}
|
|
5322
|
+
} else {
|
|
5323
|
+
for (let i = 0, l = vertices.count; i < l; i += 3) {
|
|
5324
|
+
output.setUint8(fOffset, 3);
|
|
5325
|
+
fOffset += 1;
|
|
5326
|
+
output.setUint32(fOffset, writtenVertices + i, options.littleEndian);
|
|
5327
|
+
fOffset += indexByteCount;
|
|
5328
|
+
output.setUint32(fOffset, writtenVertices + i + 1, options.littleEndian);
|
|
5329
|
+
fOffset += indexByteCount;
|
|
5330
|
+
output.setUint32(fOffset, writtenVertices + i + 2, options.littleEndian);
|
|
5331
|
+
fOffset += indexByteCount;
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5334
|
+
}
|
|
5335
|
+
writtenVertices += vertices.count;
|
|
5336
|
+
});
|
|
5337
|
+
result = output.buffer;
|
|
5338
|
+
} else {
|
|
5339
|
+
let writtenVertices = 0;
|
|
5340
|
+
let vertexList = "";
|
|
5341
|
+
let faceList = "";
|
|
5342
|
+
traverseMeshes(function(mesh, geometry) {
|
|
5343
|
+
const vertices = geometry.getAttribute("position");
|
|
5344
|
+
const normals = geometry.getAttribute("normal");
|
|
5345
|
+
const uvs = geometry.getAttribute("uv");
|
|
5346
|
+
const colors = geometry.getAttribute("color");
|
|
5347
|
+
const indices = geometry.getIndex();
|
|
5348
|
+
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
|
|
5349
|
+
for (let i = 0, l = vertices.count; i < l; i++) {
|
|
5350
|
+
vertex.fromBufferAttribute(vertices, i);
|
|
5351
|
+
vertex.applyMatrix4(mesh.matrixWorld);
|
|
5352
|
+
let line = vertex.x + " " + vertex.y + " " + vertex.z;
|
|
5353
|
+
if (includeNormals === true) {
|
|
5354
|
+
if (normals != null) {
|
|
5355
|
+
vertex.fromBufferAttribute(normals, i);
|
|
5356
|
+
vertex.applyMatrix3(normalMatrixWorld).normalize();
|
|
5357
|
+
line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
5358
|
+
} else {
|
|
5359
|
+
line += " 0 0 0";
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
if (includeUVs === true) {
|
|
5363
|
+
if (uvs != null) {
|
|
5364
|
+
line += " " + uvs.getX(i) + " " + uvs.getY(i);
|
|
5365
|
+
} else {
|
|
5366
|
+
line += " 0 0";
|
|
5367
|
+
}
|
|
5368
|
+
}
|
|
5369
|
+
if (includeColors === true) {
|
|
5370
|
+
if (colors != null) {
|
|
5371
|
+
tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
|
|
5372
|
+
line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
|
|
5373
|
+
} else {
|
|
5374
|
+
line += " 255 255 255";
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
vertexList += line + "\n";
|
|
5378
|
+
}
|
|
5379
|
+
if (includeIndices === true) {
|
|
5380
|
+
if (indices !== null) {
|
|
5381
|
+
for (let i = 0, l = indices.count; i < l; i += 3) {
|
|
5382
|
+
faceList += `3 ${indices.getX(i + 0) + writtenVertices}`;
|
|
5383
|
+
faceList += ` ${indices.getX(i + 1) + writtenVertices}`;
|
|
5384
|
+
faceList += ` ${indices.getX(i + 2) + writtenVertices}
|
|
5385
|
+
`;
|
|
5386
|
+
}
|
|
5387
|
+
} else {
|
|
5388
|
+
for (let i = 0, l = vertices.count; i < l; i += 3) {
|
|
5389
|
+
faceList += `3 ${writtenVertices + i} ${writtenVertices + i + 1} ${writtenVertices + i + 2}
|
|
5390
|
+
`;
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
faceCount += indices ? indices.count / 3 : vertices.count / 3;
|
|
5394
|
+
}
|
|
5395
|
+
writtenVertices += vertices.count;
|
|
5396
|
+
});
|
|
5397
|
+
result = `${header}${vertexList}${includeIndices ? `${faceList}
|
|
5398
|
+
` : "\n"}`;
|
|
5399
|
+
}
|
|
5400
|
+
if (typeof onDone === "function") requestAnimationFrame(() => onDone(result));
|
|
5401
|
+
return result;
|
|
5402
|
+
}
|
|
5403
|
+
};
|
|
5404
|
+
|
|
5405
|
+
// ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
|
|
5406
|
+
import {
|
|
5407
|
+
BufferAttribute as BufferAttribute3,
|
|
5408
|
+
ClampToEdgeWrapping,
|
|
5409
|
+
Color as Color5,
|
|
5410
|
+
DoubleSide as DoubleSide2,
|
|
5411
|
+
InterpolateDiscrete,
|
|
5412
|
+
InterpolateLinear,
|
|
5413
|
+
NoColorSpace,
|
|
5414
|
+
LinearFilter,
|
|
5415
|
+
LinearMipmapLinearFilter,
|
|
5416
|
+
LinearMipmapNearestFilter,
|
|
5417
|
+
MathUtils as MathUtils2,
|
|
5418
|
+
Matrix4 as Matrix44,
|
|
5419
|
+
MirroredRepeatWrapping,
|
|
5420
|
+
NearestFilter as NearestFilter2,
|
|
5421
|
+
NearestMipmapLinearFilter,
|
|
5422
|
+
NearestMipmapNearestFilter,
|
|
5423
|
+
PropertyBinding,
|
|
5424
|
+
RGBAFormat as RGBAFormat2,
|
|
5425
|
+
RepeatWrapping,
|
|
5426
|
+
Scene as Scene3,
|
|
5427
|
+
Source,
|
|
5428
|
+
SRGBColorSpace as SRGBColorSpace4,
|
|
5429
|
+
CompressedTexture,
|
|
5430
|
+
Vector3 as Vector38,
|
|
5431
|
+
Quaternion as Quaternion4
|
|
5432
|
+
} from "three";
|
|
5433
|
+
|
|
5434
|
+
// ../../node_modules/three/examples/jsm/utils/TextureUtils.js
|
|
5435
|
+
import {
|
|
5436
|
+
PlaneGeometry,
|
|
5437
|
+
ShaderMaterial as ShaderMaterial2,
|
|
5438
|
+
Uniform,
|
|
5439
|
+
Mesh as Mesh4,
|
|
5440
|
+
PerspectiveCamera,
|
|
5441
|
+
Scene as Scene2,
|
|
5442
|
+
WebGLRenderer,
|
|
5443
|
+
Texture as Texture3,
|
|
5444
|
+
SRGBColorSpace as SRGBColorSpace3
|
|
5445
|
+
} from "three";
|
|
5446
|
+
var _renderer;
|
|
5447
|
+
var fullscreenQuadGeometry;
|
|
5448
|
+
var fullscreenQuadMaterial;
|
|
5449
|
+
var fullscreenQuad;
|
|
5450
|
+
function decompress(texture, maxTextureSize = Infinity, renderer = null) {
|
|
5451
|
+
if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
|
|
5452
|
+
if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
|
|
5453
|
+
uniforms: { blitTexture: new Uniform(texture) },
|
|
5454
|
+
vertexShader: `
|
|
5455
|
+
varying vec2 vUv;
|
|
5456
|
+
void main(){
|
|
5457
|
+
vUv = uv;
|
|
5458
|
+
gl_Position = vec4(position.xy * 1.0,0.,.999999);
|
|
5459
|
+
}`,
|
|
5460
|
+
fragmentShader: `
|
|
5461
|
+
uniform sampler2D blitTexture;
|
|
5462
|
+
varying vec2 vUv;
|
|
5463
|
+
|
|
5464
|
+
void main(){
|
|
5465
|
+
gl_FragColor = vec4(vUv.xy, 0, 1);
|
|
5466
|
+
|
|
5467
|
+
#ifdef IS_SRGB
|
|
5468
|
+
gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
|
|
5469
|
+
#else
|
|
5470
|
+
gl_FragColor = texture2D( blitTexture, vUv);
|
|
5471
|
+
#endif
|
|
5472
|
+
}`
|
|
5473
|
+
});
|
|
5474
|
+
fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
|
|
5475
|
+
fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
|
|
5476
|
+
fullscreenQuadMaterial.needsUpdate = true;
|
|
5477
|
+
if (!fullscreenQuad) {
|
|
5478
|
+
fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
|
|
5479
|
+
fullscreenQuad.frustrumCulled = false;
|
|
5480
|
+
}
|
|
5481
|
+
const _camera = new PerspectiveCamera();
|
|
5482
|
+
const _scene = new Scene2();
|
|
5483
|
+
_scene.add(fullscreenQuad);
|
|
5484
|
+
if (!renderer) {
|
|
5485
|
+
renderer = _renderer = new WebGLRenderer({ antialias: false });
|
|
5486
|
+
}
|
|
5487
|
+
renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
|
|
5488
|
+
renderer.clear();
|
|
5489
|
+
renderer.render(_scene, _camera);
|
|
5490
|
+
const readableTexture = new Texture3(renderer.domElement);
|
|
5491
|
+
readableTexture.minFilter = texture.minFilter;
|
|
5492
|
+
readableTexture.magFilter = texture.magFilter;
|
|
5493
|
+
readableTexture.wrapS = texture.wrapS;
|
|
5494
|
+
readableTexture.wrapT = texture.wrapT;
|
|
5495
|
+
readableTexture.name = texture.name;
|
|
5496
|
+
if (_renderer) {
|
|
5497
|
+
_renderer.dispose();
|
|
5498
|
+
_renderer = null;
|
|
5499
|
+
}
|
|
5500
|
+
return readableTexture;
|
|
5501
|
+
}
|
|
5502
|
+
|
|
5503
|
+
// ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
|
|
5504
|
+
var KHR_mesh_quantization_ExtraAttrTypes = {
|
|
5505
|
+
POSITION: [
|
|
5506
|
+
"byte",
|
|
5507
|
+
"byte normalized",
|
|
5508
|
+
"unsigned byte",
|
|
5509
|
+
"unsigned byte normalized",
|
|
5510
|
+
"short",
|
|
5511
|
+
"short normalized",
|
|
5512
|
+
"unsigned short",
|
|
5513
|
+
"unsigned short normalized"
|
|
5514
|
+
],
|
|
5515
|
+
NORMAL: [
|
|
5516
|
+
"byte normalized",
|
|
5517
|
+
"short normalized"
|
|
5518
|
+
],
|
|
5519
|
+
TANGENT: [
|
|
5520
|
+
"byte normalized",
|
|
5521
|
+
"short normalized"
|
|
5522
|
+
],
|
|
5523
|
+
TEXCOORD: [
|
|
5524
|
+
"byte",
|
|
5525
|
+
"byte normalized",
|
|
5526
|
+
"unsigned byte",
|
|
5527
|
+
"short",
|
|
5528
|
+
"short normalized",
|
|
5529
|
+
"unsigned short"
|
|
5530
|
+
]
|
|
5531
|
+
};
|
|
5532
|
+
var GLTFExporter = class {
|
|
5533
|
+
constructor() {
|
|
5534
|
+
this.pluginCallbacks = [];
|
|
5535
|
+
this.register(function(writer) {
|
|
5536
|
+
return new GLTFLightExtension(writer);
|
|
5537
|
+
});
|
|
5538
|
+
this.register(function(writer) {
|
|
5539
|
+
return new GLTFMaterialsUnlitExtension(writer);
|
|
5540
|
+
});
|
|
5541
|
+
this.register(function(writer) {
|
|
5542
|
+
return new GLTFMaterialsTransmissionExtension(writer);
|
|
5543
|
+
});
|
|
5544
|
+
this.register(function(writer) {
|
|
5545
|
+
return new GLTFMaterialsVolumeExtension(writer);
|
|
5546
|
+
});
|
|
5547
|
+
this.register(function(writer) {
|
|
5548
|
+
return new GLTFMaterialsIorExtension(writer);
|
|
5549
|
+
});
|
|
5550
|
+
this.register(function(writer) {
|
|
5551
|
+
return new GLTFMaterialsSpecularExtension(writer);
|
|
5552
|
+
});
|
|
5553
|
+
this.register(function(writer) {
|
|
5554
|
+
return new GLTFMaterialsClearcoatExtension(writer);
|
|
5555
|
+
});
|
|
5556
|
+
this.register(function(writer) {
|
|
5557
|
+
return new GLTFMaterialsIridescenceExtension(writer);
|
|
5558
|
+
});
|
|
5559
|
+
this.register(function(writer) {
|
|
5560
|
+
return new GLTFMaterialsSheenExtension(writer);
|
|
5561
|
+
});
|
|
5562
|
+
this.register(function(writer) {
|
|
5563
|
+
return new GLTFMaterialsAnisotropyExtension(writer);
|
|
5564
|
+
});
|
|
5565
|
+
this.register(function(writer) {
|
|
5566
|
+
return new GLTFMaterialsEmissiveStrengthExtension(writer);
|
|
5567
|
+
});
|
|
5568
|
+
this.register(function(writer) {
|
|
5569
|
+
return new GLTFMeshGpuInstancing(writer);
|
|
5570
|
+
});
|
|
5571
|
+
}
|
|
5572
|
+
register(callback) {
|
|
5573
|
+
if (this.pluginCallbacks.indexOf(callback) === -1) {
|
|
5574
|
+
this.pluginCallbacks.push(callback);
|
|
5575
|
+
}
|
|
5576
|
+
return this;
|
|
5577
|
+
}
|
|
5578
|
+
unregister(callback) {
|
|
5579
|
+
if (this.pluginCallbacks.indexOf(callback) !== -1) {
|
|
5580
|
+
this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
|
|
5581
|
+
}
|
|
5582
|
+
return this;
|
|
5583
|
+
}
|
|
5584
|
+
/**
|
|
5585
|
+
* Parse scenes and generate GLTF output
|
|
5586
|
+
* @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
|
|
5587
|
+
* @param {Function} onDone Callback on completed
|
|
5588
|
+
* @param {Function} onError Callback on errors
|
|
5589
|
+
* @param {Object} options options
|
|
5590
|
+
*/
|
|
5591
|
+
parse(input, onDone, onError, options) {
|
|
5592
|
+
const writer = new GLTFWriter();
|
|
5593
|
+
const plugins = [];
|
|
5594
|
+
for (let i = 0, il = this.pluginCallbacks.length; i < il; i++) {
|
|
5595
|
+
plugins.push(this.pluginCallbacks[i](writer));
|
|
5596
|
+
}
|
|
5597
|
+
writer.setPlugins(plugins);
|
|
5598
|
+
writer.write(input, onDone, options).catch(onError);
|
|
5599
|
+
}
|
|
5600
|
+
parseAsync(input, options) {
|
|
5601
|
+
const scope = this;
|
|
5602
|
+
return new Promise(function(resolve, reject) {
|
|
5603
|
+
scope.parse(input, resolve, reject, options);
|
|
5604
|
+
});
|
|
5605
|
+
}
|
|
5606
|
+
};
|
|
5607
|
+
var WEBGL_CONSTANTS = {
|
|
5608
|
+
POINTS: 0,
|
|
5609
|
+
LINES: 1,
|
|
5610
|
+
LINE_LOOP: 2,
|
|
5611
|
+
LINE_STRIP: 3,
|
|
5612
|
+
TRIANGLES: 4,
|
|
5613
|
+
TRIANGLE_STRIP: 5,
|
|
5614
|
+
TRIANGLE_FAN: 6,
|
|
5615
|
+
BYTE: 5120,
|
|
5616
|
+
UNSIGNED_BYTE: 5121,
|
|
5617
|
+
SHORT: 5122,
|
|
5618
|
+
UNSIGNED_SHORT: 5123,
|
|
5619
|
+
INT: 5124,
|
|
5620
|
+
UNSIGNED_INT: 5125,
|
|
5621
|
+
FLOAT: 5126,
|
|
5622
|
+
ARRAY_BUFFER: 34962,
|
|
5623
|
+
ELEMENT_ARRAY_BUFFER: 34963,
|
|
5624
|
+
NEAREST: 9728,
|
|
5625
|
+
LINEAR: 9729,
|
|
5626
|
+
NEAREST_MIPMAP_NEAREST: 9984,
|
|
5627
|
+
LINEAR_MIPMAP_NEAREST: 9985,
|
|
5628
|
+
NEAREST_MIPMAP_LINEAR: 9986,
|
|
5629
|
+
LINEAR_MIPMAP_LINEAR: 9987,
|
|
5630
|
+
CLAMP_TO_EDGE: 33071,
|
|
5631
|
+
MIRRORED_REPEAT: 33648,
|
|
5632
|
+
REPEAT: 10497
|
|
5633
|
+
};
|
|
5634
|
+
var KHR_MESH_QUANTIZATION = "KHR_mesh_quantization";
|
|
5635
|
+
var THREE_TO_WEBGL = {};
|
|
5636
|
+
THREE_TO_WEBGL[NearestFilter2] = WEBGL_CONSTANTS.NEAREST;
|
|
5637
|
+
THREE_TO_WEBGL[NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
|
|
5638
|
+
THREE_TO_WEBGL[NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
|
|
5639
|
+
THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
|
|
5640
|
+
THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
|
|
5641
|
+
THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
|
|
5642
|
+
THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
|
|
5643
|
+
THREE_TO_WEBGL[RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
|
|
5644
|
+
THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
|
|
5645
|
+
var PATH_PROPERTIES = {
|
|
5646
|
+
scale: "scale",
|
|
5647
|
+
position: "translation",
|
|
5648
|
+
quaternion: "rotation",
|
|
5649
|
+
morphTargetInfluences: "weights"
|
|
5650
|
+
};
|
|
5651
|
+
var DEFAULT_SPECULAR_COLOR = new Color5();
|
|
5652
|
+
var GLB_HEADER_BYTES = 12;
|
|
5653
|
+
var GLB_HEADER_MAGIC = 1179937895;
|
|
5654
|
+
var GLB_VERSION = 2;
|
|
5655
|
+
var GLB_CHUNK_PREFIX_BYTES = 8;
|
|
5656
|
+
var GLB_CHUNK_TYPE_JSON = 1313821514;
|
|
5657
|
+
var GLB_CHUNK_TYPE_BIN = 5130562;
|
|
5658
|
+
function equalArray(array1, array2) {
|
|
5659
|
+
return array1.length === array2.length && array1.every(function(element, index) {
|
|
5660
|
+
return element === array2[index];
|
|
5661
|
+
});
|
|
5662
|
+
}
|
|
5663
|
+
function stringToArrayBuffer(text) {
|
|
5664
|
+
return new TextEncoder().encode(text).buffer;
|
|
5665
|
+
}
|
|
5666
|
+
function isIdentityMatrix(matrix) {
|
|
5667
|
+
return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
5668
|
+
}
|
|
5669
|
+
function getMinMax(attribute, start, count) {
|
|
5670
|
+
const output = {
|
|
5671
|
+
min: new Array(attribute.itemSize).fill(Number.POSITIVE_INFINITY),
|
|
5672
|
+
max: new Array(attribute.itemSize).fill(Number.NEGATIVE_INFINITY)
|
|
5673
|
+
};
|
|
5674
|
+
for (let i = start; i < start + count; i++) {
|
|
5675
|
+
for (let a = 0; a < attribute.itemSize; a++) {
|
|
5676
|
+
let value;
|
|
5677
|
+
if (attribute.itemSize > 4) {
|
|
5678
|
+
value = attribute.array[i * attribute.itemSize + a];
|
|
5679
|
+
} else {
|
|
5680
|
+
if (a === 0) value = attribute.getX(i);
|
|
5681
|
+
else if (a === 1) value = attribute.getY(i);
|
|
5682
|
+
else if (a === 2) value = attribute.getZ(i);
|
|
5683
|
+
else if (a === 3) value = attribute.getW(i);
|
|
5684
|
+
if (attribute.normalized === true) {
|
|
5685
|
+
value = MathUtils2.normalize(value, attribute.array);
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
output.min[a] = Math.min(output.min[a], value);
|
|
5689
|
+
output.max[a] = Math.max(output.max[a], value);
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
return output;
|
|
5693
|
+
}
|
|
5694
|
+
function getPaddedBufferSize(bufferSize) {
|
|
5695
|
+
return Math.ceil(bufferSize / 4) * 4;
|
|
5696
|
+
}
|
|
5697
|
+
function getPaddedArrayBuffer(arrayBuffer, paddingByte = 0) {
|
|
5698
|
+
const paddedLength = getPaddedBufferSize(arrayBuffer.byteLength);
|
|
5699
|
+
if (paddedLength !== arrayBuffer.byteLength) {
|
|
5700
|
+
const array = new Uint8Array(paddedLength);
|
|
5701
|
+
array.set(new Uint8Array(arrayBuffer));
|
|
5702
|
+
if (paddingByte !== 0) {
|
|
5703
|
+
for (let i = arrayBuffer.byteLength; i < paddedLength; i++) {
|
|
5704
|
+
array[i] = paddingByte;
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5707
|
+
return array.buffer;
|
|
5708
|
+
}
|
|
5709
|
+
return arrayBuffer;
|
|
5710
|
+
}
|
|
5711
|
+
function getCanvas() {
|
|
5712
|
+
if (typeof document === "undefined" && typeof OffscreenCanvas !== "undefined") {
|
|
5713
|
+
return new OffscreenCanvas(1, 1);
|
|
5714
|
+
}
|
|
5715
|
+
return document.createElement("canvas");
|
|
5716
|
+
}
|
|
5717
|
+
function getToBlobPromise(canvas, mimeType) {
|
|
5718
|
+
if (canvas.toBlob !== void 0) {
|
|
5719
|
+
return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
|
|
5720
|
+
}
|
|
5721
|
+
let quality;
|
|
5722
|
+
if (mimeType === "image/jpeg") {
|
|
5723
|
+
quality = 0.92;
|
|
5724
|
+
} else if (mimeType === "image/webp") {
|
|
5725
|
+
quality = 0.8;
|
|
5726
|
+
}
|
|
5727
|
+
return canvas.convertToBlob({
|
|
5728
|
+
type: mimeType,
|
|
5729
|
+
quality
|
|
5730
|
+
});
|
|
5731
|
+
}
|
|
5732
|
+
var GLTFWriter = class {
|
|
5733
|
+
constructor() {
|
|
5734
|
+
this.plugins = [];
|
|
5735
|
+
this.options = {};
|
|
5736
|
+
this.pending = [];
|
|
5737
|
+
this.buffers = [];
|
|
5738
|
+
this.byteOffset = 0;
|
|
5739
|
+
this.buffers = [];
|
|
5740
|
+
this.nodeMap = /* @__PURE__ */ new Map();
|
|
5741
|
+
this.skins = [];
|
|
5742
|
+
this.extensionsUsed = {};
|
|
5743
|
+
this.extensionsRequired = {};
|
|
5744
|
+
this.uids = /* @__PURE__ */ new Map();
|
|
5745
|
+
this.uid = 0;
|
|
5746
|
+
this.json = {
|
|
5747
|
+
asset: {
|
|
5748
|
+
version: "2.0",
|
|
5749
|
+
generator: "THREE.GLTFExporter"
|
|
5750
|
+
}
|
|
5751
|
+
};
|
|
5752
|
+
this.cache = {
|
|
5753
|
+
meshes: /* @__PURE__ */ new Map(),
|
|
5754
|
+
attributes: /* @__PURE__ */ new Map(),
|
|
5755
|
+
attributesNormalized: /* @__PURE__ */ new Map(),
|
|
5756
|
+
materials: /* @__PURE__ */ new Map(),
|
|
5757
|
+
textures: /* @__PURE__ */ new Map(),
|
|
5758
|
+
images: /* @__PURE__ */ new Map()
|
|
5759
|
+
};
|
|
5760
|
+
}
|
|
5761
|
+
setPlugins(plugins) {
|
|
5762
|
+
this.plugins = plugins;
|
|
5763
|
+
}
|
|
5764
|
+
/**
|
|
5765
|
+
* Parse scenes and generate GLTF output
|
|
5766
|
+
* @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
|
|
5767
|
+
* @param {Function} onDone Callback on completed
|
|
5768
|
+
* @param {Object} options options
|
|
5769
|
+
*/
|
|
5770
|
+
async write(input, onDone, options = {}) {
|
|
5771
|
+
this.options = Object.assign({
|
|
5772
|
+
// default options
|
|
5773
|
+
binary: false,
|
|
5774
|
+
trs: false,
|
|
5775
|
+
onlyVisible: true,
|
|
5776
|
+
maxTextureSize: Infinity,
|
|
5777
|
+
animations: [],
|
|
5778
|
+
includeCustomExtensions: false
|
|
5779
|
+
}, options);
|
|
5780
|
+
if (this.options.animations.length > 0) {
|
|
5781
|
+
this.options.trs = true;
|
|
5782
|
+
}
|
|
5783
|
+
this.processInput(input);
|
|
5784
|
+
await Promise.all(this.pending);
|
|
5785
|
+
const writer = this;
|
|
5786
|
+
const buffers = writer.buffers;
|
|
5787
|
+
const json = writer.json;
|
|
5788
|
+
options = writer.options;
|
|
5789
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
5790
|
+
const extensionsRequired = writer.extensionsRequired;
|
|
5791
|
+
const blob = new Blob(buffers, { type: "application/octet-stream" });
|
|
5792
|
+
const extensionsUsedList = Object.keys(extensionsUsed);
|
|
5793
|
+
const extensionsRequiredList = Object.keys(extensionsRequired);
|
|
5794
|
+
if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
|
|
5795
|
+
if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
|
|
5796
|
+
if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
|
|
5797
|
+
if (options.binary === true) {
|
|
5798
|
+
const reader = new FileReader();
|
|
5799
|
+
reader.readAsArrayBuffer(blob);
|
|
5800
|
+
reader.onloadend = function() {
|
|
5801
|
+
const binaryChunk = getPaddedArrayBuffer(reader.result);
|
|
5802
|
+
const binaryChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
|
|
5803
|
+
binaryChunkPrefix.setUint32(0, binaryChunk.byteLength, true);
|
|
5804
|
+
binaryChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_BIN, true);
|
|
5805
|
+
const jsonChunk = getPaddedArrayBuffer(stringToArrayBuffer(JSON.stringify(json)), 32);
|
|
5806
|
+
const jsonChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
|
|
5807
|
+
jsonChunkPrefix.setUint32(0, jsonChunk.byteLength, true);
|
|
5808
|
+
jsonChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_JSON, true);
|
|
5809
|
+
const header = new ArrayBuffer(GLB_HEADER_BYTES);
|
|
5810
|
+
const headerView = new DataView(header);
|
|
5811
|
+
headerView.setUint32(0, GLB_HEADER_MAGIC, true);
|
|
5812
|
+
headerView.setUint32(4, GLB_VERSION, true);
|
|
5813
|
+
const totalByteLength = GLB_HEADER_BYTES + jsonChunkPrefix.byteLength + jsonChunk.byteLength + binaryChunkPrefix.byteLength + binaryChunk.byteLength;
|
|
5814
|
+
headerView.setUint32(8, totalByteLength, true);
|
|
5815
|
+
const glbBlob = new Blob([
|
|
5816
|
+
header,
|
|
5817
|
+
jsonChunkPrefix,
|
|
5818
|
+
jsonChunk,
|
|
5819
|
+
binaryChunkPrefix,
|
|
5820
|
+
binaryChunk
|
|
5821
|
+
], { type: "application/octet-stream" });
|
|
5822
|
+
const glbReader = new FileReader();
|
|
5823
|
+
glbReader.readAsArrayBuffer(glbBlob);
|
|
5824
|
+
glbReader.onloadend = function() {
|
|
5825
|
+
onDone(glbReader.result);
|
|
5826
|
+
};
|
|
5827
|
+
};
|
|
5828
|
+
} else {
|
|
5829
|
+
if (json.buffers && json.buffers.length > 0) {
|
|
5830
|
+
const reader = new FileReader();
|
|
5831
|
+
reader.readAsDataURL(blob);
|
|
5832
|
+
reader.onloadend = function() {
|
|
5833
|
+
const base64data = reader.result;
|
|
5834
|
+
json.buffers[0].uri = base64data;
|
|
5835
|
+
onDone(json);
|
|
5836
|
+
};
|
|
5837
|
+
} else {
|
|
5838
|
+
onDone(json);
|
|
5839
|
+
}
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
5842
|
+
/**
|
|
5843
|
+
* Serializes a userData.
|
|
5844
|
+
*
|
|
5845
|
+
* @param {THREE.Object3D|THREE.Material} object
|
|
5846
|
+
* @param {Object} objectDef
|
|
5847
|
+
*/
|
|
5848
|
+
serializeUserData(object, objectDef) {
|
|
5849
|
+
if (Object.keys(object.userData).length === 0) return;
|
|
5850
|
+
const options = this.options;
|
|
5851
|
+
const extensionsUsed = this.extensionsUsed;
|
|
5852
|
+
try {
|
|
5853
|
+
const json = JSON.parse(JSON.stringify(object.userData));
|
|
5854
|
+
if (options.includeCustomExtensions && json.gltfExtensions) {
|
|
5855
|
+
if (objectDef.extensions === void 0) objectDef.extensions = {};
|
|
5856
|
+
for (const extensionName in json.gltfExtensions) {
|
|
5857
|
+
objectDef.extensions[extensionName] = json.gltfExtensions[extensionName];
|
|
5858
|
+
extensionsUsed[extensionName] = true;
|
|
5859
|
+
}
|
|
5860
|
+
delete json.gltfExtensions;
|
|
5861
|
+
}
|
|
5862
|
+
if (Object.keys(json).length > 0) objectDef.extras = json;
|
|
5863
|
+
} catch (error) {
|
|
5864
|
+
console.warn("THREE.GLTFExporter: userData of '" + object.name + "' won't be serialized because of JSON.stringify error - " + error.message);
|
|
5865
|
+
}
|
|
5866
|
+
}
|
|
5867
|
+
/**
|
|
5868
|
+
* Returns ids for buffer attributes.
|
|
5869
|
+
* @param {Object} object
|
|
5870
|
+
* @return {Integer}
|
|
5871
|
+
*/
|
|
5872
|
+
getUID(attribute, isRelativeCopy = false) {
|
|
5873
|
+
if (this.uids.has(attribute) === false) {
|
|
5874
|
+
const uids2 = /* @__PURE__ */ new Map();
|
|
5875
|
+
uids2.set(true, this.uid++);
|
|
5876
|
+
uids2.set(false, this.uid++);
|
|
5877
|
+
this.uids.set(attribute, uids2);
|
|
5878
|
+
}
|
|
5879
|
+
const uids = this.uids.get(attribute);
|
|
5880
|
+
return uids.get(isRelativeCopy);
|
|
5881
|
+
}
|
|
5882
|
+
/**
|
|
5883
|
+
* Checks if normal attribute values are normalized.
|
|
5884
|
+
*
|
|
5885
|
+
* @param {BufferAttribute} normal
|
|
5886
|
+
* @returns {Boolean}
|
|
5887
|
+
*/
|
|
5888
|
+
isNormalizedNormalAttribute(normal) {
|
|
5889
|
+
const cache = this.cache;
|
|
5890
|
+
if (cache.attributesNormalized.has(normal)) return false;
|
|
5891
|
+
const v = new Vector38();
|
|
5892
|
+
for (let i = 0, il = normal.count; i < il; i++) {
|
|
5893
|
+
if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1) > 5e-4) return false;
|
|
5894
|
+
}
|
|
5895
|
+
return true;
|
|
5896
|
+
}
|
|
5897
|
+
/**
|
|
5898
|
+
* Creates normalized normal buffer attribute.
|
|
5899
|
+
*
|
|
5900
|
+
* @param {BufferAttribute} normal
|
|
5901
|
+
* @returns {BufferAttribute}
|
|
5902
|
+
*
|
|
5903
|
+
*/
|
|
5904
|
+
createNormalizedNormalAttribute(normal) {
|
|
5905
|
+
const cache = this.cache;
|
|
5906
|
+
if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal);
|
|
5907
|
+
const attribute = normal.clone();
|
|
5908
|
+
const v = new Vector38();
|
|
5909
|
+
for (let i = 0, il = attribute.count; i < il; i++) {
|
|
5910
|
+
v.fromBufferAttribute(attribute, i);
|
|
5911
|
+
if (v.x === 0 && v.y === 0 && v.z === 0) {
|
|
5912
|
+
v.setX(1);
|
|
5913
|
+
} else {
|
|
5914
|
+
v.normalize();
|
|
5915
|
+
}
|
|
5916
|
+
attribute.setXYZ(i, v.x, v.y, v.z);
|
|
5917
|
+
}
|
|
5918
|
+
cache.attributesNormalized.set(normal, attribute);
|
|
5919
|
+
return attribute;
|
|
5920
|
+
}
|
|
5921
|
+
/**
|
|
5922
|
+
* Applies a texture transform, if present, to the map definition. Requires
|
|
5923
|
+
* the KHR_texture_transform extension.
|
|
5924
|
+
*
|
|
5925
|
+
* @param {Object} mapDef
|
|
5926
|
+
* @param {THREE.Texture} texture
|
|
5927
|
+
*/
|
|
5928
|
+
applyTextureTransform(mapDef, texture) {
|
|
5929
|
+
let didTransform = false;
|
|
5930
|
+
const transformDef = {};
|
|
5931
|
+
if (texture.offset.x !== 0 || texture.offset.y !== 0) {
|
|
5932
|
+
transformDef.offset = texture.offset.toArray();
|
|
5933
|
+
didTransform = true;
|
|
5934
|
+
}
|
|
5935
|
+
if (texture.rotation !== 0) {
|
|
5936
|
+
transformDef.rotation = texture.rotation;
|
|
5937
|
+
didTransform = true;
|
|
5938
|
+
}
|
|
5939
|
+
if (texture.repeat.x !== 1 || texture.repeat.y !== 1) {
|
|
5940
|
+
transformDef.scale = texture.repeat.toArray();
|
|
5941
|
+
didTransform = true;
|
|
5942
|
+
}
|
|
5943
|
+
if (didTransform) {
|
|
5944
|
+
mapDef.extensions = mapDef.extensions || {};
|
|
5945
|
+
mapDef.extensions["KHR_texture_transform"] = transformDef;
|
|
5946
|
+
this.extensionsUsed["KHR_texture_transform"] = true;
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
buildMetalRoughTexture(metalnessMap, roughnessMap) {
|
|
5950
|
+
if (metalnessMap === roughnessMap) return metalnessMap;
|
|
5951
|
+
function getEncodingConversion(map) {
|
|
5952
|
+
if (map.colorSpace === SRGBColorSpace4) {
|
|
5953
|
+
return function SRGBToLinear(c) {
|
|
5954
|
+
return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
|
|
5955
|
+
};
|
|
5956
|
+
}
|
|
5957
|
+
return function LinearToLinear(c) {
|
|
5958
|
+
return c;
|
|
5959
|
+
};
|
|
5960
|
+
}
|
|
5961
|
+
console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
|
|
5962
|
+
if (metalnessMap instanceof CompressedTexture) {
|
|
5963
|
+
metalnessMap = decompress(metalnessMap);
|
|
5964
|
+
}
|
|
5965
|
+
if (roughnessMap instanceof CompressedTexture) {
|
|
5966
|
+
roughnessMap = decompress(roughnessMap);
|
|
5967
|
+
}
|
|
5968
|
+
const metalness = metalnessMap ? metalnessMap.image : null;
|
|
5969
|
+
const roughness = roughnessMap ? roughnessMap.image : null;
|
|
5970
|
+
const width = Math.max(metalness ? metalness.width : 0, roughness ? roughness.width : 0);
|
|
5971
|
+
const height = Math.max(metalness ? metalness.height : 0, roughness ? roughness.height : 0);
|
|
5972
|
+
const canvas = getCanvas();
|
|
5973
|
+
canvas.width = width;
|
|
5974
|
+
canvas.height = height;
|
|
5975
|
+
const context = canvas.getContext("2d");
|
|
5976
|
+
context.fillStyle = "#00ffff";
|
|
5977
|
+
context.fillRect(0, 0, width, height);
|
|
5978
|
+
const composite = context.getImageData(0, 0, width, height);
|
|
5979
|
+
if (metalness) {
|
|
5980
|
+
context.drawImage(metalness, 0, 0, width, height);
|
|
5981
|
+
const convert = getEncodingConversion(metalnessMap);
|
|
5982
|
+
const data = context.getImageData(0, 0, width, height).data;
|
|
5983
|
+
for (let i = 2; i < data.length; i += 4) {
|
|
5984
|
+
composite.data[i] = convert(data[i] / 256) * 256;
|
|
5985
|
+
}
|
|
5986
|
+
}
|
|
5987
|
+
if (roughness) {
|
|
5988
|
+
context.drawImage(roughness, 0, 0, width, height);
|
|
5989
|
+
const convert = getEncodingConversion(roughnessMap);
|
|
5990
|
+
const data = context.getImageData(0, 0, width, height).data;
|
|
5991
|
+
for (let i = 1; i < data.length; i += 4) {
|
|
5992
|
+
composite.data[i] = convert(data[i] / 256) * 256;
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
context.putImageData(composite, 0, 0);
|
|
5996
|
+
const reference = metalnessMap || roughnessMap;
|
|
5997
|
+
const texture = reference.clone();
|
|
5998
|
+
texture.source = new Source(canvas);
|
|
5999
|
+
texture.colorSpace = NoColorSpace;
|
|
6000
|
+
texture.channel = (metalnessMap || roughnessMap).channel;
|
|
6001
|
+
if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
|
|
6002
|
+
console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
|
|
6003
|
+
}
|
|
6004
|
+
return texture;
|
|
6005
|
+
}
|
|
6006
|
+
/**
|
|
6007
|
+
* Process a buffer to append to the default one.
|
|
6008
|
+
* @param {ArrayBuffer} buffer
|
|
6009
|
+
* @return {Integer}
|
|
6010
|
+
*/
|
|
6011
|
+
processBuffer(buffer) {
|
|
6012
|
+
const json = this.json;
|
|
6013
|
+
const buffers = this.buffers;
|
|
6014
|
+
if (!json.buffers) json.buffers = [{ byteLength: 0 }];
|
|
6015
|
+
buffers.push(buffer);
|
|
6016
|
+
return 0;
|
|
6017
|
+
}
|
|
6018
|
+
/**
|
|
6019
|
+
* Process and generate a BufferView
|
|
6020
|
+
* @param {BufferAttribute} attribute
|
|
6021
|
+
* @param {number} componentType
|
|
6022
|
+
* @param {number} start
|
|
6023
|
+
* @param {number} count
|
|
6024
|
+
* @param {number} target (Optional) Target usage of the BufferView
|
|
6025
|
+
* @return {Object}
|
|
6026
|
+
*/
|
|
6027
|
+
processBufferView(attribute, componentType, start, count, target) {
|
|
6028
|
+
const json = this.json;
|
|
6029
|
+
if (!json.bufferViews) json.bufferViews = [];
|
|
6030
|
+
let componentSize;
|
|
6031
|
+
switch (componentType) {
|
|
6032
|
+
case WEBGL_CONSTANTS.BYTE:
|
|
6033
|
+
case WEBGL_CONSTANTS.UNSIGNED_BYTE:
|
|
6034
|
+
componentSize = 1;
|
|
6035
|
+
break;
|
|
6036
|
+
case WEBGL_CONSTANTS.SHORT:
|
|
6037
|
+
case WEBGL_CONSTANTS.UNSIGNED_SHORT:
|
|
6038
|
+
componentSize = 2;
|
|
6039
|
+
break;
|
|
6040
|
+
default:
|
|
6041
|
+
componentSize = 4;
|
|
6042
|
+
}
|
|
6043
|
+
const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
|
|
6044
|
+
const dataView = new DataView(new ArrayBuffer(byteLength));
|
|
6045
|
+
let offset = 0;
|
|
6046
|
+
for (let i = start; i < start + count; i++) {
|
|
6047
|
+
for (let a = 0; a < attribute.itemSize; a++) {
|
|
6048
|
+
let value;
|
|
6049
|
+
if (attribute.itemSize > 4) {
|
|
6050
|
+
value = attribute.array[i * attribute.itemSize + a];
|
|
6051
|
+
} else {
|
|
6052
|
+
if (a === 0) value = attribute.getX(i);
|
|
6053
|
+
else if (a === 1) value = attribute.getY(i);
|
|
6054
|
+
else if (a === 2) value = attribute.getZ(i);
|
|
6055
|
+
else if (a === 3) value = attribute.getW(i);
|
|
6056
|
+
if (attribute.normalized === true) {
|
|
6057
|
+
value = MathUtils2.normalize(value, attribute.array);
|
|
6058
|
+
}
|
|
6059
|
+
}
|
|
6060
|
+
if (componentType === WEBGL_CONSTANTS.FLOAT) {
|
|
6061
|
+
dataView.setFloat32(offset, value, true);
|
|
6062
|
+
} else if (componentType === WEBGL_CONSTANTS.INT) {
|
|
6063
|
+
dataView.setInt32(offset, value, true);
|
|
6064
|
+
} else if (componentType === WEBGL_CONSTANTS.UNSIGNED_INT) {
|
|
6065
|
+
dataView.setUint32(offset, value, true);
|
|
6066
|
+
} else if (componentType === WEBGL_CONSTANTS.SHORT) {
|
|
6067
|
+
dataView.setInt16(offset, value, true);
|
|
6068
|
+
} else if (componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT) {
|
|
6069
|
+
dataView.setUint16(offset, value, true);
|
|
6070
|
+
} else if (componentType === WEBGL_CONSTANTS.BYTE) {
|
|
6071
|
+
dataView.setInt8(offset, value);
|
|
6072
|
+
} else if (componentType === WEBGL_CONSTANTS.UNSIGNED_BYTE) {
|
|
6073
|
+
dataView.setUint8(offset, value);
|
|
6074
|
+
}
|
|
6075
|
+
offset += componentSize;
|
|
6076
|
+
}
|
|
6077
|
+
}
|
|
6078
|
+
const bufferViewDef = {
|
|
6079
|
+
buffer: this.processBuffer(dataView.buffer),
|
|
6080
|
+
byteOffset: this.byteOffset,
|
|
6081
|
+
byteLength
|
|
6082
|
+
};
|
|
6083
|
+
if (target !== void 0) bufferViewDef.target = target;
|
|
6084
|
+
if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
|
|
6085
|
+
bufferViewDef.byteStride = attribute.itemSize * componentSize;
|
|
6086
|
+
}
|
|
6087
|
+
this.byteOffset += byteLength;
|
|
6088
|
+
json.bufferViews.push(bufferViewDef);
|
|
6089
|
+
const output = {
|
|
6090
|
+
id: json.bufferViews.length - 1,
|
|
6091
|
+
byteLength: 0
|
|
6092
|
+
};
|
|
6093
|
+
return output;
|
|
6094
|
+
}
|
|
6095
|
+
/**
|
|
6096
|
+
* Process and generate a BufferView from an image Blob.
|
|
6097
|
+
* @param {Blob} blob
|
|
6098
|
+
* @return {Promise<Integer>}
|
|
6099
|
+
*/
|
|
6100
|
+
processBufferViewImage(blob) {
|
|
6101
|
+
const writer = this;
|
|
6102
|
+
const json = writer.json;
|
|
6103
|
+
if (!json.bufferViews) json.bufferViews = [];
|
|
6104
|
+
return new Promise(function(resolve) {
|
|
6105
|
+
const reader = new FileReader();
|
|
6106
|
+
reader.readAsArrayBuffer(blob);
|
|
6107
|
+
reader.onloadend = function() {
|
|
6108
|
+
const buffer = getPaddedArrayBuffer(reader.result);
|
|
6109
|
+
const bufferViewDef = {
|
|
6110
|
+
buffer: writer.processBuffer(buffer),
|
|
6111
|
+
byteOffset: writer.byteOffset,
|
|
6112
|
+
byteLength: buffer.byteLength
|
|
6113
|
+
};
|
|
6114
|
+
writer.byteOffset += buffer.byteLength;
|
|
6115
|
+
resolve(json.bufferViews.push(bufferViewDef) - 1);
|
|
6116
|
+
};
|
|
6117
|
+
});
|
|
6118
|
+
}
|
|
6119
|
+
/**
|
|
6120
|
+
* Process attribute to generate an accessor
|
|
6121
|
+
* @param {BufferAttribute} attribute Attribute to process
|
|
6122
|
+
* @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
|
|
6123
|
+
* @param {Integer} start (Optional)
|
|
6124
|
+
* @param {Integer} count (Optional)
|
|
6125
|
+
* @return {Integer|null} Index of the processed accessor on the "accessors" array
|
|
6126
|
+
*/
|
|
6127
|
+
processAccessor(attribute, geometry, start, count) {
|
|
6128
|
+
const json = this.json;
|
|
6129
|
+
const types = {
|
|
6130
|
+
1: "SCALAR",
|
|
6131
|
+
2: "VEC2",
|
|
6132
|
+
3: "VEC3",
|
|
6133
|
+
4: "VEC4",
|
|
6134
|
+
9: "MAT3",
|
|
6135
|
+
16: "MAT4"
|
|
6136
|
+
};
|
|
6137
|
+
let componentType;
|
|
6138
|
+
if (attribute.array.constructor === Float32Array) {
|
|
6139
|
+
componentType = WEBGL_CONSTANTS.FLOAT;
|
|
6140
|
+
} else if (attribute.array.constructor === Int32Array) {
|
|
6141
|
+
componentType = WEBGL_CONSTANTS.INT;
|
|
6142
|
+
} else if (attribute.array.constructor === Uint32Array) {
|
|
6143
|
+
componentType = WEBGL_CONSTANTS.UNSIGNED_INT;
|
|
6144
|
+
} else if (attribute.array.constructor === Int16Array) {
|
|
6145
|
+
componentType = WEBGL_CONSTANTS.SHORT;
|
|
6146
|
+
} else if (attribute.array.constructor === Uint16Array) {
|
|
6147
|
+
componentType = WEBGL_CONSTANTS.UNSIGNED_SHORT;
|
|
6148
|
+
} else if (attribute.array.constructor === Int8Array) {
|
|
6149
|
+
componentType = WEBGL_CONSTANTS.BYTE;
|
|
6150
|
+
} else if (attribute.array.constructor === Uint8Array) {
|
|
6151
|
+
componentType = WEBGL_CONSTANTS.UNSIGNED_BYTE;
|
|
6152
|
+
} else {
|
|
6153
|
+
throw new Error("THREE.GLTFExporter: Unsupported bufferAttribute component type: " + attribute.array.constructor.name);
|
|
6154
|
+
}
|
|
6155
|
+
if (start === void 0) start = 0;
|
|
6156
|
+
if (count === void 0 || count === Infinity) count = attribute.count;
|
|
6157
|
+
if (count === 0) return null;
|
|
6158
|
+
const minMax = getMinMax(attribute, start, count);
|
|
6159
|
+
let bufferViewTarget;
|
|
6160
|
+
if (geometry !== void 0) {
|
|
6161
|
+
bufferViewTarget = attribute === geometry.index ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER : WEBGL_CONSTANTS.ARRAY_BUFFER;
|
|
6162
|
+
}
|
|
6163
|
+
const bufferView = this.processBufferView(attribute, componentType, start, count, bufferViewTarget);
|
|
6164
|
+
const accessorDef = {
|
|
6165
|
+
bufferView: bufferView.id,
|
|
6166
|
+
byteOffset: bufferView.byteOffset,
|
|
6167
|
+
componentType,
|
|
6168
|
+
count,
|
|
6169
|
+
max: minMax.max,
|
|
6170
|
+
min: minMax.min,
|
|
6171
|
+
type: types[attribute.itemSize]
|
|
6172
|
+
};
|
|
6173
|
+
if (attribute.normalized === true) accessorDef.normalized = true;
|
|
6174
|
+
if (!json.accessors) json.accessors = [];
|
|
6175
|
+
return json.accessors.push(accessorDef) - 1;
|
|
6176
|
+
}
|
|
6177
|
+
/**
|
|
6178
|
+
* Process image
|
|
6179
|
+
* @param {Image} image to process
|
|
6180
|
+
* @param {Integer} format of the image (RGBAFormat)
|
|
6181
|
+
* @param {Boolean} flipY before writing out the image
|
|
6182
|
+
* @param {String} mimeType export format
|
|
6183
|
+
* @return {Integer} Index of the processed texture in the "images" array
|
|
6184
|
+
*/
|
|
6185
|
+
processImage(image, format, flipY, mimeType = "image/png") {
|
|
6186
|
+
if (image !== null) {
|
|
6187
|
+
const writer = this;
|
|
6188
|
+
const cache = writer.cache;
|
|
6189
|
+
const json = writer.json;
|
|
6190
|
+
const options = writer.options;
|
|
6191
|
+
const pending = writer.pending;
|
|
6192
|
+
if (!cache.images.has(image)) cache.images.set(image, {});
|
|
6193
|
+
const cachedImages = cache.images.get(image);
|
|
6194
|
+
const key = mimeType + ":flipY/" + flipY.toString();
|
|
6195
|
+
if (cachedImages[key] !== void 0) return cachedImages[key];
|
|
6196
|
+
if (!json.images) json.images = [];
|
|
6197
|
+
const imageDef = { mimeType };
|
|
6198
|
+
const canvas = getCanvas();
|
|
6199
|
+
canvas.width = Math.min(image.width, options.maxTextureSize);
|
|
6200
|
+
canvas.height = Math.min(image.height, options.maxTextureSize);
|
|
6201
|
+
const ctx = canvas.getContext("2d");
|
|
6202
|
+
if (flipY === true) {
|
|
6203
|
+
ctx.translate(0, canvas.height);
|
|
6204
|
+
ctx.scale(1, -1);
|
|
6205
|
+
}
|
|
6206
|
+
if (image.data !== void 0) {
|
|
6207
|
+
if (format !== RGBAFormat2) {
|
|
6208
|
+
console.error("GLTFExporter: Only RGBAFormat is supported.", format);
|
|
6209
|
+
}
|
|
6210
|
+
if (image.width > options.maxTextureSize || image.height > options.maxTextureSize) {
|
|
6211
|
+
console.warn("GLTFExporter: Image size is bigger than maxTextureSize", image);
|
|
6212
|
+
}
|
|
6213
|
+
const data = new Uint8ClampedArray(image.height * image.width * 4);
|
|
6214
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
6215
|
+
data[i + 0] = image.data[i + 0];
|
|
6216
|
+
data[i + 1] = image.data[i + 1];
|
|
6217
|
+
data[i + 2] = image.data[i + 2];
|
|
6218
|
+
data[i + 3] = image.data[i + 3];
|
|
6219
|
+
}
|
|
6220
|
+
ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
|
|
6221
|
+
} else {
|
|
6222
|
+
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
6223
|
+
}
|
|
6224
|
+
if (options.binary === true) {
|
|
6225
|
+
pending.push(
|
|
6226
|
+
getToBlobPromise(canvas, mimeType).then((blob) => writer.processBufferViewImage(blob)).then((bufferViewIndex) => {
|
|
6227
|
+
imageDef.bufferView = bufferViewIndex;
|
|
6228
|
+
})
|
|
6229
|
+
);
|
|
6230
|
+
} else {
|
|
6231
|
+
if (canvas.toDataURL !== void 0) {
|
|
6232
|
+
imageDef.uri = canvas.toDataURL(mimeType);
|
|
6233
|
+
} else {
|
|
6234
|
+
pending.push(
|
|
6235
|
+
getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
|
|
6236
|
+
imageDef.uri = dataURL;
|
|
6237
|
+
})
|
|
6238
|
+
);
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
const index = json.images.push(imageDef) - 1;
|
|
6242
|
+
cachedImages[key] = index;
|
|
6243
|
+
return index;
|
|
6244
|
+
} else {
|
|
6245
|
+
throw new Error("THREE.GLTFExporter: No valid image data found. Unable to process texture.");
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
6248
|
+
/**
|
|
6249
|
+
* Process sampler
|
|
6250
|
+
* @param {Texture} map Texture to process
|
|
6251
|
+
* @return {Integer} Index of the processed texture in the "samplers" array
|
|
6252
|
+
*/
|
|
6253
|
+
processSampler(map) {
|
|
6254
|
+
const json = this.json;
|
|
6255
|
+
if (!json.samplers) json.samplers = [];
|
|
6256
|
+
const samplerDef = {
|
|
6257
|
+
magFilter: THREE_TO_WEBGL[map.magFilter],
|
|
6258
|
+
minFilter: THREE_TO_WEBGL[map.minFilter],
|
|
6259
|
+
wrapS: THREE_TO_WEBGL[map.wrapS],
|
|
6260
|
+
wrapT: THREE_TO_WEBGL[map.wrapT]
|
|
6261
|
+
};
|
|
6262
|
+
return json.samplers.push(samplerDef) - 1;
|
|
6263
|
+
}
|
|
6264
|
+
/**
|
|
6265
|
+
* Process texture
|
|
6266
|
+
* @param {Texture} map Map to process
|
|
6267
|
+
* @return {Integer} Index of the processed texture in the "textures" array
|
|
6268
|
+
*/
|
|
6269
|
+
processTexture(map) {
|
|
6270
|
+
const writer = this;
|
|
6271
|
+
const options = writer.options;
|
|
6272
|
+
const cache = this.cache;
|
|
6273
|
+
const json = this.json;
|
|
6274
|
+
if (cache.textures.has(map)) return cache.textures.get(map);
|
|
6275
|
+
if (!json.textures) json.textures = [];
|
|
6276
|
+
if (map instanceof CompressedTexture) {
|
|
6277
|
+
map = decompress(map, options.maxTextureSize);
|
|
6278
|
+
}
|
|
6279
|
+
let mimeType = map.userData.mimeType;
|
|
6280
|
+
if (mimeType === "image/webp") mimeType = "image/png";
|
|
6281
|
+
const textureDef = {
|
|
6282
|
+
sampler: this.processSampler(map),
|
|
6283
|
+
source: this.processImage(map.image, map.format, map.flipY, mimeType)
|
|
6284
|
+
};
|
|
6285
|
+
if (map.name) textureDef.name = map.name;
|
|
6286
|
+
this._invokeAll(function(ext) {
|
|
6287
|
+
ext.writeTexture && ext.writeTexture(map, textureDef);
|
|
6288
|
+
});
|
|
6289
|
+
const index = json.textures.push(textureDef) - 1;
|
|
6290
|
+
cache.textures.set(map, index);
|
|
6291
|
+
return index;
|
|
6292
|
+
}
|
|
6293
|
+
/**
|
|
6294
|
+
* Process material
|
|
6295
|
+
* @param {THREE.Material} material Material to process
|
|
6296
|
+
* @return {Integer|null} Index of the processed material in the "materials" array
|
|
6297
|
+
*/
|
|
6298
|
+
processMaterial(material) {
|
|
6299
|
+
const cache = this.cache;
|
|
6300
|
+
const json = this.json;
|
|
6301
|
+
if (cache.materials.has(material)) return cache.materials.get(material);
|
|
6302
|
+
if (material.isShaderMaterial) {
|
|
6303
|
+
console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
|
|
6304
|
+
return null;
|
|
6305
|
+
}
|
|
6306
|
+
if (!json.materials) json.materials = [];
|
|
6307
|
+
const materialDef = { pbrMetallicRoughness: {} };
|
|
6308
|
+
if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
|
|
6309
|
+
console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
|
|
6310
|
+
}
|
|
6311
|
+
const color = material.color.toArray().concat([material.opacity]);
|
|
6312
|
+
if (!equalArray(color, [1, 1, 1, 1])) {
|
|
6313
|
+
materialDef.pbrMetallicRoughness.baseColorFactor = color;
|
|
6314
|
+
}
|
|
6315
|
+
if (material.isMeshStandardMaterial) {
|
|
6316
|
+
materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
|
|
6317
|
+
materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
|
|
6318
|
+
} else {
|
|
6319
|
+
materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
|
|
6320
|
+
materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
|
|
6321
|
+
}
|
|
6322
|
+
if (material.metalnessMap || material.roughnessMap) {
|
|
6323
|
+
const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
|
|
6324
|
+
const metalRoughMapDef = {
|
|
6325
|
+
index: this.processTexture(metalRoughTexture),
|
|
6326
|
+
channel: metalRoughTexture.channel
|
|
6327
|
+
};
|
|
6328
|
+
this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
|
|
6329
|
+
materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
|
|
6330
|
+
}
|
|
6331
|
+
if (material.map) {
|
|
6332
|
+
const baseColorMapDef = {
|
|
6333
|
+
index: this.processTexture(material.map),
|
|
6334
|
+
texCoord: material.map.channel
|
|
6335
|
+
};
|
|
6336
|
+
this.applyTextureTransform(baseColorMapDef, material.map);
|
|
6337
|
+
materialDef.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
|
|
6338
|
+
}
|
|
6339
|
+
if (material.emissive) {
|
|
6340
|
+
const emissive = material.emissive;
|
|
6341
|
+
const maxEmissiveComponent = Math.max(emissive.r, emissive.g, emissive.b);
|
|
6342
|
+
if (maxEmissiveComponent > 0) {
|
|
6343
|
+
materialDef.emissiveFactor = material.emissive.toArray();
|
|
6344
|
+
}
|
|
6345
|
+
if (material.emissiveMap) {
|
|
6346
|
+
const emissiveMapDef = {
|
|
6347
|
+
index: this.processTexture(material.emissiveMap),
|
|
6348
|
+
texCoord: material.emissiveMap.channel
|
|
6349
|
+
};
|
|
6350
|
+
this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
|
|
6351
|
+
materialDef.emissiveTexture = emissiveMapDef;
|
|
6352
|
+
}
|
|
6353
|
+
}
|
|
6354
|
+
if (material.normalMap) {
|
|
6355
|
+
const normalMapDef = {
|
|
6356
|
+
index: this.processTexture(material.normalMap),
|
|
6357
|
+
texCoord: material.normalMap.channel
|
|
6358
|
+
};
|
|
6359
|
+
if (material.normalScale && material.normalScale.x !== 1) {
|
|
6360
|
+
normalMapDef.scale = material.normalScale.x;
|
|
6361
|
+
}
|
|
6362
|
+
this.applyTextureTransform(normalMapDef, material.normalMap);
|
|
6363
|
+
materialDef.normalTexture = normalMapDef;
|
|
6364
|
+
}
|
|
6365
|
+
if (material.aoMap) {
|
|
6366
|
+
const occlusionMapDef = {
|
|
6367
|
+
index: this.processTexture(material.aoMap),
|
|
6368
|
+
texCoord: material.aoMap.channel
|
|
6369
|
+
};
|
|
6370
|
+
if (material.aoMapIntensity !== 1) {
|
|
6371
|
+
occlusionMapDef.strength = material.aoMapIntensity;
|
|
6372
|
+
}
|
|
6373
|
+
this.applyTextureTransform(occlusionMapDef, material.aoMap);
|
|
6374
|
+
materialDef.occlusionTexture = occlusionMapDef;
|
|
6375
|
+
}
|
|
6376
|
+
if (material.transparent) {
|
|
6377
|
+
materialDef.alphaMode = "BLEND";
|
|
6378
|
+
} else {
|
|
6379
|
+
if (material.alphaTest > 0) {
|
|
6380
|
+
materialDef.alphaMode = "MASK";
|
|
6381
|
+
materialDef.alphaCutoff = material.alphaTest;
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
if (material.side === DoubleSide2) materialDef.doubleSided = true;
|
|
6385
|
+
if (material.name !== "") materialDef.name = material.name;
|
|
6386
|
+
this.serializeUserData(material, materialDef);
|
|
6387
|
+
this._invokeAll(function(ext) {
|
|
6388
|
+
ext.writeMaterial && ext.writeMaterial(material, materialDef);
|
|
6389
|
+
});
|
|
6390
|
+
const index = json.materials.push(materialDef) - 1;
|
|
6391
|
+
cache.materials.set(material, index);
|
|
6392
|
+
return index;
|
|
6393
|
+
}
|
|
6394
|
+
/**
|
|
6395
|
+
* Process mesh
|
|
6396
|
+
* @param {THREE.Mesh} mesh Mesh to process
|
|
6397
|
+
* @return {Integer|null} Index of the processed mesh in the "meshes" array
|
|
6398
|
+
*/
|
|
6399
|
+
processMesh(mesh) {
|
|
6400
|
+
const cache = this.cache;
|
|
6401
|
+
const json = this.json;
|
|
6402
|
+
const meshCacheKeyParts = [mesh.geometry.uuid];
|
|
6403
|
+
if (Array.isArray(mesh.material)) {
|
|
6404
|
+
for (let i = 0, l = mesh.material.length; i < l; i++) {
|
|
6405
|
+
meshCacheKeyParts.push(mesh.material[i].uuid);
|
|
6406
|
+
}
|
|
6407
|
+
} else {
|
|
6408
|
+
meshCacheKeyParts.push(mesh.material.uuid);
|
|
6409
|
+
}
|
|
6410
|
+
const meshCacheKey = meshCacheKeyParts.join(":");
|
|
6411
|
+
if (cache.meshes.has(meshCacheKey)) return cache.meshes.get(meshCacheKey);
|
|
6412
|
+
const geometry = mesh.geometry;
|
|
6413
|
+
let mode;
|
|
6414
|
+
if (mesh.isLineSegments) {
|
|
6415
|
+
mode = WEBGL_CONSTANTS.LINES;
|
|
6416
|
+
} else if (mesh.isLineLoop) {
|
|
6417
|
+
mode = WEBGL_CONSTANTS.LINE_LOOP;
|
|
6418
|
+
} else if (mesh.isLine) {
|
|
6419
|
+
mode = WEBGL_CONSTANTS.LINE_STRIP;
|
|
6420
|
+
} else if (mesh.isPoints) {
|
|
6421
|
+
mode = WEBGL_CONSTANTS.POINTS;
|
|
6422
|
+
} else {
|
|
6423
|
+
mode = mesh.material.wireframe ? WEBGL_CONSTANTS.LINES : WEBGL_CONSTANTS.TRIANGLES;
|
|
6424
|
+
}
|
|
6425
|
+
const meshDef = {};
|
|
6426
|
+
const attributes = {};
|
|
6427
|
+
const primitives = [];
|
|
6428
|
+
const targets = [];
|
|
6429
|
+
const nameConversion = {
|
|
6430
|
+
uv: "TEXCOORD_0",
|
|
6431
|
+
uv1: "TEXCOORD_1",
|
|
6432
|
+
uv2: "TEXCOORD_2",
|
|
6433
|
+
uv3: "TEXCOORD_3",
|
|
6434
|
+
color: "COLOR_0",
|
|
6435
|
+
skinWeight: "WEIGHTS_0",
|
|
6436
|
+
skinIndex: "JOINTS_0"
|
|
6437
|
+
};
|
|
6438
|
+
const originalNormal = geometry.getAttribute("normal");
|
|
6439
|
+
if (originalNormal !== void 0 && !this.isNormalizedNormalAttribute(originalNormal)) {
|
|
6440
|
+
console.warn("THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.");
|
|
6441
|
+
geometry.setAttribute("normal", this.createNormalizedNormalAttribute(originalNormal));
|
|
6442
|
+
}
|
|
6443
|
+
let modifiedAttribute = null;
|
|
6444
|
+
for (let attributeName in geometry.attributes) {
|
|
6445
|
+
if (attributeName.slice(0, 5) === "morph") continue;
|
|
6446
|
+
const attribute = geometry.attributes[attributeName];
|
|
6447
|
+
attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
|
|
6448
|
+
const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
|
|
6449
|
+
if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
|
|
6450
|
+
if (cache.attributes.has(this.getUID(attribute))) {
|
|
6451
|
+
attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
|
|
6452
|
+
continue;
|
|
6453
|
+
}
|
|
6454
|
+
modifiedAttribute = null;
|
|
6455
|
+
const array = attribute.array;
|
|
6456
|
+
if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
|
|
6457
|
+
console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
|
|
6458
|
+
modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
|
|
6459
|
+
}
|
|
6460
|
+
const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
|
|
6461
|
+
if (accessor !== null) {
|
|
6462
|
+
if (!attributeName.startsWith("_")) {
|
|
6463
|
+
this.detectMeshQuantization(attributeName, attribute);
|
|
6464
|
+
}
|
|
6465
|
+
attributes[attributeName] = accessor;
|
|
6466
|
+
cache.attributes.set(this.getUID(attribute), accessor);
|
|
6467
|
+
}
|
|
6468
|
+
}
|
|
6469
|
+
if (originalNormal !== void 0) geometry.setAttribute("normal", originalNormal);
|
|
6470
|
+
if (Object.keys(attributes).length === 0) return null;
|
|
6471
|
+
if (mesh.morphTargetInfluences !== void 0 && mesh.morphTargetInfluences.length > 0) {
|
|
6472
|
+
const weights = [];
|
|
6473
|
+
const targetNames = [];
|
|
6474
|
+
const reverseDictionary = {};
|
|
6475
|
+
if (mesh.morphTargetDictionary !== void 0) {
|
|
6476
|
+
for (const key in mesh.morphTargetDictionary) {
|
|
6477
|
+
reverseDictionary[mesh.morphTargetDictionary[key]] = key;
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
for (let i = 0; i < mesh.morphTargetInfluences.length; ++i) {
|
|
6481
|
+
const target = {};
|
|
6482
|
+
let warned = false;
|
|
6483
|
+
for (const attributeName in geometry.morphAttributes) {
|
|
6484
|
+
if (attributeName !== "position" && attributeName !== "normal") {
|
|
6485
|
+
if (!warned) {
|
|
6486
|
+
console.warn("GLTFExporter: Only POSITION and NORMAL morph are supported.");
|
|
6487
|
+
warned = true;
|
|
6488
|
+
}
|
|
6489
|
+
continue;
|
|
6490
|
+
}
|
|
6491
|
+
const attribute = geometry.morphAttributes[attributeName][i];
|
|
6492
|
+
const gltfAttributeName = attributeName.toUpperCase();
|
|
6493
|
+
const baseAttribute = geometry.attributes[attributeName];
|
|
6494
|
+
if (cache.attributes.has(this.getUID(attribute, true))) {
|
|
6495
|
+
target[gltfAttributeName] = cache.attributes.get(this.getUID(attribute, true));
|
|
6496
|
+
continue;
|
|
6497
|
+
}
|
|
6498
|
+
const relativeAttribute = attribute.clone();
|
|
6499
|
+
if (!geometry.morphTargetsRelative) {
|
|
6500
|
+
for (let j = 0, jl = attribute.count; j < jl; j++) {
|
|
6501
|
+
for (let a = 0; a < attribute.itemSize; a++) {
|
|
6502
|
+
if (a === 0) relativeAttribute.setX(j, attribute.getX(j) - baseAttribute.getX(j));
|
|
6503
|
+
if (a === 1) relativeAttribute.setY(j, attribute.getY(j) - baseAttribute.getY(j));
|
|
6504
|
+
if (a === 2) relativeAttribute.setZ(j, attribute.getZ(j) - baseAttribute.getZ(j));
|
|
6505
|
+
if (a === 3) relativeAttribute.setW(j, attribute.getW(j) - baseAttribute.getW(j));
|
|
6506
|
+
}
|
|
6507
|
+
}
|
|
6508
|
+
}
|
|
6509
|
+
target[gltfAttributeName] = this.processAccessor(relativeAttribute, geometry);
|
|
6510
|
+
cache.attributes.set(this.getUID(baseAttribute, true), target[gltfAttributeName]);
|
|
6511
|
+
}
|
|
6512
|
+
targets.push(target);
|
|
6513
|
+
weights.push(mesh.morphTargetInfluences[i]);
|
|
6514
|
+
if (mesh.morphTargetDictionary !== void 0) targetNames.push(reverseDictionary[i]);
|
|
6515
|
+
}
|
|
6516
|
+
meshDef.weights = weights;
|
|
6517
|
+
if (targetNames.length > 0) {
|
|
6518
|
+
meshDef.extras = {};
|
|
6519
|
+
meshDef.extras.targetNames = targetNames;
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
const isMultiMaterial = Array.isArray(mesh.material);
|
|
6523
|
+
if (isMultiMaterial && geometry.groups.length === 0) return null;
|
|
6524
|
+
const materials = isMultiMaterial ? mesh.material : [mesh.material];
|
|
6525
|
+
const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
|
|
6526
|
+
for (let i = 0, il = groups.length; i < il; i++) {
|
|
6527
|
+
const primitive = {
|
|
6528
|
+
mode,
|
|
6529
|
+
attributes
|
|
6530
|
+
};
|
|
6531
|
+
this.serializeUserData(geometry, primitive);
|
|
6532
|
+
if (targets.length > 0) primitive.targets = targets;
|
|
6533
|
+
if (geometry.index !== null) {
|
|
6534
|
+
let cacheKey = this.getUID(geometry.index);
|
|
6535
|
+
if (groups[i].start !== void 0 || groups[i].count !== void 0) {
|
|
6536
|
+
cacheKey += ":" + groups[i].start + ":" + groups[i].count;
|
|
6537
|
+
}
|
|
6538
|
+
if (cache.attributes.has(cacheKey)) {
|
|
6539
|
+
primitive.indices = cache.attributes.get(cacheKey);
|
|
6540
|
+
} else {
|
|
6541
|
+
primitive.indices = this.processAccessor(geometry.index, geometry, groups[i].start, groups[i].count);
|
|
6542
|
+
cache.attributes.set(cacheKey, primitive.indices);
|
|
6543
|
+
}
|
|
6544
|
+
if (primitive.indices === null) delete primitive.indices;
|
|
6545
|
+
}
|
|
6546
|
+
const material = this.processMaterial(materials[groups[i].materialIndex]);
|
|
6547
|
+
if (material !== null) primitive.material = material;
|
|
6548
|
+
primitives.push(primitive);
|
|
6549
|
+
}
|
|
6550
|
+
meshDef.primitives = primitives;
|
|
6551
|
+
if (!json.meshes) json.meshes = [];
|
|
6552
|
+
this._invokeAll(function(ext) {
|
|
6553
|
+
ext.writeMesh && ext.writeMesh(mesh, meshDef);
|
|
6554
|
+
});
|
|
6555
|
+
const index = json.meshes.push(meshDef) - 1;
|
|
6556
|
+
cache.meshes.set(meshCacheKey, index);
|
|
6557
|
+
return index;
|
|
6558
|
+
}
|
|
6559
|
+
/**
|
|
6560
|
+
* If a vertex attribute with a
|
|
6561
|
+
* [non-standard data type](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview)
|
|
6562
|
+
* is used, it is checked whether it is a valid data type according to the
|
|
6563
|
+
* [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md)
|
|
6564
|
+
* extension.
|
|
6565
|
+
* In this case the extension is automatically added to the list of used extensions.
|
|
6566
|
+
*
|
|
6567
|
+
* @param {string} attributeName
|
|
6568
|
+
* @param {THREE.BufferAttribute} attribute
|
|
6569
|
+
*/
|
|
6570
|
+
detectMeshQuantization(attributeName, attribute) {
|
|
6571
|
+
if (this.extensionsUsed[KHR_MESH_QUANTIZATION]) return;
|
|
6572
|
+
let attrType = void 0;
|
|
6573
|
+
switch (attribute.array.constructor) {
|
|
6574
|
+
case Int8Array:
|
|
6575
|
+
attrType = "byte";
|
|
6576
|
+
break;
|
|
6577
|
+
case Uint8Array:
|
|
6578
|
+
attrType = "unsigned byte";
|
|
6579
|
+
break;
|
|
6580
|
+
case Int16Array:
|
|
6581
|
+
attrType = "short";
|
|
6582
|
+
break;
|
|
6583
|
+
case Uint16Array:
|
|
6584
|
+
attrType = "unsigned short";
|
|
6585
|
+
break;
|
|
6586
|
+
default:
|
|
6587
|
+
return;
|
|
6588
|
+
}
|
|
6589
|
+
if (attribute.normalized) attrType += " normalized";
|
|
6590
|
+
const attrNamePrefix = attributeName.split("_", 1)[0];
|
|
6591
|
+
if (KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix] && KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix].includes(attrType)) {
|
|
6592
|
+
this.extensionsUsed[KHR_MESH_QUANTIZATION] = true;
|
|
6593
|
+
this.extensionsRequired[KHR_MESH_QUANTIZATION] = true;
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6596
|
+
/**
|
|
6597
|
+
* Process camera
|
|
6598
|
+
* @param {THREE.Camera} camera Camera to process
|
|
6599
|
+
* @return {Integer} Index of the processed mesh in the "camera" array
|
|
6600
|
+
*/
|
|
6601
|
+
processCamera(camera) {
|
|
6602
|
+
const json = this.json;
|
|
6603
|
+
if (!json.cameras) json.cameras = [];
|
|
6604
|
+
const isOrtho = camera.isOrthographicCamera;
|
|
6605
|
+
const cameraDef = {
|
|
6606
|
+
type: isOrtho ? "orthographic" : "perspective"
|
|
6607
|
+
};
|
|
6608
|
+
if (isOrtho) {
|
|
6609
|
+
cameraDef.orthographic = {
|
|
6610
|
+
xmag: camera.right * 2,
|
|
6611
|
+
ymag: camera.top * 2,
|
|
6612
|
+
zfar: camera.far <= 0 ? 1e-3 : camera.far,
|
|
6613
|
+
znear: camera.near < 0 ? 0 : camera.near
|
|
6614
|
+
};
|
|
6615
|
+
} else {
|
|
6616
|
+
cameraDef.perspective = {
|
|
6617
|
+
aspectRatio: camera.aspect,
|
|
6618
|
+
yfov: MathUtils2.degToRad(camera.fov),
|
|
6619
|
+
zfar: camera.far <= 0 ? 1e-3 : camera.far,
|
|
6620
|
+
znear: camera.near < 0 ? 0 : camera.near
|
|
6621
|
+
};
|
|
6622
|
+
}
|
|
6623
|
+
if (camera.name !== "") cameraDef.name = camera.type;
|
|
6624
|
+
return json.cameras.push(cameraDef) - 1;
|
|
6625
|
+
}
|
|
6626
|
+
/**
|
|
6627
|
+
* Creates glTF animation entry from AnimationClip object.
|
|
6628
|
+
*
|
|
6629
|
+
* Status:
|
|
6630
|
+
* - Only properties listed in PATH_PROPERTIES may be animated.
|
|
6631
|
+
*
|
|
6632
|
+
* @param {THREE.AnimationClip} clip
|
|
6633
|
+
* @param {THREE.Object3D} root
|
|
6634
|
+
* @return {number|null}
|
|
6635
|
+
*/
|
|
6636
|
+
processAnimation(clip, root) {
|
|
6637
|
+
const json = this.json;
|
|
6638
|
+
const nodeMap = this.nodeMap;
|
|
6639
|
+
if (!json.animations) json.animations = [];
|
|
6640
|
+
clip = GLTFExporter.Utils.mergeMorphTargetTracks(clip.clone(), root);
|
|
6641
|
+
const tracks = clip.tracks;
|
|
6642
|
+
const channels = [];
|
|
6643
|
+
const samplers = [];
|
|
6644
|
+
for (let i = 0; i < tracks.length; ++i) {
|
|
6645
|
+
const track = tracks[i];
|
|
6646
|
+
const trackBinding = PropertyBinding.parseTrackName(track.name);
|
|
6647
|
+
let trackNode = PropertyBinding.findNode(root, trackBinding.nodeName);
|
|
6648
|
+
const trackProperty = PATH_PROPERTIES[trackBinding.propertyName];
|
|
6649
|
+
if (trackBinding.objectName === "bones") {
|
|
6650
|
+
if (trackNode.isSkinnedMesh === true) {
|
|
6651
|
+
trackNode = trackNode.skeleton.getBoneByName(trackBinding.objectIndex);
|
|
6652
|
+
} else {
|
|
6653
|
+
trackNode = void 0;
|
|
6654
|
+
}
|
|
6655
|
+
}
|
|
6656
|
+
if (!trackNode || !trackProperty) {
|
|
6657
|
+
console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
|
|
6658
|
+
return null;
|
|
6659
|
+
}
|
|
6660
|
+
const inputItemSize = 1;
|
|
6661
|
+
let outputItemSize = track.values.length / track.times.length;
|
|
6662
|
+
if (trackProperty === PATH_PROPERTIES.morphTargetInfluences) {
|
|
6663
|
+
outputItemSize /= trackNode.morphTargetInfluences.length;
|
|
6664
|
+
}
|
|
6665
|
+
let interpolation;
|
|
6666
|
+
if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) {
|
|
6667
|
+
interpolation = "CUBICSPLINE";
|
|
6668
|
+
outputItemSize /= 3;
|
|
6669
|
+
} else if (track.getInterpolation() === InterpolateDiscrete) {
|
|
6670
|
+
interpolation = "STEP";
|
|
6671
|
+
} else {
|
|
6672
|
+
interpolation = "LINEAR";
|
|
6673
|
+
}
|
|
6674
|
+
samplers.push({
|
|
6675
|
+
input: this.processAccessor(new BufferAttribute3(track.times, inputItemSize)),
|
|
6676
|
+
output: this.processAccessor(new BufferAttribute3(track.values, outputItemSize)),
|
|
6677
|
+
interpolation
|
|
6678
|
+
});
|
|
6679
|
+
channels.push({
|
|
6680
|
+
sampler: samplers.length - 1,
|
|
6681
|
+
target: {
|
|
6682
|
+
node: nodeMap.get(trackNode),
|
|
6683
|
+
path: trackProperty
|
|
6684
|
+
}
|
|
6685
|
+
});
|
|
6686
|
+
}
|
|
6687
|
+
json.animations.push({
|
|
6688
|
+
name: clip.name || "clip_" + json.animations.length,
|
|
6689
|
+
samplers,
|
|
6690
|
+
channels
|
|
6691
|
+
});
|
|
6692
|
+
return json.animations.length - 1;
|
|
6693
|
+
}
|
|
6694
|
+
/**
|
|
6695
|
+
* @param {THREE.Object3D} object
|
|
6696
|
+
* @return {number|null}
|
|
6697
|
+
*/
|
|
6698
|
+
processSkin(object) {
|
|
6699
|
+
const json = this.json;
|
|
6700
|
+
const nodeMap = this.nodeMap;
|
|
6701
|
+
const node = json.nodes[nodeMap.get(object)];
|
|
6702
|
+
const skeleton = object.skeleton;
|
|
6703
|
+
if (skeleton === void 0) return null;
|
|
6704
|
+
const rootJoint = object.skeleton.bones[0];
|
|
6705
|
+
if (rootJoint === void 0) return null;
|
|
6706
|
+
const joints = [];
|
|
6707
|
+
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
6708
|
+
const temporaryBoneInverse = new Matrix44();
|
|
6709
|
+
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
6710
|
+
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
6711
|
+
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
6712
|
+
temporaryBoneInverse.multiply(object.bindMatrix).toArray(inverseBindMatrices, i * 16);
|
|
6713
|
+
}
|
|
6714
|
+
if (json.skins === void 0) json.skins = [];
|
|
6715
|
+
json.skins.push({
|
|
6716
|
+
inverseBindMatrices: this.processAccessor(new BufferAttribute3(inverseBindMatrices, 16)),
|
|
6717
|
+
joints,
|
|
6718
|
+
skeleton: nodeMap.get(rootJoint)
|
|
6719
|
+
});
|
|
6720
|
+
const skinIndex = node.skin = json.skins.length - 1;
|
|
6721
|
+
return skinIndex;
|
|
6722
|
+
}
|
|
6723
|
+
/**
|
|
6724
|
+
* Process Object3D node
|
|
6725
|
+
* @param {THREE.Object3D} node Object3D to processNode
|
|
6726
|
+
* @return {Integer} Index of the node in the nodes list
|
|
6727
|
+
*/
|
|
6728
|
+
processNode(object) {
|
|
6729
|
+
const json = this.json;
|
|
6730
|
+
const options = this.options;
|
|
6731
|
+
const nodeMap = this.nodeMap;
|
|
6732
|
+
if (!json.nodes) json.nodes = [];
|
|
6733
|
+
const nodeDef = {};
|
|
6734
|
+
if (options.trs) {
|
|
6735
|
+
const rotation = object.quaternion.toArray();
|
|
6736
|
+
const position = object.position.toArray();
|
|
6737
|
+
const scale = object.scale.toArray();
|
|
6738
|
+
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
6739
|
+
nodeDef.rotation = rotation;
|
|
6740
|
+
}
|
|
6741
|
+
if (!equalArray(position, [0, 0, 0])) {
|
|
6742
|
+
nodeDef.translation = position;
|
|
6743
|
+
}
|
|
6744
|
+
if (!equalArray(scale, [1, 1, 1])) {
|
|
6745
|
+
nodeDef.scale = scale;
|
|
6746
|
+
}
|
|
6747
|
+
} else {
|
|
6748
|
+
if (object.matrixAutoUpdate) {
|
|
6749
|
+
object.updateMatrix();
|
|
6750
|
+
}
|
|
6751
|
+
if (isIdentityMatrix(object.matrix) === false) {
|
|
6752
|
+
nodeDef.matrix = object.matrix.elements;
|
|
6753
|
+
}
|
|
6754
|
+
}
|
|
6755
|
+
if (object.name !== "") nodeDef.name = String(object.name);
|
|
6756
|
+
this.serializeUserData(object, nodeDef);
|
|
6757
|
+
if (object.isMesh || object.isLine || object.isPoints) {
|
|
6758
|
+
const meshIndex = this.processMesh(object);
|
|
6759
|
+
if (meshIndex !== null) nodeDef.mesh = meshIndex;
|
|
6760
|
+
} else if (object.isCamera) {
|
|
6761
|
+
nodeDef.camera = this.processCamera(object);
|
|
6762
|
+
}
|
|
6763
|
+
if (object.isSkinnedMesh) this.skins.push(object);
|
|
6764
|
+
if (object.children.length > 0) {
|
|
6765
|
+
const children = [];
|
|
6766
|
+
for (let i = 0, l = object.children.length; i < l; i++) {
|
|
6767
|
+
const child = object.children[i];
|
|
6768
|
+
if (child.visible || options.onlyVisible === false) {
|
|
6769
|
+
const nodeIndex2 = this.processNode(child);
|
|
6770
|
+
if (nodeIndex2 !== null) children.push(nodeIndex2);
|
|
6771
|
+
}
|
|
6772
|
+
}
|
|
6773
|
+
if (children.length > 0) nodeDef.children = children;
|
|
6774
|
+
}
|
|
6775
|
+
this._invokeAll(function(ext) {
|
|
6776
|
+
ext.writeNode && ext.writeNode(object, nodeDef);
|
|
6777
|
+
});
|
|
6778
|
+
const nodeIndex = json.nodes.push(nodeDef) - 1;
|
|
6779
|
+
nodeMap.set(object, nodeIndex);
|
|
6780
|
+
return nodeIndex;
|
|
6781
|
+
}
|
|
6782
|
+
/**
|
|
6783
|
+
* Process Scene
|
|
6784
|
+
* @param {Scene} node Scene to process
|
|
6785
|
+
*/
|
|
6786
|
+
processScene(scene) {
|
|
6787
|
+
const json = this.json;
|
|
6788
|
+
const options = this.options;
|
|
6789
|
+
if (!json.scenes) {
|
|
6790
|
+
json.scenes = [];
|
|
6791
|
+
json.scene = 0;
|
|
6792
|
+
}
|
|
6793
|
+
const sceneDef = {};
|
|
6794
|
+
if (scene.name !== "") sceneDef.name = scene.name;
|
|
6795
|
+
json.scenes.push(sceneDef);
|
|
6796
|
+
const nodes = [];
|
|
6797
|
+
for (let i = 0, l = scene.children.length; i < l; i++) {
|
|
6798
|
+
const child = scene.children[i];
|
|
6799
|
+
if (child.visible || options.onlyVisible === false) {
|
|
6800
|
+
const nodeIndex = this.processNode(child);
|
|
6801
|
+
if (nodeIndex !== null) nodes.push(nodeIndex);
|
|
6802
|
+
}
|
|
6803
|
+
}
|
|
6804
|
+
if (nodes.length > 0) sceneDef.nodes = nodes;
|
|
6805
|
+
this.serializeUserData(scene, sceneDef);
|
|
6806
|
+
}
|
|
6807
|
+
/**
|
|
6808
|
+
* Creates a Scene to hold a list of objects and parse it
|
|
6809
|
+
* @param {Array} objects List of objects to process
|
|
6810
|
+
*/
|
|
6811
|
+
processObjects(objects) {
|
|
6812
|
+
const scene = new Scene3();
|
|
6813
|
+
scene.name = "AuxScene";
|
|
6814
|
+
for (let i = 0; i < objects.length; i++) {
|
|
6815
|
+
scene.children.push(objects[i]);
|
|
6816
|
+
}
|
|
6817
|
+
this.processScene(scene);
|
|
6818
|
+
}
|
|
6819
|
+
/**
|
|
6820
|
+
* @param {THREE.Object3D|Array<THREE.Object3D>} input
|
|
6821
|
+
*/
|
|
6822
|
+
processInput(input) {
|
|
6823
|
+
const options = this.options;
|
|
6824
|
+
input = input instanceof Array ? input : [input];
|
|
6825
|
+
this._invokeAll(function(ext) {
|
|
6826
|
+
ext.beforeParse && ext.beforeParse(input);
|
|
6827
|
+
});
|
|
6828
|
+
const objectsWithoutScene = [];
|
|
6829
|
+
for (let i = 0; i < input.length; i++) {
|
|
6830
|
+
if (input[i] instanceof Scene3) {
|
|
6831
|
+
this.processScene(input[i]);
|
|
6832
|
+
} else {
|
|
6833
|
+
objectsWithoutScene.push(input[i]);
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
|
|
6837
|
+
for (let i = 0; i < this.skins.length; ++i) {
|
|
6838
|
+
this.processSkin(this.skins[i]);
|
|
6839
|
+
}
|
|
6840
|
+
for (let i = 0; i < options.animations.length; ++i) {
|
|
6841
|
+
this.processAnimation(options.animations[i], input[0]);
|
|
6842
|
+
}
|
|
6843
|
+
this._invokeAll(function(ext) {
|
|
6844
|
+
ext.afterParse && ext.afterParse(input);
|
|
6845
|
+
});
|
|
6846
|
+
}
|
|
6847
|
+
_invokeAll(func) {
|
|
6848
|
+
for (let i = 0, il = this.plugins.length; i < il; i++) {
|
|
6849
|
+
func(this.plugins[i]);
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
};
|
|
6853
|
+
var GLTFLightExtension = class {
|
|
6854
|
+
constructor(writer) {
|
|
6855
|
+
this.writer = writer;
|
|
6856
|
+
this.name = "KHR_lights_punctual";
|
|
6857
|
+
}
|
|
6858
|
+
writeNode(light, nodeDef) {
|
|
6859
|
+
if (!light.isLight) return;
|
|
6860
|
+
if (!light.isDirectionalLight && !light.isPointLight && !light.isSpotLight) {
|
|
6861
|
+
console.warn("THREE.GLTFExporter: Only directional, point, and spot lights are supported.", light);
|
|
6862
|
+
return;
|
|
6863
|
+
}
|
|
6864
|
+
const writer = this.writer;
|
|
6865
|
+
const json = writer.json;
|
|
6866
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6867
|
+
const lightDef = {};
|
|
6868
|
+
if (light.name) lightDef.name = light.name;
|
|
6869
|
+
lightDef.color = light.color.toArray();
|
|
6870
|
+
lightDef.intensity = light.intensity;
|
|
6871
|
+
if (light.isDirectionalLight) {
|
|
6872
|
+
lightDef.type = "directional";
|
|
6873
|
+
} else if (light.isPointLight) {
|
|
6874
|
+
lightDef.type = "point";
|
|
6875
|
+
if (light.distance > 0) lightDef.range = light.distance;
|
|
6876
|
+
} else if (light.isSpotLight) {
|
|
6877
|
+
lightDef.type = "spot";
|
|
6878
|
+
if (light.distance > 0) lightDef.range = light.distance;
|
|
6879
|
+
lightDef.spot = {};
|
|
6880
|
+
lightDef.spot.innerConeAngle = (1 - light.penumbra) * light.angle;
|
|
6881
|
+
lightDef.spot.outerConeAngle = light.angle;
|
|
6882
|
+
}
|
|
6883
|
+
if (light.decay !== void 0 && light.decay !== 2) {
|
|
6884
|
+
console.warn("THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, and expects light.decay=2.");
|
|
6885
|
+
}
|
|
6886
|
+
if (light.target && (light.target.parent !== light || light.target.position.x !== 0 || light.target.position.y !== 0 || light.target.position.z !== -1)) {
|
|
6887
|
+
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.");
|
|
6888
|
+
}
|
|
6889
|
+
if (!extensionsUsed[this.name]) {
|
|
6890
|
+
json.extensions = json.extensions || {};
|
|
6891
|
+
json.extensions[this.name] = { lights: [] };
|
|
6892
|
+
extensionsUsed[this.name] = true;
|
|
6893
|
+
}
|
|
6894
|
+
const lights = json.extensions[this.name].lights;
|
|
6895
|
+
lights.push(lightDef);
|
|
6896
|
+
nodeDef.extensions = nodeDef.extensions || {};
|
|
6897
|
+
nodeDef.extensions[this.name] = { light: lights.length - 1 };
|
|
6898
|
+
}
|
|
6899
|
+
};
|
|
6900
|
+
var GLTFMaterialsUnlitExtension = class {
|
|
6901
|
+
constructor(writer) {
|
|
6902
|
+
this.writer = writer;
|
|
6903
|
+
this.name = "KHR_materials_unlit";
|
|
6904
|
+
}
|
|
6905
|
+
writeMaterial(material, materialDef) {
|
|
6906
|
+
if (!material.isMeshBasicMaterial) return;
|
|
6907
|
+
const writer = this.writer;
|
|
6908
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6909
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6910
|
+
materialDef.extensions[this.name] = {};
|
|
6911
|
+
extensionsUsed[this.name] = true;
|
|
6912
|
+
materialDef.pbrMetallicRoughness.metallicFactor = 0;
|
|
6913
|
+
materialDef.pbrMetallicRoughness.roughnessFactor = 0.9;
|
|
6914
|
+
}
|
|
6915
|
+
};
|
|
6916
|
+
var GLTFMaterialsClearcoatExtension = class {
|
|
6917
|
+
constructor(writer) {
|
|
6918
|
+
this.writer = writer;
|
|
6919
|
+
this.name = "KHR_materials_clearcoat";
|
|
6920
|
+
}
|
|
6921
|
+
writeMaterial(material, materialDef) {
|
|
6922
|
+
if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
|
|
6923
|
+
const writer = this.writer;
|
|
6924
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6925
|
+
const extensionDef = {};
|
|
6926
|
+
extensionDef.clearcoatFactor = material.clearcoat;
|
|
6927
|
+
if (material.clearcoatMap) {
|
|
6928
|
+
const clearcoatMapDef = {
|
|
6929
|
+
index: writer.processTexture(material.clearcoatMap),
|
|
6930
|
+
texCoord: material.clearcoatMap.channel
|
|
6931
|
+
};
|
|
6932
|
+
writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
|
|
6933
|
+
extensionDef.clearcoatTexture = clearcoatMapDef;
|
|
6934
|
+
}
|
|
6935
|
+
extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
|
|
6936
|
+
if (material.clearcoatRoughnessMap) {
|
|
6937
|
+
const clearcoatRoughnessMapDef = {
|
|
6938
|
+
index: writer.processTexture(material.clearcoatRoughnessMap),
|
|
6939
|
+
texCoord: material.clearcoatRoughnessMap.channel
|
|
6940
|
+
};
|
|
6941
|
+
writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
|
|
6942
|
+
extensionDef.clearcoatRoughnessTexture = clearcoatRoughnessMapDef;
|
|
6943
|
+
}
|
|
6944
|
+
if (material.clearcoatNormalMap) {
|
|
6945
|
+
const clearcoatNormalMapDef = {
|
|
6946
|
+
index: writer.processTexture(material.clearcoatNormalMap),
|
|
6947
|
+
texCoord: material.clearcoatNormalMap.channel
|
|
6948
|
+
};
|
|
6949
|
+
writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
|
|
6950
|
+
extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
|
|
6951
|
+
}
|
|
6952
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6953
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
6954
|
+
extensionsUsed[this.name] = true;
|
|
6955
|
+
}
|
|
6956
|
+
};
|
|
6957
|
+
var GLTFMaterialsIridescenceExtension = class {
|
|
6958
|
+
constructor(writer) {
|
|
6959
|
+
this.writer = writer;
|
|
6960
|
+
this.name = "KHR_materials_iridescence";
|
|
6961
|
+
}
|
|
6962
|
+
writeMaterial(material, materialDef) {
|
|
6963
|
+
if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
|
|
6964
|
+
const writer = this.writer;
|
|
6965
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
6966
|
+
const extensionDef = {};
|
|
6967
|
+
extensionDef.iridescenceFactor = material.iridescence;
|
|
6968
|
+
if (material.iridescenceMap) {
|
|
6969
|
+
const iridescenceMapDef = {
|
|
6970
|
+
index: writer.processTexture(material.iridescenceMap),
|
|
6971
|
+
texCoord: material.iridescenceMap.channel
|
|
6972
|
+
};
|
|
6973
|
+
writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
|
|
6974
|
+
extensionDef.iridescenceTexture = iridescenceMapDef;
|
|
6975
|
+
}
|
|
6976
|
+
extensionDef.iridescenceIor = material.iridescenceIOR;
|
|
6977
|
+
extensionDef.iridescenceThicknessMinimum = material.iridescenceThicknessRange[0];
|
|
6978
|
+
extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
|
|
6979
|
+
if (material.iridescenceThicknessMap) {
|
|
6980
|
+
const iridescenceThicknessMapDef = {
|
|
6981
|
+
index: writer.processTexture(material.iridescenceThicknessMap),
|
|
6982
|
+
texCoord: material.iridescenceThicknessMap.channel
|
|
6983
|
+
};
|
|
6984
|
+
writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
|
|
6985
|
+
extensionDef.iridescenceThicknessTexture = iridescenceThicknessMapDef;
|
|
6986
|
+
}
|
|
6987
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
6988
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
6989
|
+
extensionsUsed[this.name] = true;
|
|
6990
|
+
}
|
|
6991
|
+
};
|
|
6992
|
+
var GLTFMaterialsTransmissionExtension = class {
|
|
6993
|
+
constructor(writer) {
|
|
6994
|
+
this.writer = writer;
|
|
6995
|
+
this.name = "KHR_materials_transmission";
|
|
6996
|
+
}
|
|
6997
|
+
writeMaterial(material, materialDef) {
|
|
6998
|
+
if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
|
|
6999
|
+
const writer = this.writer;
|
|
7000
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7001
|
+
const extensionDef = {};
|
|
7002
|
+
extensionDef.transmissionFactor = material.transmission;
|
|
7003
|
+
if (material.transmissionMap) {
|
|
7004
|
+
const transmissionMapDef = {
|
|
7005
|
+
index: writer.processTexture(material.transmissionMap),
|
|
7006
|
+
texCoord: material.transmissionMap.channel
|
|
7007
|
+
};
|
|
7008
|
+
writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
|
|
7009
|
+
extensionDef.transmissionTexture = transmissionMapDef;
|
|
7010
|
+
}
|
|
7011
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7012
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7013
|
+
extensionsUsed[this.name] = true;
|
|
7014
|
+
}
|
|
7015
|
+
};
|
|
7016
|
+
var GLTFMaterialsVolumeExtension = class {
|
|
7017
|
+
constructor(writer) {
|
|
7018
|
+
this.writer = writer;
|
|
7019
|
+
this.name = "KHR_materials_volume";
|
|
7020
|
+
}
|
|
7021
|
+
writeMaterial(material, materialDef) {
|
|
7022
|
+
if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
|
|
7023
|
+
const writer = this.writer;
|
|
7024
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7025
|
+
const extensionDef = {};
|
|
7026
|
+
extensionDef.thicknessFactor = material.thickness;
|
|
7027
|
+
if (material.thicknessMap) {
|
|
7028
|
+
const thicknessMapDef = {
|
|
7029
|
+
index: writer.processTexture(material.thicknessMap),
|
|
7030
|
+
texCoord: material.thicknessMap.channel
|
|
7031
|
+
};
|
|
7032
|
+
writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
|
|
7033
|
+
extensionDef.thicknessTexture = thicknessMapDef;
|
|
7034
|
+
}
|
|
7035
|
+
extensionDef.attenuationDistance = material.attenuationDistance;
|
|
7036
|
+
extensionDef.attenuationColor = material.attenuationColor.toArray();
|
|
7037
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7038
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7039
|
+
extensionsUsed[this.name] = true;
|
|
7040
|
+
}
|
|
7041
|
+
};
|
|
7042
|
+
var GLTFMaterialsIorExtension = class {
|
|
7043
|
+
constructor(writer) {
|
|
7044
|
+
this.writer = writer;
|
|
7045
|
+
this.name = "KHR_materials_ior";
|
|
7046
|
+
}
|
|
7047
|
+
writeMaterial(material, materialDef) {
|
|
7048
|
+
if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
|
|
7049
|
+
const writer = this.writer;
|
|
7050
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7051
|
+
const extensionDef = {};
|
|
7052
|
+
extensionDef.ior = material.ior;
|
|
7053
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7054
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7055
|
+
extensionsUsed[this.name] = true;
|
|
7056
|
+
}
|
|
7057
|
+
};
|
|
7058
|
+
var GLTFMaterialsSpecularExtension = class {
|
|
7059
|
+
constructor(writer) {
|
|
7060
|
+
this.writer = writer;
|
|
7061
|
+
this.name = "KHR_materials_specular";
|
|
7062
|
+
}
|
|
7063
|
+
writeMaterial(material, materialDef) {
|
|
7064
|
+
if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
|
|
7065
|
+
const writer = this.writer;
|
|
7066
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7067
|
+
const extensionDef = {};
|
|
7068
|
+
if (material.specularIntensityMap) {
|
|
7069
|
+
const specularIntensityMapDef = {
|
|
7070
|
+
index: writer.processTexture(material.specularIntensityMap),
|
|
7071
|
+
texCoord: material.specularIntensityMap.channel
|
|
7072
|
+
};
|
|
7073
|
+
writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
|
|
7074
|
+
extensionDef.specularTexture = specularIntensityMapDef;
|
|
7075
|
+
}
|
|
7076
|
+
if (material.specularColorMap) {
|
|
7077
|
+
const specularColorMapDef = {
|
|
7078
|
+
index: writer.processTexture(material.specularColorMap),
|
|
7079
|
+
texCoord: material.specularColorMap.channel
|
|
7080
|
+
};
|
|
7081
|
+
writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
|
|
7082
|
+
extensionDef.specularColorTexture = specularColorMapDef;
|
|
7083
|
+
}
|
|
7084
|
+
extensionDef.specularFactor = material.specularIntensity;
|
|
7085
|
+
extensionDef.specularColorFactor = material.specularColor.toArray();
|
|
7086
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7087
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7088
|
+
extensionsUsed[this.name] = true;
|
|
7089
|
+
}
|
|
7090
|
+
};
|
|
7091
|
+
var GLTFMaterialsSheenExtension = class {
|
|
7092
|
+
constructor(writer) {
|
|
7093
|
+
this.writer = writer;
|
|
7094
|
+
this.name = "KHR_materials_sheen";
|
|
7095
|
+
}
|
|
7096
|
+
writeMaterial(material, materialDef) {
|
|
7097
|
+
if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
|
|
7098
|
+
const writer = this.writer;
|
|
7099
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7100
|
+
const extensionDef = {};
|
|
7101
|
+
if (material.sheenRoughnessMap) {
|
|
7102
|
+
const sheenRoughnessMapDef = {
|
|
7103
|
+
index: writer.processTexture(material.sheenRoughnessMap),
|
|
7104
|
+
texCoord: material.sheenRoughnessMap.channel
|
|
7105
|
+
};
|
|
7106
|
+
writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
|
|
7107
|
+
extensionDef.sheenRoughnessTexture = sheenRoughnessMapDef;
|
|
7108
|
+
}
|
|
7109
|
+
if (material.sheenColorMap) {
|
|
7110
|
+
const sheenColorMapDef = {
|
|
7111
|
+
index: writer.processTexture(material.sheenColorMap),
|
|
7112
|
+
texCoord: material.sheenColorMap.channel
|
|
7113
|
+
};
|
|
7114
|
+
writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
|
|
7115
|
+
extensionDef.sheenColorTexture = sheenColorMapDef;
|
|
7116
|
+
}
|
|
7117
|
+
extensionDef.sheenRoughnessFactor = material.sheenRoughness;
|
|
7118
|
+
extensionDef.sheenColorFactor = material.sheenColor.toArray();
|
|
7119
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7120
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7121
|
+
extensionsUsed[this.name] = true;
|
|
7122
|
+
}
|
|
7123
|
+
};
|
|
7124
|
+
var GLTFMaterialsAnisotropyExtension = class {
|
|
7125
|
+
constructor(writer) {
|
|
7126
|
+
this.writer = writer;
|
|
7127
|
+
this.name = "KHR_materials_anisotropy";
|
|
7128
|
+
}
|
|
7129
|
+
writeMaterial(material, materialDef) {
|
|
7130
|
+
if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
|
|
7131
|
+
const writer = this.writer;
|
|
7132
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7133
|
+
const extensionDef = {};
|
|
7134
|
+
if (material.anisotropyMap) {
|
|
7135
|
+
const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
|
|
7136
|
+
writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
|
|
7137
|
+
extensionDef.anisotropyTexture = anisotropyMapDef;
|
|
7138
|
+
}
|
|
7139
|
+
extensionDef.anisotropyStrength = material.anisotropy;
|
|
7140
|
+
extensionDef.anisotropyRotation = material.anisotropyRotation;
|
|
7141
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7142
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7143
|
+
extensionsUsed[this.name] = true;
|
|
7144
|
+
}
|
|
7145
|
+
};
|
|
7146
|
+
var GLTFMaterialsEmissiveStrengthExtension = class {
|
|
7147
|
+
constructor(writer) {
|
|
7148
|
+
this.writer = writer;
|
|
7149
|
+
this.name = "KHR_materials_emissive_strength";
|
|
7150
|
+
}
|
|
7151
|
+
writeMaterial(material, materialDef) {
|
|
7152
|
+
if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
|
|
7153
|
+
const writer = this.writer;
|
|
7154
|
+
const extensionsUsed = writer.extensionsUsed;
|
|
7155
|
+
const extensionDef = {};
|
|
7156
|
+
extensionDef.emissiveStrength = material.emissiveIntensity;
|
|
7157
|
+
materialDef.extensions = materialDef.extensions || {};
|
|
7158
|
+
materialDef.extensions[this.name] = extensionDef;
|
|
7159
|
+
extensionsUsed[this.name] = true;
|
|
7160
|
+
}
|
|
7161
|
+
};
|
|
7162
|
+
var GLTFMeshGpuInstancing = class {
|
|
7163
|
+
constructor(writer) {
|
|
7164
|
+
this.writer = writer;
|
|
7165
|
+
this.name = "EXT_mesh_gpu_instancing";
|
|
7166
|
+
}
|
|
7167
|
+
writeNode(object, nodeDef) {
|
|
7168
|
+
if (!object.isInstancedMesh) return;
|
|
7169
|
+
const writer = this.writer;
|
|
7170
|
+
const mesh = object;
|
|
7171
|
+
const translationAttr = new Float32Array(mesh.count * 3);
|
|
7172
|
+
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
7173
|
+
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
7174
|
+
const matrix = new Matrix44();
|
|
7175
|
+
const position = new Vector38();
|
|
7176
|
+
const quaternion = new Quaternion4();
|
|
7177
|
+
const scale = new Vector38();
|
|
7178
|
+
for (let i = 0; i < mesh.count; i++) {
|
|
7179
|
+
mesh.getMatrixAt(i, matrix);
|
|
7180
|
+
matrix.decompose(position, quaternion, scale);
|
|
7181
|
+
position.toArray(translationAttr, i * 3);
|
|
7182
|
+
quaternion.toArray(rotationAttr, i * 4);
|
|
7183
|
+
scale.toArray(scaleAttr, i * 3);
|
|
7184
|
+
}
|
|
7185
|
+
const attributes = {
|
|
7186
|
+
TRANSLATION: writer.processAccessor(new BufferAttribute3(translationAttr, 3)),
|
|
7187
|
+
ROTATION: writer.processAccessor(new BufferAttribute3(rotationAttr, 4)),
|
|
7188
|
+
SCALE: writer.processAccessor(new BufferAttribute3(scaleAttr, 3))
|
|
7189
|
+
};
|
|
7190
|
+
if (mesh.instanceColor)
|
|
7191
|
+
attributes._COLOR_0 = writer.processAccessor(mesh.instanceColor);
|
|
7192
|
+
nodeDef.extensions = nodeDef.extensions || {};
|
|
7193
|
+
nodeDef.extensions[this.name] = { attributes };
|
|
7194
|
+
writer.extensionsUsed[this.name] = true;
|
|
7195
|
+
writer.extensionsRequired[this.name] = true;
|
|
7196
|
+
}
|
|
7197
|
+
};
|
|
7198
|
+
GLTFExporter.Utils = {
|
|
7199
|
+
insertKeyframe: function(track, time) {
|
|
7200
|
+
const tolerance = 1e-3;
|
|
7201
|
+
const valueSize = track.getValueSize();
|
|
7202
|
+
const times = new track.TimeBufferType(track.times.length + 1);
|
|
7203
|
+
const values = new track.ValueBufferType(track.values.length + valueSize);
|
|
7204
|
+
const interpolant = track.createInterpolant(new track.ValueBufferType(valueSize));
|
|
7205
|
+
let index;
|
|
7206
|
+
if (track.times.length === 0) {
|
|
7207
|
+
times[0] = time;
|
|
7208
|
+
for (let i = 0; i < valueSize; i++) {
|
|
7209
|
+
values[i] = 0;
|
|
7210
|
+
}
|
|
7211
|
+
index = 0;
|
|
7212
|
+
} else if (time < track.times[0]) {
|
|
7213
|
+
if (Math.abs(track.times[0] - time) < tolerance) return 0;
|
|
7214
|
+
times[0] = time;
|
|
7215
|
+
times.set(track.times, 1);
|
|
7216
|
+
values.set(interpolant.evaluate(time), 0);
|
|
7217
|
+
values.set(track.values, valueSize);
|
|
7218
|
+
index = 0;
|
|
7219
|
+
} else if (time > track.times[track.times.length - 1]) {
|
|
7220
|
+
if (Math.abs(track.times[track.times.length - 1] - time) < tolerance) {
|
|
7221
|
+
return track.times.length - 1;
|
|
7222
|
+
}
|
|
7223
|
+
times[times.length - 1] = time;
|
|
7224
|
+
times.set(track.times, 0);
|
|
7225
|
+
values.set(track.values, 0);
|
|
7226
|
+
values.set(interpolant.evaluate(time), track.values.length);
|
|
7227
|
+
index = times.length - 1;
|
|
7228
|
+
} else {
|
|
7229
|
+
for (let i = 0; i < track.times.length; i++) {
|
|
7230
|
+
if (Math.abs(track.times[i] - time) < tolerance) return i;
|
|
7231
|
+
if (track.times[i] < time && track.times[i + 1] > time) {
|
|
7232
|
+
times.set(track.times.slice(0, i + 1), 0);
|
|
7233
|
+
times[i + 1] = time;
|
|
7234
|
+
times.set(track.times.slice(i + 1), i + 2);
|
|
7235
|
+
values.set(track.values.slice(0, (i + 1) * valueSize), 0);
|
|
7236
|
+
values.set(interpolant.evaluate(time), (i + 1) * valueSize);
|
|
7237
|
+
values.set(track.values.slice((i + 1) * valueSize), (i + 2) * valueSize);
|
|
7238
|
+
index = i + 1;
|
|
7239
|
+
break;
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
}
|
|
7243
|
+
track.times = times;
|
|
7244
|
+
track.values = values;
|
|
7245
|
+
return index;
|
|
7246
|
+
},
|
|
7247
|
+
mergeMorphTargetTracks: function(clip, root) {
|
|
7248
|
+
const tracks = [];
|
|
7249
|
+
const mergedTracks = {};
|
|
7250
|
+
const sourceTracks = clip.tracks;
|
|
7251
|
+
for (let i = 0; i < sourceTracks.length; ++i) {
|
|
7252
|
+
let sourceTrack = sourceTracks[i];
|
|
7253
|
+
const sourceTrackBinding = PropertyBinding.parseTrackName(sourceTrack.name);
|
|
7254
|
+
const sourceTrackNode = PropertyBinding.findNode(root, sourceTrackBinding.nodeName);
|
|
7255
|
+
if (sourceTrackBinding.propertyName !== "morphTargetInfluences" || sourceTrackBinding.propertyIndex === void 0) {
|
|
7256
|
+
tracks.push(sourceTrack);
|
|
7257
|
+
continue;
|
|
7258
|
+
}
|
|
7259
|
+
if (sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete && sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear) {
|
|
7260
|
+
if (sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) {
|
|
7261
|
+
throw new Error("THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.");
|
|
7262
|
+
}
|
|
7263
|
+
console.warn("THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.");
|
|
7264
|
+
sourceTrack = sourceTrack.clone();
|
|
7265
|
+
sourceTrack.setInterpolation(InterpolateLinear);
|
|
7266
|
+
}
|
|
7267
|
+
const targetCount = sourceTrackNode.morphTargetInfluences.length;
|
|
7268
|
+
const targetIndex = sourceTrackNode.morphTargetDictionary[sourceTrackBinding.propertyIndex];
|
|
7269
|
+
if (targetIndex === void 0) {
|
|
7270
|
+
throw new Error("THREE.GLTFExporter: Morph target name not found: " + sourceTrackBinding.propertyIndex);
|
|
7271
|
+
}
|
|
7272
|
+
let mergedTrack;
|
|
7273
|
+
if (mergedTracks[sourceTrackNode.uuid] === void 0) {
|
|
7274
|
+
mergedTrack = sourceTrack.clone();
|
|
7275
|
+
const values = new mergedTrack.ValueBufferType(targetCount * mergedTrack.times.length);
|
|
7276
|
+
for (let j = 0; j < mergedTrack.times.length; j++) {
|
|
7277
|
+
values[j * targetCount + targetIndex] = mergedTrack.values[j];
|
|
7278
|
+
}
|
|
7279
|
+
mergedTrack.name = (sourceTrackBinding.nodeName || "") + ".morphTargetInfluences";
|
|
7280
|
+
mergedTrack.values = values;
|
|
7281
|
+
mergedTracks[sourceTrackNode.uuid] = mergedTrack;
|
|
7282
|
+
tracks.push(mergedTrack);
|
|
7283
|
+
continue;
|
|
7284
|
+
}
|
|
7285
|
+
const sourceInterpolant = sourceTrack.createInterpolant(new sourceTrack.ValueBufferType(1));
|
|
7286
|
+
mergedTrack = mergedTracks[sourceTrackNode.uuid];
|
|
7287
|
+
for (let j = 0; j < mergedTrack.times.length; j++) {
|
|
7288
|
+
mergedTrack.values[j * targetCount + targetIndex] = sourceInterpolant.evaluate(mergedTrack.times[j]);
|
|
7289
|
+
}
|
|
7290
|
+
for (let j = 0; j < sourceTrack.times.length; j++) {
|
|
7291
|
+
const keyframeIndex = this.insertKeyframe(mergedTrack, sourceTrack.times[j]);
|
|
7292
|
+
mergedTrack.values[keyframeIndex * targetCount + targetIndex] = sourceTrack.values[j];
|
|
7293
|
+
}
|
|
7294
|
+
}
|
|
7295
|
+
clip.tracks = tracks;
|
|
7296
|
+
return clip;
|
|
7297
|
+
}
|
|
7298
|
+
};
|
|
7299
|
+
|
|
7300
|
+
// src/export/SceneExporter.ts
|
|
7301
|
+
init_MineRenderError();
|
|
7302
|
+
init_DisplayTransforms();
|
|
7303
|
+
init_CanvasCompat();
|
|
7304
|
+
var SceneExporter = class {
|
|
7305
|
+
/** Returns OBJ geometry with normals and UVs; material files and textures are not included. */
|
|
7306
|
+
static toObj(root) {
|
|
7307
|
+
const snapshot = createSnapshot(root, false);
|
|
7308
|
+
try {
|
|
7309
|
+
return new OBJExporter().parse(snapshot.scene);
|
|
7310
|
+
} finally {
|
|
7311
|
+
snapshot.dispose();
|
|
7312
|
+
}
|
|
7313
|
+
}
|
|
7314
|
+
/** Returns PLY geometry with vertex colors and UVs; texture images are not included. */
|
|
7315
|
+
static toPLY(root, options) {
|
|
7316
|
+
const snapshot = createSnapshot(root, false, true);
|
|
7317
|
+
try {
|
|
7318
|
+
const result = new PLYExporter().parse(snapshot.scene, void 0, options);
|
|
7319
|
+
if (result === null) throw new MineRenderError("The scene could not be exported as PLY");
|
|
7320
|
+
return result;
|
|
7321
|
+
} finally {
|
|
7322
|
+
snapshot.dispose();
|
|
7323
|
+
}
|
|
7324
|
+
}
|
|
7325
|
+
/**
|
|
7326
|
+
* Exports a static glTF/GLB snapshot in a browser. Atlas textures and vertex tints are retained;
|
|
7327
|
+
* MineRender's custom directional lighting is not baked into the exported materials.
|
|
7328
|
+
*/
|
|
7329
|
+
static async toGLTF(root, options = {}) {
|
|
7330
|
+
if (typeof document === "undefined" || typeof FileReader === "undefined") {
|
|
7331
|
+
throw new MineRenderError("glTF export requires a browser with canvas and FileReader support");
|
|
7332
|
+
}
|
|
7333
|
+
if (options.maxTextureSize !== void 0 && !(options.maxTextureSize >= 1)) {
|
|
7334
|
+
throw new MineRenderError("maxTextureSize must be at least 1 pixel");
|
|
7335
|
+
}
|
|
7336
|
+
const snapshot = createSnapshot(root, true);
|
|
7337
|
+
try {
|
|
7338
|
+
return await new GLTFExporter().parseAsync(snapshot.scene, {
|
|
7339
|
+
binary: options.binary ?? false,
|
|
7340
|
+
maxTextureSize: options.maxTextureSize ?? Infinity
|
|
7341
|
+
});
|
|
7342
|
+
} finally {
|
|
7343
|
+
snapshot.dispose();
|
|
7344
|
+
}
|
|
7345
|
+
}
|
|
7346
|
+
};
|
|
7347
|
+
function localMatrix(object) {
|
|
7348
|
+
return object.matrixAutoUpdate ? new Matrix45().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
|
|
7349
|
+
}
|
|
7350
|
+
function createSnapshot(root, gltf, bakeColors = false) {
|
|
7351
|
+
const scene = new Scene4();
|
|
7352
|
+
const geometries = [];
|
|
7353
|
+
const materials = [];
|
|
7354
|
+
const textures = [];
|
|
7355
|
+
const textureCopies = /* @__PURE__ */ new Map();
|
|
7356
|
+
const dispose = () => {
|
|
7357
|
+
for (const geometry of geometries) geometry.dispose();
|
|
7358
|
+
for (const material of materials) material.dispose();
|
|
7359
|
+
for (const texture of textures) texture.dispose();
|
|
7360
|
+
};
|
|
7361
|
+
const copyMaterial = (source, geometry) => {
|
|
7362
|
+
let material;
|
|
7363
|
+
const shader = source;
|
|
7364
|
+
if (shader.isShaderMaterial && gltf) {
|
|
7365
|
+
const uniforms = shader.uniforms;
|
|
7366
|
+
if (!uniforms.map?.value?.isTexture || !uniforms.SHADE || !uniforms.BRIGHTNESS || !uniforms.EMISSIVE) {
|
|
7367
|
+
throw new MineRenderError("glTF export does not support this custom ShaderMaterial");
|
|
7368
|
+
}
|
|
7369
|
+
material = new MeshBasicMaterial2({
|
|
7370
|
+
map: uniforms.map.value,
|
|
7371
|
+
vertexColors: source.vertexColors,
|
|
7372
|
+
transparent: source.transparent,
|
|
7373
|
+
side: source.side,
|
|
7374
|
+
alphaTest: 0.01,
|
|
7375
|
+
depthWrite: source.depthWrite
|
|
7376
|
+
});
|
|
7377
|
+
material.name = source.name;
|
|
7378
|
+
} else if (shader.isShaderMaterial) {
|
|
7379
|
+
material = new MeshBasicMaterial2({ vertexColors: source.vertexColors });
|
|
7380
|
+
material.name = source.name;
|
|
7381
|
+
} else {
|
|
7382
|
+
const copySource = Object.create(source);
|
|
7383
|
+
copySource.userData = {};
|
|
7384
|
+
material = source.clone.call(copySource);
|
|
7385
|
+
}
|
|
7386
|
+
materials.push(material);
|
|
7387
|
+
if (gltf) {
|
|
7388
|
+
selectAlphaMode(material, geometry);
|
|
7389
|
+
for (const [key, value] of Object.entries(material)) {
|
|
7390
|
+
if (value?.isDataTexture) {
|
|
7391
|
+
let texture = textureCopies.get(value);
|
|
7392
|
+
if (!texture) {
|
|
7393
|
+
texture = copyDataTexture(value);
|
|
7394
|
+
textureCopies.set(value, texture);
|
|
7395
|
+
textures.push(texture);
|
|
7396
|
+
}
|
|
7397
|
+
material[key] = texture;
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
}
|
|
7401
|
+
return material;
|
|
7402
|
+
};
|
|
7403
|
+
const addMesh = (mesh, world, instanceColor) => {
|
|
7404
|
+
if (world.determinant() === 0 || !mesh.geometry.getAttribute("position")) return;
|
|
7405
|
+
const source = mesh.geometry;
|
|
7406
|
+
const count = source.index?.count ?? source.getAttribute("position").count;
|
|
7407
|
+
const groups = Array.isArray(mesh.material) ? source.groups : [{ start: 0, count, materialIndex: 0 }];
|
|
7408
|
+
for (const group of groups) {
|
|
7409
|
+
const sourceMaterial = Array.isArray(mesh.material) ? mesh.material[group.materialIndex ?? 0] : mesh.material;
|
|
7410
|
+
if (!sourceMaterial?.visible) continue;
|
|
7411
|
+
const start = Math.max(group.start, source.drawRange.start);
|
|
7412
|
+
const end = Math.min(count, group.start + group.count, source.drawRange.start + source.drawRange.count);
|
|
7413
|
+
const indices = [];
|
|
7414
|
+
for (let i = start; i + 2 < end; i += 3) {
|
|
7415
|
+
for (let corner = 0; corner < 3; corner++) indices.push(source.index?.getX(i + corner) ?? i + corner);
|
|
7416
|
+
}
|
|
7417
|
+
if (!indices.length) continue;
|
|
7418
|
+
let geometry = source.clone();
|
|
7419
|
+
geometry.setIndex(indices);
|
|
7420
|
+
if (new Set(indices).size < geometry.getAttribute("position").count) {
|
|
7421
|
+
const compact = geometry.toNonIndexed();
|
|
7422
|
+
geometry.dispose();
|
|
7423
|
+
geometry = compact;
|
|
7424
|
+
}
|
|
7425
|
+
geometries.push(geometry);
|
|
7426
|
+
geometry.userData = {};
|
|
7427
|
+
geometry.clearGroups();
|
|
7428
|
+
geometry.setDrawRange(0, Infinity);
|
|
7429
|
+
DisplayTransforms.apply(geometry, world);
|
|
7430
|
+
const material = copyMaterial(sourceMaterial, geometry);
|
|
7431
|
+
if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
|
|
7432
|
+
if (bakeColors || instanceColor) {
|
|
7433
|
+
const tint = (material.color ?? new Color6()).clone();
|
|
7434
|
+
if (instanceColor) tint.multiply(instanceColor);
|
|
7435
|
+
if (bakeColors) {
|
|
7436
|
+
const original = geometry.getAttribute("color");
|
|
7437
|
+
const colors = new Float32BufferAttribute3(new Float32Array(geometry.getAttribute("position").count * 3), 3);
|
|
7438
|
+
for (let i = 0; i < colors.count; i++) {
|
|
7439
|
+
colors.setXYZ(i, (original?.getX(i) ?? 1) * tint.r, (original?.getY(i) ?? 1) * tint.g, (original?.getZ(i) ?? 1) * tint.b);
|
|
7440
|
+
}
|
|
7441
|
+
geometry.setAttribute("color", colors);
|
|
7442
|
+
} else if (material.color) {
|
|
7443
|
+
material.color.copy(tint);
|
|
7444
|
+
}
|
|
7445
|
+
}
|
|
7446
|
+
const copy = new Mesh5(geometry, material);
|
|
7447
|
+
copy.name = mesh.name;
|
|
7448
|
+
copy.renderOrder = mesh.renderOrder;
|
|
7449
|
+
scene.add(copy);
|
|
7450
|
+
}
|
|
7451
|
+
};
|
|
7452
|
+
const visit = (object, parentWorld) => {
|
|
7453
|
+
if (!object.visible) return;
|
|
7454
|
+
const world = parentWorld.clone().multiply(localMatrix(object));
|
|
7455
|
+
const mesh = object;
|
|
7456
|
+
if (mesh.isMesh) {
|
|
7457
|
+
const instanced = mesh;
|
|
7458
|
+
if (instanced.isInstancedMesh) {
|
|
7459
|
+
for (let i = 0; i < instanced.count; i++) {
|
|
7460
|
+
const matrix = new Matrix45();
|
|
7461
|
+
instanced.getMatrixAt(i, matrix);
|
|
7462
|
+
const color = instanced.instanceColor ? new Color6().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
7463
|
+
addMesh(mesh, world.clone().multiply(matrix), color);
|
|
7464
|
+
}
|
|
7465
|
+
} else {
|
|
7466
|
+
addMesh(mesh, world);
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
7469
|
+
for (const child of object.children) visit(child, world);
|
|
7470
|
+
};
|
|
7471
|
+
try {
|
|
7472
|
+
const ancestors = [];
|
|
7473
|
+
for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
|
|
7474
|
+
const world = new Matrix45();
|
|
7475
|
+
for (const ancestor of ancestors) {
|
|
7476
|
+
if (!ancestor.visible) return { scene, dispose };
|
|
7477
|
+
world.multiply(localMatrix(ancestor));
|
|
7478
|
+
}
|
|
7479
|
+
visit(root, world);
|
|
7480
|
+
return { scene, dispose };
|
|
7481
|
+
} catch (error) {
|
|
7482
|
+
dispose();
|
|
7483
|
+
throw error;
|
|
7484
|
+
}
|
|
7485
|
+
}
|
|
7486
|
+
function selectAlphaMode(material, geometry) {
|
|
7487
|
+
const texture = material.map;
|
|
7488
|
+
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;
|
|
7489
|
+
const uv = geometry.getAttribute(texture.channel === 0 ? "uv" : `uv${texture.channel}`);
|
|
7490
|
+
const colors = geometry.getAttribute("color");
|
|
7491
|
+
if (!uv || material.vertexColors && colors?.itemSize === 4) return;
|
|
7492
|
+
const { data, width, height } = texture.image;
|
|
7493
|
+
if (!data || width < 1 || height < 1 || data.length < width * height * 4) return;
|
|
7494
|
+
const count = geometry.index?.count ?? uv.count;
|
|
7495
|
+
let holes = false;
|
|
7496
|
+
for (let i = 0; i + 2 < count; i += 3) {
|
|
7497
|
+
let minU = Infinity, maxU = -Infinity, minV = Infinity, maxV = -Infinity;
|
|
7498
|
+
for (let corner = 0; corner < 3; corner++) {
|
|
7499
|
+
const index = geometry.index?.getX(i + corner) ?? i + corner;
|
|
7500
|
+
const u = uv.getX(index), v = texture.flipY ? 1 - uv.getY(index) : uv.getY(index);
|
|
7501
|
+
if (!Number.isFinite(u) || !Number.isFinite(v)) return;
|
|
7502
|
+
minU = Math.min(minU, u);
|
|
7503
|
+
maxU = Math.max(maxU, u);
|
|
7504
|
+
minV = Math.min(minV, v);
|
|
7505
|
+
maxV = Math.max(maxV, v);
|
|
7506
|
+
}
|
|
7507
|
+
const minX = Math.max(0, Math.min(width - 1, Math.floor(minU * width)));
|
|
7508
|
+
const maxX = Math.max(minX, Math.min(width - 1, Math.ceil(maxU * width) - 1));
|
|
7509
|
+
const minY = Math.max(0, Math.min(height - 1, Math.floor(minV * height)));
|
|
7510
|
+
const maxY = Math.max(minY, Math.min(height - 1, Math.ceil(maxV * height) - 1));
|
|
7511
|
+
for (let y = minY; y <= maxY; y++) {
|
|
7512
|
+
for (let x = minX; x <= maxX; x++) {
|
|
7513
|
+
const alpha = data[(y * width + x) * 4 + 3];
|
|
7514
|
+
if (alpha === 255) continue;
|
|
7515
|
+
if (alpha !== 0 && alpha / 255 >= material.alphaTest) return;
|
|
7516
|
+
holes = true;
|
|
7517
|
+
}
|
|
7518
|
+
}
|
|
7519
|
+
}
|
|
7520
|
+
material.transparent = false;
|
|
7521
|
+
if (holes && material.alphaTest === 0) material.alphaTest = 1 / 255;
|
|
7522
|
+
}
|
|
7523
|
+
function copyDataTexture(source) {
|
|
7524
|
+
const image = source.image;
|
|
7525
|
+
if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
|
|
7526
|
+
throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
|
|
7527
|
+
}
|
|
7528
|
+
const canvas = createCanvas2(image.width, image.height);
|
|
7529
|
+
const context = canvas.getContext("2d");
|
|
7530
|
+
if (!context) throw new MineRenderError("glTF export could not create a 2D canvas context");
|
|
7531
|
+
const pixels = context.createImageData(image.width, image.height);
|
|
7532
|
+
pixels.data.set(image.data);
|
|
7533
|
+
context.putImageData(pixels, 0, 0);
|
|
7534
|
+
const copySource = Object.create(source);
|
|
7535
|
+
copySource.userData = {};
|
|
7536
|
+
copySource.source = new Source2(canvas);
|
|
7537
|
+
return new Texture4().copy(copySource);
|
|
7538
|
+
}
|
|
7539
|
+
|
|
4960
7540
|
// src/gui/GuiHelper.ts
|
|
4961
7541
|
var GuiHelper = class {
|
|
4962
7542
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
@@ -4971,7 +7551,7 @@ init_ModelTextures();
|
|
|
4971
7551
|
init_Caching();
|
|
4972
7552
|
init_SceneObject();
|
|
4973
7553
|
init_Materials();
|
|
4974
|
-
import { Box2, Mesh as
|
|
7554
|
+
import { Box2, Mesh as Mesh6, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
|
|
4975
7555
|
var GuiObject = class extends SceneObject {
|
|
4976
7556
|
constructor(textureLayers, options) {
|
|
4977
7557
|
super({ ...options, instanceMeshes: false, mergeMeshes: false });
|
|
@@ -4993,7 +7573,7 @@ var GuiObject = class extends SceneObject {
|
|
|
4993
7573
|
const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
|
|
4994
7574
|
const [width, height] = layer.size ?? [cropWidth, cropHeight];
|
|
4995
7575
|
const [x, y] = layer.position ?? [0, 0];
|
|
4996
|
-
const geometry = new
|
|
7576
|
+
const geometry = new PlaneGeometry2(width, height);
|
|
4997
7577
|
this.geometries.add(geometry);
|
|
4998
7578
|
const uv = geometry.getAttribute("uv");
|
|
4999
7579
|
for (let i = 0; i < uv.count; i++) {
|
|
@@ -5003,13 +7583,13 @@ var GuiObject = class extends SceneObject {
|
|
|
5003
7583
|
1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
|
|
5004
7584
|
);
|
|
5005
7585
|
}
|
|
5006
|
-
const mesh = new
|
|
7586
|
+
const mesh = new Mesh6(geometry, material);
|
|
5007
7587
|
mesh.name = `mesh:${layer.name ?? index}`;
|
|
5008
7588
|
mesh.position.set(x + width / 2, -y - height / 2, 0);
|
|
5009
7589
|
mesh.renderOrder = index;
|
|
5010
7590
|
this.add(mesh);
|
|
5011
|
-
this.bounds.expandByPoint(new
|
|
5012
|
-
this.bounds.expandByPoint(new
|
|
7591
|
+
this.bounds.expandByPoint(new Vector23(x, y));
|
|
7592
|
+
this.bounds.expandByPoint(new Vector23(x + width, y + height));
|
|
5013
7593
|
}
|
|
5014
7594
|
this.initialized = true;
|
|
5015
7595
|
this.notifyDirty();
|
|
@@ -5058,7 +7638,7 @@ init_image();
|
|
|
5058
7638
|
// src/inspector/SceneInspector.ts
|
|
5059
7639
|
init_SceneObject();
|
|
5060
7640
|
init_util();
|
|
5061
|
-
import { Raycaster, Vector2 as
|
|
7641
|
+
import { Raycaster, Vector2 as Vector24 } from "three";
|
|
5062
7642
|
init_log();
|
|
5063
7643
|
init_three();
|
|
5064
7644
|
var p7 = prefix("SceneInspector");
|
|
@@ -5066,7 +7646,7 @@ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
|
|
|
5066
7646
|
var SceneInspector = class {
|
|
5067
7647
|
constructor(renderer) {
|
|
5068
7648
|
this.renderer = renderer;
|
|
5069
|
-
this.mouse = new
|
|
7649
|
+
this.mouse = new Vector24();
|
|
5070
7650
|
this.listeners = new AbortController();
|
|
5071
7651
|
this.objectInfoContainer = document.createElement("div");
|
|
5072
7652
|
this.objectControlsContainer = document.createElement("div");
|
|
@@ -5674,7 +8254,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
|
|
|
5674
8254
|
init_MineRenderError();
|
|
5675
8255
|
init_InstanceReference();
|
|
5676
8256
|
init_AssetKey();
|
|
5677
|
-
import { Euler as Euler7, Matrix4 as
|
|
8257
|
+
import { Euler as Euler7, Matrix4 as Matrix47, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
|
|
5678
8258
|
init_ModelCulling();
|
|
5679
8259
|
init_FluidGeometry();
|
|
5680
8260
|
var BlockObject = class _BlockObject extends SceneObject {
|
|
@@ -5740,11 +8320,11 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
5740
8320
|
getModelCullMask(model, worldMask) {
|
|
5741
8321
|
const object = isInstanceReference(model) ? model.instanceable : model;
|
|
5742
8322
|
if (object.options.displayPosition) return 0;
|
|
5743
|
-
const position = new
|
|
5744
|
-
const rotation = new
|
|
5745
|
-
const scale = new
|
|
8323
|
+
const position = new Vector311();
|
|
8324
|
+
const rotation = new Quaternion5();
|
|
8325
|
+
const scale = new Vector311();
|
|
5746
8326
|
this.getModelMatrix(model).decompose(position, rotation, scale);
|
|
5747
|
-
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new
|
|
8327
|
+
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
|
|
5748
8328
|
return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
|
|
5749
8329
|
}
|
|
5750
8330
|
async setCullMask(worldMask) {
|
|
@@ -5807,7 +8387,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
5807
8387
|
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
|
|
5808
8388
|
);
|
|
5809
8389
|
const previous = this._fluidModel;
|
|
5810
|
-
const matrix = previous ? this.getModelMatrix(previous) : new
|
|
8390
|
+
const matrix = previous ? this.getModelMatrix(previous) : new Matrix47().makeTranslation(...this.position.toArray());
|
|
5811
8391
|
if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
|
|
5812
8392
|
else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
5813
8393
|
this._models = this._models.filter((model) => model !== previous);
|
|
@@ -5938,7 +8518,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
5938
8518
|
setPositionRotationScaleAt(index, position, rotation, scale) {
|
|
5939
8519
|
super.setPositionRotationScaleAt(index, position, rotation, scale);
|
|
5940
8520
|
}
|
|
5941
|
-
getMatrixAt(index, matrix = new
|
|
8521
|
+
getMatrixAt(index, matrix = new Matrix47()) {
|
|
5942
8522
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
5943
8523
|
const child = this._models[0];
|
|
5944
8524
|
if (child && isModelObject(child)) {
|
|
@@ -7807,7 +10387,7 @@ init_nbt();
|
|
|
7807
10387
|
init_SceneObject();
|
|
7808
10388
|
var import_ts_deepmerge8 = __toESM(require_dist());
|
|
7809
10389
|
init_ModelObject();
|
|
7810
|
-
import { Scene as
|
|
10390
|
+
import { Scene as Scene5 } from "three";
|
|
7811
10391
|
|
|
7812
10392
|
// src/skin/scene/SkinObject.ts
|
|
7813
10393
|
init_SceneObject();
|
|
@@ -8540,7 +11120,7 @@ init_util();
|
|
|
8540
11120
|
init_Caching();
|
|
8541
11121
|
init_CacheKey();
|
|
8542
11122
|
init_MineRenderError();
|
|
8543
|
-
import { DataTexture, DoubleSide as
|
|
11123
|
+
import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial5, SRGBColorSpace as SRGBColorSpace5 } from "three";
|
|
8544
11124
|
|
|
8545
11125
|
// src/skin/SkinImage.ts
|
|
8546
11126
|
init_Caching();
|
|
@@ -8621,11 +11201,11 @@ var SkinTextures = class {
|
|
|
8621
11201
|
});
|
|
8622
11202
|
}
|
|
8623
11203
|
static createMaterial(pixels, width, height, transparent = true) {
|
|
8624
|
-
const texture = Textures.initTextureProps(new
|
|
8625
|
-
texture.colorSpace =
|
|
11204
|
+
const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
|
|
11205
|
+
texture.colorSpace = SRGBColorSpace5;
|
|
8626
11206
|
texture.flipY = true;
|
|
8627
11207
|
texture.needsUpdate = true;
|
|
8628
|
-
return new
|
|
11208
|
+
return new MeshBasicMaterial5({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
|
|
8629
11209
|
}
|
|
8630
11210
|
static isSlim(image, scale) {
|
|
8631
11211
|
for (const [x, y] of [[46, 52], [54, 20]]) {
|
|
@@ -8852,7 +11432,7 @@ var SkinObject = class extends SceneObject {
|
|
|
8852
11432
|
};
|
|
8853
11433
|
|
|
8854
11434
|
// src/renderer/MineRenderScene.ts
|
|
8855
|
-
var MineRenderScene = class _MineRenderScene extends
|
|
11435
|
+
var MineRenderScene = class _MineRenderScene extends Scene5 {
|
|
8856
11436
|
constructor(options) {
|
|
8857
11437
|
super();
|
|
8858
11438
|
this.isMineRenderScene = true;
|
|
@@ -8985,7 +11565,7 @@ function isMineRenderScene(obj) {
|
|
|
8985
11565
|
}
|
|
8986
11566
|
|
|
8987
11567
|
// src/renderer/Renderer.ts
|
|
8988
|
-
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as
|
|
11568
|
+
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector313, WebGLRenderer as WebGLRenderer2 } from "three";
|
|
8989
11569
|
var import_ts_deepmerge9 = __toESM(require_dist());
|
|
8990
11570
|
init_util();
|
|
8991
11571
|
import Stats from "stats.js";
|
|
@@ -8996,11 +11576,11 @@ init_three();
|
|
|
8996
11576
|
import {
|
|
8997
11577
|
EventDispatcher,
|
|
8998
11578
|
MOUSE,
|
|
8999
|
-
Quaternion as
|
|
11579
|
+
Quaternion as Quaternion6,
|
|
9000
11580
|
Spherical,
|
|
9001
11581
|
TOUCH,
|
|
9002
|
-
Vector2 as
|
|
9003
|
-
Vector3 as
|
|
11582
|
+
Vector2 as Vector25,
|
|
11583
|
+
Vector3 as Vector312
|
|
9004
11584
|
} from "three";
|
|
9005
11585
|
var _changeEvent = { type: "change" };
|
|
9006
11586
|
var _startEvent = { type: "start" };
|
|
@@ -9014,7 +11594,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9014
11594
|
this.domElement = domElement;
|
|
9015
11595
|
this.domElement.style.touchAction = "none";
|
|
9016
11596
|
this.enabled = true;
|
|
9017
|
-
this.target = new
|
|
11597
|
+
this.target = new Vector312();
|
|
9018
11598
|
this.minDistance = 0;
|
|
9019
11599
|
this.maxDistance = Infinity;
|
|
9020
11600
|
this.minZoom = 0;
|
|
@@ -9066,11 +11646,11 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9066
11646
|
state = STATE.NONE;
|
|
9067
11647
|
};
|
|
9068
11648
|
this.update = function() {
|
|
9069
|
-
const offset = new
|
|
9070
|
-
const quat = new
|
|
11649
|
+
const offset = new Vector312();
|
|
11650
|
+
const quat = new Quaternion6().setFromUnitVectors(object.up, new Vector312(0, 1, 0));
|
|
9071
11651
|
const quatInverse = quat.clone().invert();
|
|
9072
|
-
const lastPosition = new
|
|
9073
|
-
const lastQuaternion = new
|
|
11652
|
+
const lastPosition = new Vector312();
|
|
11653
|
+
const lastQuaternion = new Quaternion6();
|
|
9074
11654
|
const twoPI = 2 * Math.PI;
|
|
9075
11655
|
return function update() {
|
|
9076
11656
|
const position = scope.object.position;
|
|
@@ -9159,17 +11739,17 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9159
11739
|
const spherical = new Spherical();
|
|
9160
11740
|
const sphericalDelta = new Spherical();
|
|
9161
11741
|
let scale = 1;
|
|
9162
|
-
const panOffset = new
|
|
11742
|
+
const panOffset = new Vector312();
|
|
9163
11743
|
let zoomChanged = false;
|
|
9164
|
-
const rotateStart = new
|
|
9165
|
-
const rotateEnd = new
|
|
9166
|
-
const rotateDelta = new
|
|
9167
|
-
const panStart = new
|
|
9168
|
-
const panEnd = new
|
|
9169
|
-
const panDelta = new
|
|
9170
|
-
const dollyStart = new
|
|
9171
|
-
const dollyEnd = new
|
|
9172
|
-
const dollyDelta = new
|
|
11744
|
+
const rotateStart = new Vector25();
|
|
11745
|
+
const rotateEnd = new Vector25();
|
|
11746
|
+
const rotateDelta = new Vector25();
|
|
11747
|
+
const panStart = new Vector25();
|
|
11748
|
+
const panEnd = new Vector25();
|
|
11749
|
+
const panDelta = new Vector25();
|
|
11750
|
+
const dollyStart = new Vector25();
|
|
11751
|
+
const dollyEnd = new Vector25();
|
|
11752
|
+
const dollyDelta = new Vector25();
|
|
9173
11753
|
const pointers = [];
|
|
9174
11754
|
const pointerPositions = {};
|
|
9175
11755
|
function getAutoRotationAngle() {
|
|
@@ -9185,7 +11765,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9185
11765
|
sphericalDelta.phi -= angle;
|
|
9186
11766
|
}
|
|
9187
11767
|
const panLeft = function() {
|
|
9188
|
-
const v = new
|
|
11768
|
+
const v = new Vector312();
|
|
9189
11769
|
return function panLeft2(distance, objectMatrix) {
|
|
9190
11770
|
v.setFromMatrixColumn(objectMatrix, 0);
|
|
9191
11771
|
v.multiplyScalar(-distance);
|
|
@@ -9193,7 +11773,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9193
11773
|
};
|
|
9194
11774
|
}();
|
|
9195
11775
|
const panUp = function() {
|
|
9196
|
-
const v = new
|
|
11776
|
+
const v = new Vector312();
|
|
9197
11777
|
return function panUp2(distance, objectMatrix) {
|
|
9198
11778
|
if (scope.screenSpacePanning === true) {
|
|
9199
11779
|
v.setFromMatrixColumn(objectMatrix, 1);
|
|
@@ -9206,7 +11786,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9206
11786
|
};
|
|
9207
11787
|
}();
|
|
9208
11788
|
const pan = function() {
|
|
9209
|
-
const offset = new
|
|
11789
|
+
const offset = new Vector312();
|
|
9210
11790
|
return function pan2(deltaX, deltaY) {
|
|
9211
11791
|
const element = scope.domElement;
|
|
9212
11792
|
if (scope.object.isPerspectiveCamera) {
|
|
@@ -9615,7 +12195,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
9615
12195
|
function trackPointer(event) {
|
|
9616
12196
|
let position = pointerPositions[event.pointerId];
|
|
9617
12197
|
if (position === void 0) {
|
|
9618
|
-
position = new
|
|
12198
|
+
position = new Vector25();
|
|
9619
12199
|
pointerPositions[event.pointerId] = position;
|
|
9620
12200
|
}
|
|
9621
12201
|
position.set(event.pageX, event.pageY);
|
|
@@ -9687,8 +12267,8 @@ var Renderer = class _Renderer {
|
|
|
9687
12267
|
top: void 0,
|
|
9688
12268
|
bottom: void 0
|
|
9689
12269
|
},
|
|
9690
|
-
position: new
|
|
9691
|
-
lookingAt: new
|
|
12270
|
+
position: new Vector313(50, 50, 50),
|
|
12271
|
+
lookingAt: new Vector313(0, 0, 0)
|
|
9692
12272
|
},
|
|
9693
12273
|
render: {
|
|
9694
12274
|
fpsLimit: 60,
|
|
@@ -9719,7 +12299,7 @@ var Renderer = class _Renderer {
|
|
|
9719
12299
|
switch (this.options.camera.type) {
|
|
9720
12300
|
case "perspective":
|
|
9721
12301
|
default:
|
|
9722
|
-
return new
|
|
12302
|
+
return new PerspectiveCamera2(
|
|
9723
12303
|
this.options.camera.perspective.fov,
|
|
9724
12304
|
this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
|
|
9725
12305
|
this.options.camera.near,
|
|
@@ -9737,7 +12317,7 @@ var Renderer = class _Renderer {
|
|
|
9737
12317
|
}
|
|
9738
12318
|
}
|
|
9739
12319
|
createRenderer() {
|
|
9740
|
-
const renderer = new
|
|
12320
|
+
const renderer = new WebGLRenderer2({
|
|
9741
12321
|
antialias: this.options.render.antialias,
|
|
9742
12322
|
alpha: true,
|
|
9743
12323
|
powerPreference: "high-performance",
|
|
@@ -9746,7 +12326,7 @@ var Renderer = class _Renderer {
|
|
|
9746
12326
|
renderer.setClearColor(0, 0);
|
|
9747
12327
|
renderer.shadowMap.enabled = true;
|
|
9748
12328
|
renderer.shadowMap.type = PCFSoftShadowMap;
|
|
9749
|
-
renderer.outputColorSpace =
|
|
12329
|
+
renderer.outputColorSpace = SRGBColorSpace6;
|
|
9750
12330
|
renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
|
|
9751
12331
|
renderer.setSize(this.viewWidth, this.viewHeight);
|
|
9752
12332
|
return renderer;
|
|
@@ -9938,6 +12518,9 @@ var Renderer = class _Renderer {
|
|
|
9938
12518
|
if (next !== void 0 && t + 0.1 < next) return;
|
|
9939
12519
|
this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
|
|
9940
12520
|
}
|
|
12521
|
+
this.drawFrame();
|
|
12522
|
+
}
|
|
12523
|
+
drawFrame() {
|
|
9941
12524
|
if (this._stats) {
|
|
9942
12525
|
this._stats.begin();
|
|
9943
12526
|
}
|
|
@@ -9952,8 +12535,28 @@ var Renderer = class _Renderer {
|
|
|
9952
12535
|
}
|
|
9953
12536
|
}
|
|
9954
12537
|
//</editor-fold>
|
|
9955
|
-
|
|
9956
|
-
|
|
12538
|
+
/**
|
|
12539
|
+
* Renders a fresh frame and returns an image data URL, including while the animation loop is stopped.
|
|
12540
|
+
* Trimming removes transparent borders; an empty image becomes one transparent pixel.
|
|
12541
|
+
* MIME type support and lossy quality (0–1) follow the canvas encoder.
|
|
12542
|
+
*/
|
|
12543
|
+
toImage(trim = false, mime = "image/png", quality) {
|
|
12544
|
+
if (this._disposed) throw new Error("Cannot export an image from a disposed renderer");
|
|
12545
|
+
if (this._controls?.enabled) {
|
|
12546
|
+
this._controls.update();
|
|
12547
|
+
}
|
|
12548
|
+
this.drawFrame();
|
|
12549
|
+
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
12550
|
+
return canvas.toDataURL(mime, quality);
|
|
12551
|
+
}
|
|
12552
|
+
toObj() {
|
|
12553
|
+
return SceneExporter.toObj(this.scene);
|
|
12554
|
+
}
|
|
12555
|
+
toPLY(options) {
|
|
12556
|
+
return SceneExporter.toPLY(this.scene, options);
|
|
12557
|
+
}
|
|
12558
|
+
toGLTF(options) {
|
|
12559
|
+
return SceneExporter.toGLTF(this.scene, options);
|
|
9957
12560
|
}
|
|
9958
12561
|
///
|
|
9959
12562
|
get attachedToBody() {
|
|
@@ -10424,12 +13027,12 @@ var AnvilParser = class {
|
|
|
10424
13027
|
};
|
|
10425
13028
|
|
|
10426
13029
|
// src/world/Chunk.ts
|
|
10427
|
-
import { Vector3 as
|
|
13030
|
+
import { Vector3 as Vector316 } from "three";
|
|
10428
13031
|
init_BlockStates();
|
|
10429
13032
|
init_AssetKey();
|
|
10430
13033
|
|
|
10431
13034
|
// src/world/MineRenderWorld.ts
|
|
10432
|
-
import { Vector3 as
|
|
13035
|
+
import { Vector3 as Vector315 } from "three";
|
|
10433
13036
|
init_BatchedExecutor();
|
|
10434
13037
|
init_AssetKey();
|
|
10435
13038
|
init_BlockStates();
|
|
@@ -10439,7 +13042,7 @@ init_CubeFace();
|
|
|
10439
13042
|
init_AssetKey();
|
|
10440
13043
|
init_Models();
|
|
10441
13044
|
init_CubeFace();
|
|
10442
|
-
import { Matrix4 as
|
|
13045
|
+
import { Matrix4 as Matrix48, Vector3 as Vector314 } from "three";
|
|
10443
13046
|
init_ModelCulling();
|
|
10444
13047
|
init_ModelObject();
|
|
10445
13048
|
init_UVMapper();
|
|
@@ -10502,12 +13105,12 @@ var SectionModels = class {
|
|
|
10502
13105
|
});
|
|
10503
13106
|
await object.init();
|
|
10504
13107
|
const geometry = object.children[0].geometry;
|
|
10505
|
-
geometry.applyMatrix4(new
|
|
13108
|
+
geometry.applyMatrix4(new Matrix48().makeRotationFromEuler(rotation));
|
|
10506
13109
|
object.clear();
|
|
10507
13110
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
10508
13111
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
10509
13112
|
if (local < 0) return 0;
|
|
10510
|
-
const normal = new
|
|
13113
|
+
const normal = new Vector314(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
10511
13114
|
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);
|
|
10512
13115
|
return 1 << world;
|
|
10513
13116
|
});
|
|
@@ -10537,20 +13140,20 @@ var MineRenderWorld = class {
|
|
|
10537
13140
|
}
|
|
10538
13141
|
getBlockAt(posOrX, y, z) {
|
|
10539
13142
|
if (typeof posOrX == "number") {
|
|
10540
|
-
return this.getBlockAt(new
|
|
13143
|
+
return this.getBlockAt(new Vector315(posOrX, y, z));
|
|
10541
13144
|
}
|
|
10542
13145
|
if (isTripleArray(posOrX)) {
|
|
10543
|
-
return this.getBlockAt(new
|
|
13146
|
+
return this.getBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]));
|
|
10544
13147
|
}
|
|
10545
13148
|
this.validatePosBounds(posOrX);
|
|
10546
13149
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
10547
13150
|
}
|
|
10548
13151
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
10549
13152
|
if (typeof posOrX == "number") {
|
|
10550
|
-
return this.setBlockAt(new
|
|
13153
|
+
return this.setBlockAt(new Vector315(posOrX, yOrBlock, z), block);
|
|
10551
13154
|
}
|
|
10552
13155
|
if (isTripleArray(posOrX)) {
|
|
10553
|
-
return this.setBlockAt(new
|
|
13156
|
+
return this.setBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
10554
13157
|
}
|
|
10555
13158
|
return this.placeBlock(posOrX, yOrBlock);
|
|
10556
13159
|
}
|
|
@@ -10571,7 +13174,7 @@ var MineRenderWorld = class {
|
|
|
10571
13174
|
const collect = async (positions2) => {
|
|
10572
13175
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
10573
13176
|
};
|
|
10574
|
-
const place = (block) => this.placeBlock(new
|
|
13177
|
+
const place = (block) => this.placeBlock(new Vector315(...block.position), block, collect);
|
|
10575
13178
|
const keys = /* @__PURE__ */ new Map();
|
|
10576
13179
|
for (const block of multiblock.blocks) {
|
|
10577
13180
|
if (Chunk.isAir(block)) continue;
|
|
@@ -10649,13 +13252,13 @@ var MineRenderWorld = class {
|
|
|
10649
13252
|
for (const pos of positions) {
|
|
10650
13253
|
this.pendingCulling.set(pos.toArray().join(","), pos.clone());
|
|
10651
13254
|
for (const offset of CUBE_FACE_OFFSETS) {
|
|
10652
|
-
const neighbor = pos.clone().add(new
|
|
13255
|
+
const neighbor = pos.clone().add(new Vector315(...offset));
|
|
10653
13256
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
10654
13257
|
}
|
|
10655
13258
|
for (let y = -1; y <= 1; y++) {
|
|
10656
13259
|
for (let z = -1; z <= 1; z++) {
|
|
10657
13260
|
for (let x = -1; x <= 1; x++) {
|
|
10658
|
-
const neighbor = pos.clone().add(new
|
|
13261
|
+
const neighbor = pos.clone().add(new Vector315(x, y, z));
|
|
10659
13262
|
if (this.getBlockAt(neighbor)?.object?.fluidKind) {
|
|
10660
13263
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
10661
13264
|
}
|
|
@@ -10677,7 +13280,7 @@ var MineRenderWorld = class {
|
|
|
10677
13280
|
if (!block) continue;
|
|
10678
13281
|
if (block.object?.fluidKind) {
|
|
10679
13282
|
await block.object.updateFluid((x, y, z) => {
|
|
10680
|
-
const neighbor = pos.clone().add(new
|
|
13283
|
+
const neighbor = pos.clone().add(new Vector315(x, y, z));
|
|
10681
13284
|
const section = this.getChunkAt(neighbor);
|
|
10682
13285
|
const object = section?.getBlockAt(neighbor)?.object;
|
|
10683
13286
|
return {
|
|
@@ -10689,7 +13292,7 @@ var MineRenderWorld = class {
|
|
|
10689
13292
|
}
|
|
10690
13293
|
let mask = 0;
|
|
10691
13294
|
for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
10692
|
-
const neighbor = pos.clone().add(new
|
|
13295
|
+
const neighbor = pos.clone().add(new Vector315(...offset));
|
|
10693
13296
|
if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
|
|
10694
13297
|
mask |= 1 << face;
|
|
10695
13298
|
}
|
|
@@ -10723,14 +13326,14 @@ var MineRenderWorld = class {
|
|
|
10723
13326
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
10724
13327
|
}
|
|
10725
13328
|
static worldToScenePosition(pos) {
|
|
10726
|
-
return new
|
|
13329
|
+
return new Vector315(
|
|
10727
13330
|
pos.x * 16,
|
|
10728
13331
|
pos.y * 16,
|
|
10729
13332
|
pos.z * 16
|
|
10730
13333
|
);
|
|
10731
13334
|
}
|
|
10732
13335
|
static sceneToWorldPosition(pos) {
|
|
10733
|
-
return new
|
|
13336
|
+
return new Vector315(
|
|
10734
13337
|
pos.x / 16,
|
|
10735
13338
|
pos.y / 16,
|
|
10736
13339
|
pos.z / 16
|
|
@@ -10752,7 +13355,7 @@ var MineRenderWorld = class {
|
|
|
10752
13355
|
// src/world/SectionMesh.ts
|
|
10753
13356
|
init_CanvasCompat();
|
|
10754
13357
|
init_Materials();
|
|
10755
|
-
import { BufferGeometry as
|
|
13358
|
+
import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
|
|
10756
13359
|
var SectionMesh = class _SectionMesh extends Group {
|
|
10757
13360
|
constructor() {
|
|
10758
13361
|
super(...arguments);
|
|
@@ -10826,18 +13429,18 @@ var SectionMesh = class _SectionMesh extends Group {
|
|
|
10826
13429
|
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
10827
13430
|
}
|
|
10828
13431
|
}
|
|
10829
|
-
const geometry = new
|
|
10830
|
-
geometry.setAttribute("position", new
|
|
10831
|
-
geometry.setAttribute("normal", new
|
|
10832
|
-
geometry.setAttribute("uv", new
|
|
10833
|
-
geometry.setAttribute("color", new
|
|
13432
|
+
const geometry = new BufferGeometry5();
|
|
13433
|
+
geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
|
|
13434
|
+
geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
|
|
13435
|
+
geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
|
|
13436
|
+
geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
|
|
10834
13437
|
geometry.setIndex(indices);
|
|
10835
13438
|
geometry.computeBoundingBox();
|
|
10836
13439
|
geometry.computeBoundingSphere();
|
|
10837
13440
|
const material = Materials.createShadedCanvasMaterial(canvas, false);
|
|
10838
13441
|
material.vertexColors = true;
|
|
10839
13442
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
10840
|
-
const mesh = new
|
|
13443
|
+
const mesh = new Mesh10(geometry, material);
|
|
10841
13444
|
section.add(mesh);
|
|
10842
13445
|
section.ownedMeshes.push({ mesh, texture });
|
|
10843
13446
|
}
|
|
@@ -10871,10 +13474,10 @@ var Chunk = class _Chunk {
|
|
|
10871
13474
|
}
|
|
10872
13475
|
getBlockAt(posOrX, y, z) {
|
|
10873
13476
|
if (typeof posOrX == "number") {
|
|
10874
|
-
return this.getBlockAt(new
|
|
13477
|
+
return this.getBlockAt(new Vector316(posOrX, y, z));
|
|
10875
13478
|
}
|
|
10876
13479
|
if (isTripleArray(posOrX)) {
|
|
10877
|
-
return this.getBlockAt(new
|
|
13480
|
+
return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
|
|
10878
13481
|
}
|
|
10879
13482
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
10880
13483
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
@@ -10882,10 +13485,10 @@ var Chunk = class _Chunk {
|
|
|
10882
13485
|
}
|
|
10883
13486
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
10884
13487
|
if (typeof posOrX == "number") {
|
|
10885
|
-
return this.setBlockAt(new
|
|
13488
|
+
return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
|
|
10886
13489
|
}
|
|
10887
13490
|
if (isTripleArray(posOrX)) {
|
|
10888
|
-
return this.setBlockAt(new
|
|
13491
|
+
return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
10889
13492
|
}
|
|
10890
13493
|
const worldPos = posOrX;
|
|
10891
13494
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -10970,7 +13573,7 @@ var Chunk = class _Chunk {
|
|
|
10970
13573
|
}
|
|
10971
13574
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
10972
13575
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
10973
|
-
new
|
|
13576
|
+
new Vector316(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
10974
13577
|
));
|
|
10975
13578
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
10976
13579
|
this.sectionBlocks.clear();
|
|
@@ -10994,14 +13597,14 @@ var Chunk = class _Chunk {
|
|
|
10994
13597
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
10995
13598
|
}
|
|
10996
13599
|
worldPosToChunkPos(pos) {
|
|
10997
|
-
return new
|
|
13600
|
+
return new Vector316(
|
|
10998
13601
|
pos.x - this.x * 16,
|
|
10999
13602
|
pos.y - this.y * 16,
|
|
11000
13603
|
pos.z - this.z * 16
|
|
11001
13604
|
);
|
|
11002
13605
|
}
|
|
11003
13606
|
chunkPosToWorldPos(pos) {
|
|
11004
|
-
return new
|
|
13607
|
+
return new Vector316(
|
|
11005
13608
|
this.x * 16 + pos.x,
|
|
11006
13609
|
this.y * 16 + pos.y,
|
|
11007
13610
|
this.z * 16 + pos.z
|
|
@@ -11080,6 +13683,7 @@ export {
|
|
|
11080
13683
|
RequestError,
|
|
11081
13684
|
Requests,
|
|
11082
13685
|
SKIN_PARTS,
|
|
13686
|
+
SceneExporter,
|
|
11083
13687
|
SceneInspector,
|
|
11084
13688
|
SceneObject,
|
|
11085
13689
|
SceneStats,
|
|
@@ -11168,6 +13772,7 @@ export {
|
|
|
11168
13772
|
timingStart,
|
|
11169
13773
|
toDegrees,
|
|
11170
13774
|
toRadians,
|
|
11171
|
-
toTrianglesDrawMode
|
|
13775
|
+
toTrianglesDrawMode,
|
|
13776
|
+
trimCanvas
|
|
11172
13777
|
};
|
|
11173
13778
|
//# sourceMappingURL=index.mjs.map
|