Favivon - Correção

This commit is contained in:
2026-05-30 19:59:39 -03:00
parent 76ddaa815d
commit d7dfd221f0
32859 changed files with 5459654 additions and 404 deletions
+333
View File
@@ -0,0 +1,333 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const uv1 = require("../_polyfill/uv1.cjs");
class ColladaExporter {
constructor() {
__publicField(this, "options");
__publicField(this, "geometryInfo");
__publicField(this, "materialMap");
__publicField(this, "imageMap");
__publicField(this, "textures");
__publicField(this, "libraryImages");
__publicField(this, "libraryGeometries");
__publicField(this, "libraryEffects");
__publicField(this, "libraryMaterials");
__publicField(this, "canvas");
__publicField(this, "ctx");
__publicField(this, "transMat");
__publicField(this, "getFuncs", ["getX", "getY", "getZ", "getW"]);
this.options = {
version: "1.4.1",
author: null,
textureDirectory: "",
upAxis: "Y_UP",
unitName: null,
unitMeter: null
};
this.geometryInfo = /* @__PURE__ */ new WeakMap();
this.materialMap = /* @__PURE__ */ new WeakMap();
this.imageMap = /* @__PURE__ */ new WeakMap();
this.textures = [];
this.libraryImages = [];
this.libraryGeometries = [];
this.libraryEffects = [];
this.libraryMaterials = [];
this.canvas = null;
this.ctx = null;
this.transMat = null;
}
parse(object, onDone, options = {}) {
this.options = { ...this.options, ...options };
if (this.options.upAxis.match(/^[XYZ]_UP$/) === null) {
console.error("ColladaExporter: Invalid upAxis: valid values are X_UP, Y_UP or Z_UP.");
return null;
}
if (this.options.unitName !== null && this.options.unitMeter === null) {
console.error("ColladaExporter: unitMeter needs to be specified if unitName is specified.");
return null;
}
if (this.options.unitMeter !== null && this.options.unitName === null) {
console.error("ColladaExporter: unitName needs to be specified if unitMeter is specified.");
return null;
}
if (this.options.textureDirectory !== "") {
this.options.textureDirectory = `${this.options.textureDirectory}/`.replace(/\\/g, "/").replace(/\/+/g, "/");
}
if (this.options.version !== "1.4.1" && this.options.version !== "1.5.0") {
console.warn(`ColladaExporter : Version ${this.options.version} not supported for export. Only 1.4.1 and 1.5.0.`);
return null;
}
const libraryVisualScenes = this.processObject(object);
const specLink = this.options.version === "1.4.1" ? "http://www.collada.org/2005/11/COLLADASchema" : "https://www.khronos.org/collada/";
let dae = `<?xml version="1.0" encoding="UTF-8" standalone="no" ?>${`<COLLADA xmlns="${specLink}" version="${this.options.version}">`}<asset><contributor><authoring_tool>three.js Collada Exporter</authoring_tool>${this.options.author !== null ? `<author>${this.options.author}</author>` : ""}</contributor>${`<created>${(/* @__PURE__ */ new Date()).toISOString()}</created>`}${`<modified>${(/* @__PURE__ */ new Date()).toISOString()}</modified>`}<up_axis>Y_UP</up_axis></asset>`;
dae += `<library_images>${this.libraryImages.join("")}</library_images>`;
dae += `<library_effects>${this.libraryEffects.join("")}</library_effects>`;
dae += `<library_materials>${this.libraryMaterials.join("")}</library_materials>`;
dae += `<library_geometries>${this.libraryGeometries.join("")}</library_geometries>`;
dae += `<library_visual_scenes><visual_scene id="Scene" name="scene">${libraryVisualScenes}</visual_scene></library_visual_scenes>`;
dae += '<scene><instance_visual_scene url="#Scene"/></scene>';
dae += "</COLLADA>";
const res = {
data: this.format(dae),
textures: this.textures
};
if (typeof onDone === "function") {
requestAnimationFrame(() => onDone(res));
}
return res;
}
// Convert the urdf xml into a well-formatted, indented format
format(urdf) {
var _a, _b;
const IS_END_TAG = /^<\//;
const IS_SELF_CLOSING = /(\?>$)|(\/>$)/;
const HAS_TEXT = /<[^>]+>[^<]*<\/[^<]+>/;
const pad = (ch, num) => num > 0 ? ch + pad(ch, num - 1) : "";
let tagnum = 0;
return (_b = (_a = urdf.match(/(<[^>]+>[^<]+<\/[^<]+>)|(<[^>]+>)/g)) == null ? void 0 : _a.map((tag) => {
if (!HAS_TEXT.test(tag) && !IS_SELF_CLOSING.test(tag) && IS_END_TAG.test(tag)) {
tagnum--;
}
const res = `${pad(" ", tagnum)}${tag}`;
if (!HAS_TEXT.test(tag) && !IS_SELF_CLOSING.test(tag) && !IS_END_TAG.test(tag)) {
tagnum++;
}
return res;
}).join("\n")) != null ? _b : "";
}
// Convert an image into a png format for saving
base64ToBuffer(str) {
const b = atob(str);
const buf = new Uint8Array(b.length);
for (let i = 0, l = buf.length; i < l; i++) {
buf[i] = b.charCodeAt(i);
}
return buf;
}
imageToData(image, ext) {
var _a;
this.canvas = this.canvas || document.createElement("canvas");
this.ctx = this.ctx || this.canvas.getContext("2d");
this.canvas.width = image.width instanceof SVGAnimatedLength ? 0 : image.width;
this.canvas.height = image.height instanceof SVGAnimatedLength ? 0 : image.height;
(_a = this.ctx) == null ? void 0 : _a.drawImage(image, 0, 0);
const base64data = this.canvas.toDataURL(`image/${ext}`, 1).replace(/^data:image\/(png|jpg);base64,/, "");
return this.base64ToBuffer(base64data);
}
// gets the attribute array. Generate a new array if the attribute is interleaved
attrBufferToArray(attr) {
if (attr instanceof THREE.InterleavedBufferAttribute && attr.isInterleavedBufferAttribute) {
const TypedArrayConstructor = attr.array.constructor;
const arr = new TypedArrayConstructor(attr.count * attr.itemSize);
const size = attr.itemSize;
for (let i = 0, l = attr.count; i < l; i++) {
for (let j = 0; j < size; j++) {
arr[i * size + j] = attr[this.getFuncs[j]](i);
}
}
return arr;
} else {
return attr.array;
}
}
// Returns an array of the same type starting at the `st` index,
// and `ct` length
subArray(arr, st, ct) {
if (Array.isArray(arr)) {
return arr.slice(st, st + ct);
} else {
const TypedArrayConstructor = arr.constructor;
return new TypedArrayConstructor(arr.buffer, st * arr.BYTES_PER_ELEMENT, ct);
}
}
// Returns the string for a geometry's attribute
getAttribute(attr, name, params, type) {
const array = this.attrBufferToArray(attr);
const res = Array.isArray(array) ? `${`<source id="${name}"><float_array id="${name}-array" count="${array.length}">` + array.join(" ")}</float_array><technique_common>${`<accessor source="#${name}-array" count="${Math.floor(
array.length / attr.itemSize
)}" stride="${attr.itemSize}">`}${params.map((n) => `<param name="${n}" type="${type}" />`).join("")}</accessor></technique_common></source>` : "";
return res;
}
// Returns the string for a node's transform information
getTransform(o) {
o.updateMatrix();
this.transMat = this.transMat || new THREE.Matrix4();
this.transMat.copy(o.matrix);
this.transMat.transpose();
return `<matrix>${this.transMat.toArray().join(" ")}</matrix>`;
}
// Process the given piece of geometry into the geometry library
// Returns the mesh id
processGeometry(g) {
let info = this.geometryInfo.get(g);
if (!info) {
const bufferGeometry = g;
if (!bufferGeometry.isBufferGeometry) {
throw new Error("THREE.ColladaExporter: Geometry is not of type THREE.BufferGeometry.");
}
const meshid = `Mesh${this.libraryGeometries.length + 1}`;
const indexCount = bufferGeometry.index ? bufferGeometry.index.count * bufferGeometry.index.itemSize : bufferGeometry.attributes.position.count;
const groups = bufferGeometry.groups != null && bufferGeometry.groups.length !== 0 ? bufferGeometry.groups : [{ start: 0, count: indexCount, materialIndex: 0 }];
const gname = g.name ? ` name="${g.name}"` : "";
let gnode = `<geometry id="${meshid}"${gname}><mesh>`;
const posName = `${meshid}-position`;
const vertName = `${meshid}-vertices`;
gnode += this.getAttribute(bufferGeometry.attributes.position, posName, ["X", "Y", "Z"], "float");
gnode += `<vertices id="${vertName}"><input semantic="POSITION" source="#${posName}" /></vertices>`;
let triangleInputs = `<input semantic="VERTEX" source="#${vertName}" offset="0" />`;
if ("normal" in bufferGeometry.attributes) {
const normName = `${meshid}-normal`;
gnode += this.getAttribute(bufferGeometry.attributes.normal, normName, ["X", "Y", "Z"], "float");
triangleInputs += `<input semantic="NORMAL" source="#${normName}" offset="0" />`;
}
if ("uv" in bufferGeometry.attributes) {
const uvName = `${meshid}-texcoord`;
gnode += this.getAttribute(bufferGeometry.attributes.uv, uvName, ["S", "T"], "float");
triangleInputs += `<input semantic="TEXCOORD" source="#${uvName}" offset="0" set="0" />`;
}
if (uv1.UV1 in bufferGeometry.attributes) {
const uvName = `${meshid}-texcoord2`;
gnode += this.getAttribute(bufferGeometry.attributes[uv1.UV1], uvName, ["S", "T"], "float");
triangleInputs += `<input semantic="TEXCOORD" source="#${uvName}" offset="0" set="1" />`;
}
if ("color" in bufferGeometry.attributes) {
const colName = `${meshid}-color`;
gnode += this.getAttribute(bufferGeometry.attributes.color, colName, ["X", "Y", "Z"], "uint8");
triangleInputs += `<input semantic="COLOR" source="#${colName}" offset="0" />`;
}
let indexArray = null;
if (bufferGeometry.index) {
indexArray = this.attrBufferToArray(bufferGeometry.index);
} else {
indexArray = new Array(indexCount);
for (let i = 0, l = indexArray.length; i < l && Array.isArray(indexArray); i++)
indexArray[i] = i;
}
for (let i = 0, l = groups.length; i < l; i++) {
const group = groups[i];
const subarr = this.subArray(indexArray, group.start, group.count);
const polycount = subarr.length / 3;
gnode += `<triangles material="MESH_MATERIAL_${group.materialIndex}" count="${polycount}">`;
gnode += triangleInputs;
gnode += `<p>${subarr.join(" ")}</p>`;
gnode += "</triangles>";
}
gnode += "</mesh></geometry>";
this.libraryGeometries.push(gnode);
info = { meshid, bufferGeometry };
this.geometryInfo.set(g, info);
}
return info;
}
// Process the given texture into the image library
// Returns the image library
processTexture(tex) {
let texid = this.imageMap.get(tex);
if (texid == null) {
texid = `image-${this.libraryImages.length + 1}`;
const ext = "png";
const name = tex.name || texid;
let imageNode = `<image id="${texid}" name="${name}">`;
if (this.options.version === "1.5.0") {
imageNode += `<init_from><ref>${this.options.textureDirectory}${name}.${ext}</ref></init_from>`;
} else {
imageNode += `<init_from>${this.options.textureDirectory}${name}.${ext}</init_from>`;
}
imageNode += "</image>";
this.libraryImages.push(imageNode);
this.imageMap.set(tex, texid);
this.textures.push({
directory: this.options.textureDirectory,
name,
ext,
data: this.imageToData(tex.image, ext),
original: tex
});
}
return texid;
}
// Process the given material into the material and effect libraries
// Returns the material id
processMaterial(m) {
let matid = this.materialMap.get(m);
if (matid == null) {
matid = `Mat${this.libraryEffects.length + 1}`;
let type = "phong";
if (m instanceof THREE.MeshLambertMaterial) {
type = "lambert";
} else if (m instanceof THREE.MeshBasicMaterial) {
type = "constant";
if (m.map !== null) {
console.warn("ColladaExporter: Texture maps not supported with MeshBasicMaterial.");
}
}
if (m instanceof THREE.MeshPhongMaterial) {
const emissive = m.emissive ? m.emissive : new THREE.Color(0, 0, 0);
const diffuse = m.color ? m.color : new THREE.Color(0, 0, 0);
const specular = m.specular ? m.specular : new THREE.Color(1, 1, 1);
const shininess = m.shininess || 0;
const reflectivity = m.reflectivity || 0;
let transparencyNode = "";
if (m.transparent) {
transparencyNode += `<transparent>${m.map ? '<texture texture="diffuse-sampler"></texture>' : "<float>1</float>"}</transparent>`;
if (m.opacity < 1) {
transparencyNode += `<transparency><float>${m.opacity}</float></transparency>`;
}
}
const techniqueNode = `${`<technique sid="common"><${type}>`}<emission>${m.emissiveMap ? '<texture texture="emissive-sampler" texcoord="TEXCOORD" />' : `<color sid="emission">${emissive.r} ${emissive.g} ${emissive.b} 1</color>`}</emission>${type !== "constant" ? `<diffuse>${m.map ? '<texture texture="diffuse-sampler" texcoord="TEXCOORD" />' : `<color sid="diffuse">${diffuse.r} ${diffuse.g} ${diffuse.b} 1</color>`}</diffuse>` : ""}${type !== "constant" ? `<bump>${m.normalMap ? '<texture texture="bump-sampler" texcoord="TEXCOORD" />' : ""}</bump>` : ""}${type === "phong" ? `${`<specular><color sid="specular">${specular.r} ${specular.g} ${specular.b} 1</color></specular>`}<shininess>${m.specularMap ? '<texture texture="specular-sampler" texcoord="TEXCOORD" />' : `<float sid="shininess">${shininess}</float>`}</shininess>` : ""}${`<reflective><color>${diffuse.r} ${diffuse.g} ${diffuse.b} 1</color></reflective>`}${`<reflectivity><float>${reflectivity}</float></reflectivity>`}${transparencyNode}${`</${type}></technique>`}`;
const effectnode = `${`<effect id="${matid}-effect">`}<profile_COMMON>${m.map ? `<newparam sid="diffuse-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.map
)}</init_from>`}</surface></newparam><newparam sid="diffuse-sampler"><sampler2D><source>diffuse-surface</source></sampler2D></newparam>` : ""}${m.specularMap ? `<newparam sid="specular-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.specularMap
)}</init_from>`}</surface></newparam><newparam sid="specular-sampler"><sampler2D><source>specular-surface</source></sampler2D></newparam>` : ""}${m.emissiveMap ? `<newparam sid="emissive-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.emissiveMap
)}</init_from>`}</surface></newparam><newparam sid="emissive-sampler"><sampler2D><source>emissive-surface</source></sampler2D></newparam>` : ""}${m.normalMap ? `<newparam sid="bump-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.normalMap
)}</init_from>`}</surface></newparam><newparam sid="bump-sampler"><sampler2D><source>bump-surface</source></sampler2D></newparam>` : ""}${techniqueNode}${m.side === THREE.DoubleSide ? '<extra><technique profile="THREEJS"><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>' : ""}</profile_COMMON></effect>`;
const materialName = m.name ? ` name="${m.name}"` : "";
const materialNode = `<material id="${matid}"${materialName}><instance_effect url="#${matid}-effect" /></material>`;
this.libraryMaterials.push(materialNode);
this.libraryEffects.push(effectnode);
this.materialMap.set(m, matid);
}
}
return matid;
}
// Recursively process the object into a scene
processObject(o) {
let node = `<node name="${o.name}">`;
node += this.getTransform(o);
const a = new THREE.Mesh();
a.geometry;
if (o instanceof THREE.Mesh && o.isMesh && o.geometry !== null) {
const geomInfo = this.processGeometry(o.geometry);
const meshid = geomInfo.meshid;
const geometry = geomInfo.bufferGeometry;
let matids = null;
let matidsArray;
const mat = o.material || new THREE.MeshBasicMaterial();
const materials = Array.isArray(mat) ? mat : [mat];
if (geometry.groups.length > materials.length) {
matidsArray = new Array(geometry.groups.length);
} else {
matidsArray = new Array(materials.length);
}
matids = matidsArray.fill(null).map((_, i) => this.processMaterial(materials[i % materials.length]));
node += `${`<instance_geometry url="#${meshid}">` + (matids != null ? `<bind_material><technique_common>${matids.map(
(id, i) => `${`<instance_material symbol="MESH_MATERIAL_${i}" target="#${id}" >`}<bind_vertex_input semantic="TEXCOORD" input_semantic="TEXCOORD" input_set="0" /></instance_material>`
).join("")}</technique_common></bind_material>` : "")}</instance_geometry>`;
}
o.children.forEach((c) => node += this.processObject(c));
node += "</node>";
return node;
}
}
exports.ColladaExporter = ColladaExporter;
//# sourceMappingURL=ColladaExporter.cjs.map
File diff suppressed because one or more lines are too long
+50
View File
@@ -0,0 +1,50 @@
import { Object3D } from 'three';
/**
* https://github.com/gkjohnson/collada-exporter-js
*
* Usage:
* const exporter = new ColladaExporter();
*
* const data = exporter.parse(mesh);
*
* Format Definition:
* https://www.khronos.org/collada/
*/
export interface ColladaExporterOptions {
author?: string;
textureDirectory?: string;
version?: string;
}
export interface ColladaExporterResult {
data: string;
textures: object[];
}
declare class ColladaExporter {
private options;
private geometryInfo;
private materialMap;
private imageMap;
private textures;
private libraryImages;
private libraryGeometries;
private libraryEffects;
private libraryMaterials;
private canvas;
private ctx;
private transMat;
private getFuncs;
constructor();
parse(object: Object3D, onDone: (res: ColladaExporterResult) => void, options?: ColladaExporterOptions): ColladaExporterResult | null;
private format;
private base64ToBuffer;
private imageToData;
private attrBufferToArray;
private subArray;
private getAttribute;
private getTransform;
private processGeometry;
private processTexture;
private processMaterial;
private processObject;
}
export { ColladaExporter };
+333
View File
@@ -0,0 +1,333 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { InterleavedBufferAttribute, Matrix4, MeshLambertMaterial, MeshBasicMaterial, MeshPhongMaterial, Color, DoubleSide, Mesh } from "three";
import { UV1 } from "../_polyfill/uv1.js";
class ColladaExporter {
constructor() {
__publicField(this, "options");
__publicField(this, "geometryInfo");
__publicField(this, "materialMap");
__publicField(this, "imageMap");
__publicField(this, "textures");
__publicField(this, "libraryImages");
__publicField(this, "libraryGeometries");
__publicField(this, "libraryEffects");
__publicField(this, "libraryMaterials");
__publicField(this, "canvas");
__publicField(this, "ctx");
__publicField(this, "transMat");
__publicField(this, "getFuncs", ["getX", "getY", "getZ", "getW"]);
this.options = {
version: "1.4.1",
author: null,
textureDirectory: "",
upAxis: "Y_UP",
unitName: null,
unitMeter: null
};
this.geometryInfo = /* @__PURE__ */ new WeakMap();
this.materialMap = /* @__PURE__ */ new WeakMap();
this.imageMap = /* @__PURE__ */ new WeakMap();
this.textures = [];
this.libraryImages = [];
this.libraryGeometries = [];
this.libraryEffects = [];
this.libraryMaterials = [];
this.canvas = null;
this.ctx = null;
this.transMat = null;
}
parse(object, onDone, options = {}) {
this.options = { ...this.options, ...options };
if (this.options.upAxis.match(/^[XYZ]_UP$/) === null) {
console.error("ColladaExporter: Invalid upAxis: valid values are X_UP, Y_UP or Z_UP.");
return null;
}
if (this.options.unitName !== null && this.options.unitMeter === null) {
console.error("ColladaExporter: unitMeter needs to be specified if unitName is specified.");
return null;
}
if (this.options.unitMeter !== null && this.options.unitName === null) {
console.error("ColladaExporter: unitName needs to be specified if unitMeter is specified.");
return null;
}
if (this.options.textureDirectory !== "") {
this.options.textureDirectory = `${this.options.textureDirectory}/`.replace(/\\/g, "/").replace(/\/+/g, "/");
}
if (this.options.version !== "1.4.1" && this.options.version !== "1.5.0") {
console.warn(`ColladaExporter : Version ${this.options.version} not supported for export. Only 1.4.1 and 1.5.0.`);
return null;
}
const libraryVisualScenes = this.processObject(object);
const specLink = this.options.version === "1.4.1" ? "http://www.collada.org/2005/11/COLLADASchema" : "https://www.khronos.org/collada/";
let dae = `<?xml version="1.0" encoding="UTF-8" standalone="no" ?>${`<COLLADA xmlns="${specLink}" version="${this.options.version}">`}<asset><contributor><authoring_tool>three.js Collada Exporter</authoring_tool>${this.options.author !== null ? `<author>${this.options.author}</author>` : ""}</contributor>${`<created>${(/* @__PURE__ */ new Date()).toISOString()}</created>`}${`<modified>${(/* @__PURE__ */ new Date()).toISOString()}</modified>`}<up_axis>Y_UP</up_axis></asset>`;
dae += `<library_images>${this.libraryImages.join("")}</library_images>`;
dae += `<library_effects>${this.libraryEffects.join("")}</library_effects>`;
dae += `<library_materials>${this.libraryMaterials.join("")}</library_materials>`;
dae += `<library_geometries>${this.libraryGeometries.join("")}</library_geometries>`;
dae += `<library_visual_scenes><visual_scene id="Scene" name="scene">${libraryVisualScenes}</visual_scene></library_visual_scenes>`;
dae += '<scene><instance_visual_scene url="#Scene"/></scene>';
dae += "</COLLADA>";
const res = {
data: this.format(dae),
textures: this.textures
};
if (typeof onDone === "function") {
requestAnimationFrame(() => onDone(res));
}
return res;
}
// Convert the urdf xml into a well-formatted, indented format
format(urdf) {
var _a, _b;
const IS_END_TAG = /^<\//;
const IS_SELF_CLOSING = /(\?>$)|(\/>$)/;
const HAS_TEXT = /<[^>]+>[^<]*<\/[^<]+>/;
const pad = (ch, num) => num > 0 ? ch + pad(ch, num - 1) : "";
let tagnum = 0;
return (_b = (_a = urdf.match(/(<[^>]+>[^<]+<\/[^<]+>)|(<[^>]+>)/g)) == null ? void 0 : _a.map((tag) => {
if (!HAS_TEXT.test(tag) && !IS_SELF_CLOSING.test(tag) && IS_END_TAG.test(tag)) {
tagnum--;
}
const res = `${pad(" ", tagnum)}${tag}`;
if (!HAS_TEXT.test(tag) && !IS_SELF_CLOSING.test(tag) && !IS_END_TAG.test(tag)) {
tagnum++;
}
return res;
}).join("\n")) != null ? _b : "";
}
// Convert an image into a png format for saving
base64ToBuffer(str) {
const b = atob(str);
const buf = new Uint8Array(b.length);
for (let i = 0, l = buf.length; i < l; i++) {
buf[i] = b.charCodeAt(i);
}
return buf;
}
imageToData(image, ext) {
var _a;
this.canvas = this.canvas || document.createElement("canvas");
this.ctx = this.ctx || this.canvas.getContext("2d");
this.canvas.width = image.width instanceof SVGAnimatedLength ? 0 : image.width;
this.canvas.height = image.height instanceof SVGAnimatedLength ? 0 : image.height;
(_a = this.ctx) == null ? void 0 : _a.drawImage(image, 0, 0);
const base64data = this.canvas.toDataURL(`image/${ext}`, 1).replace(/^data:image\/(png|jpg);base64,/, "");
return this.base64ToBuffer(base64data);
}
// gets the attribute array. Generate a new array if the attribute is interleaved
attrBufferToArray(attr) {
if (attr instanceof InterleavedBufferAttribute && attr.isInterleavedBufferAttribute) {
const TypedArrayConstructor = attr.array.constructor;
const arr = new TypedArrayConstructor(attr.count * attr.itemSize);
const size = attr.itemSize;
for (let i = 0, l = attr.count; i < l; i++) {
for (let j = 0; j < size; j++) {
arr[i * size + j] = attr[this.getFuncs[j]](i);
}
}
return arr;
} else {
return attr.array;
}
}
// Returns an array of the same type starting at the `st` index,
// and `ct` length
subArray(arr, st, ct) {
if (Array.isArray(arr)) {
return arr.slice(st, st + ct);
} else {
const TypedArrayConstructor = arr.constructor;
return new TypedArrayConstructor(arr.buffer, st * arr.BYTES_PER_ELEMENT, ct);
}
}
// Returns the string for a geometry's attribute
getAttribute(attr, name, params, type) {
const array = this.attrBufferToArray(attr);
const res = Array.isArray(array) ? `${`<source id="${name}"><float_array id="${name}-array" count="${array.length}">` + array.join(" ")}</float_array><technique_common>${`<accessor source="#${name}-array" count="${Math.floor(
array.length / attr.itemSize
)}" stride="${attr.itemSize}">`}${params.map((n) => `<param name="${n}" type="${type}" />`).join("")}</accessor></technique_common></source>` : "";
return res;
}
// Returns the string for a node's transform information
getTransform(o) {
o.updateMatrix();
this.transMat = this.transMat || new Matrix4();
this.transMat.copy(o.matrix);
this.transMat.transpose();
return `<matrix>${this.transMat.toArray().join(" ")}</matrix>`;
}
// Process the given piece of geometry into the geometry library
// Returns the mesh id
processGeometry(g) {
let info = this.geometryInfo.get(g);
if (!info) {
const bufferGeometry = g;
if (!bufferGeometry.isBufferGeometry) {
throw new Error("THREE.ColladaExporter: Geometry is not of type THREE.BufferGeometry.");
}
const meshid = `Mesh${this.libraryGeometries.length + 1}`;
const indexCount = bufferGeometry.index ? bufferGeometry.index.count * bufferGeometry.index.itemSize : bufferGeometry.attributes.position.count;
const groups = bufferGeometry.groups != null && bufferGeometry.groups.length !== 0 ? bufferGeometry.groups : [{ start: 0, count: indexCount, materialIndex: 0 }];
const gname = g.name ? ` name="${g.name}"` : "";
let gnode = `<geometry id="${meshid}"${gname}><mesh>`;
const posName = `${meshid}-position`;
const vertName = `${meshid}-vertices`;
gnode += this.getAttribute(bufferGeometry.attributes.position, posName, ["X", "Y", "Z"], "float");
gnode += `<vertices id="${vertName}"><input semantic="POSITION" source="#${posName}" /></vertices>`;
let triangleInputs = `<input semantic="VERTEX" source="#${vertName}" offset="0" />`;
if ("normal" in bufferGeometry.attributes) {
const normName = `${meshid}-normal`;
gnode += this.getAttribute(bufferGeometry.attributes.normal, normName, ["X", "Y", "Z"], "float");
triangleInputs += `<input semantic="NORMAL" source="#${normName}" offset="0" />`;
}
if ("uv" in bufferGeometry.attributes) {
const uvName = `${meshid}-texcoord`;
gnode += this.getAttribute(bufferGeometry.attributes.uv, uvName, ["S", "T"], "float");
triangleInputs += `<input semantic="TEXCOORD" source="#${uvName}" offset="0" set="0" />`;
}
if (UV1 in bufferGeometry.attributes) {
const uvName = `${meshid}-texcoord2`;
gnode += this.getAttribute(bufferGeometry.attributes[UV1], uvName, ["S", "T"], "float");
triangleInputs += `<input semantic="TEXCOORD" source="#${uvName}" offset="0" set="1" />`;
}
if ("color" in bufferGeometry.attributes) {
const colName = `${meshid}-color`;
gnode += this.getAttribute(bufferGeometry.attributes.color, colName, ["X", "Y", "Z"], "uint8");
triangleInputs += `<input semantic="COLOR" source="#${colName}" offset="0" />`;
}
let indexArray = null;
if (bufferGeometry.index) {
indexArray = this.attrBufferToArray(bufferGeometry.index);
} else {
indexArray = new Array(indexCount);
for (let i = 0, l = indexArray.length; i < l && Array.isArray(indexArray); i++)
indexArray[i] = i;
}
for (let i = 0, l = groups.length; i < l; i++) {
const group = groups[i];
const subarr = this.subArray(indexArray, group.start, group.count);
const polycount = subarr.length / 3;
gnode += `<triangles material="MESH_MATERIAL_${group.materialIndex}" count="${polycount}">`;
gnode += triangleInputs;
gnode += `<p>${subarr.join(" ")}</p>`;
gnode += "</triangles>";
}
gnode += "</mesh></geometry>";
this.libraryGeometries.push(gnode);
info = { meshid, bufferGeometry };
this.geometryInfo.set(g, info);
}
return info;
}
// Process the given texture into the image library
// Returns the image library
processTexture(tex) {
let texid = this.imageMap.get(tex);
if (texid == null) {
texid = `image-${this.libraryImages.length + 1}`;
const ext = "png";
const name = tex.name || texid;
let imageNode = `<image id="${texid}" name="${name}">`;
if (this.options.version === "1.5.0") {
imageNode += `<init_from><ref>${this.options.textureDirectory}${name}.${ext}</ref></init_from>`;
} else {
imageNode += `<init_from>${this.options.textureDirectory}${name}.${ext}</init_from>`;
}
imageNode += "</image>";
this.libraryImages.push(imageNode);
this.imageMap.set(tex, texid);
this.textures.push({
directory: this.options.textureDirectory,
name,
ext,
data: this.imageToData(tex.image, ext),
original: tex
});
}
return texid;
}
// Process the given material into the material and effect libraries
// Returns the material id
processMaterial(m) {
let matid = this.materialMap.get(m);
if (matid == null) {
matid = `Mat${this.libraryEffects.length + 1}`;
let type = "phong";
if (m instanceof MeshLambertMaterial) {
type = "lambert";
} else if (m instanceof MeshBasicMaterial) {
type = "constant";
if (m.map !== null) {
console.warn("ColladaExporter: Texture maps not supported with MeshBasicMaterial.");
}
}
if (m instanceof MeshPhongMaterial) {
const emissive = m.emissive ? m.emissive : new Color(0, 0, 0);
const diffuse = m.color ? m.color : new Color(0, 0, 0);
const specular = m.specular ? m.specular : new Color(1, 1, 1);
const shininess = m.shininess || 0;
const reflectivity = m.reflectivity || 0;
let transparencyNode = "";
if (m.transparent) {
transparencyNode += `<transparent>${m.map ? '<texture texture="diffuse-sampler"></texture>' : "<float>1</float>"}</transparent>`;
if (m.opacity < 1) {
transparencyNode += `<transparency><float>${m.opacity}</float></transparency>`;
}
}
const techniqueNode = `${`<technique sid="common"><${type}>`}<emission>${m.emissiveMap ? '<texture texture="emissive-sampler" texcoord="TEXCOORD" />' : `<color sid="emission">${emissive.r} ${emissive.g} ${emissive.b} 1</color>`}</emission>${type !== "constant" ? `<diffuse>${m.map ? '<texture texture="diffuse-sampler" texcoord="TEXCOORD" />' : `<color sid="diffuse">${diffuse.r} ${diffuse.g} ${diffuse.b} 1</color>`}</diffuse>` : ""}${type !== "constant" ? `<bump>${m.normalMap ? '<texture texture="bump-sampler" texcoord="TEXCOORD" />' : ""}</bump>` : ""}${type === "phong" ? `${`<specular><color sid="specular">${specular.r} ${specular.g} ${specular.b} 1</color></specular>`}<shininess>${m.specularMap ? '<texture texture="specular-sampler" texcoord="TEXCOORD" />' : `<float sid="shininess">${shininess}</float>`}</shininess>` : ""}${`<reflective><color>${diffuse.r} ${diffuse.g} ${diffuse.b} 1</color></reflective>`}${`<reflectivity><float>${reflectivity}</float></reflectivity>`}${transparencyNode}${`</${type}></technique>`}`;
const effectnode = `${`<effect id="${matid}-effect">`}<profile_COMMON>${m.map ? `<newparam sid="diffuse-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.map
)}</init_from>`}</surface></newparam><newparam sid="diffuse-sampler"><sampler2D><source>diffuse-surface</source></sampler2D></newparam>` : ""}${m.specularMap ? `<newparam sid="specular-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.specularMap
)}</init_from>`}</surface></newparam><newparam sid="specular-sampler"><sampler2D><source>specular-surface</source></sampler2D></newparam>` : ""}${m.emissiveMap ? `<newparam sid="emissive-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.emissiveMap
)}</init_from>`}</surface></newparam><newparam sid="emissive-sampler"><sampler2D><source>emissive-surface</source></sampler2D></newparam>` : ""}${m.normalMap ? `<newparam sid="bump-surface"><surface type="2D">${`<init_from>${this.processTexture(
m.normalMap
)}</init_from>`}</surface></newparam><newparam sid="bump-sampler"><sampler2D><source>bump-surface</source></sampler2D></newparam>` : ""}${techniqueNode}${m.side === DoubleSide ? '<extra><technique profile="THREEJS"><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>' : ""}</profile_COMMON></effect>`;
const materialName = m.name ? ` name="${m.name}"` : "";
const materialNode = `<material id="${matid}"${materialName}><instance_effect url="#${matid}-effect" /></material>`;
this.libraryMaterials.push(materialNode);
this.libraryEffects.push(effectnode);
this.materialMap.set(m, matid);
}
}
return matid;
}
// Recursively process the object into a scene
processObject(o) {
let node = `<node name="${o.name}">`;
node += this.getTransform(o);
const a = new Mesh();
a.geometry;
if (o instanceof Mesh && o.isMesh && o.geometry !== null) {
const geomInfo = this.processGeometry(o.geometry);
const meshid = geomInfo.meshid;
const geometry = geomInfo.bufferGeometry;
let matids = null;
let matidsArray;
const mat = o.material || new MeshBasicMaterial();
const materials = Array.isArray(mat) ? mat : [mat];
if (geometry.groups.length > materials.length) {
matidsArray = new Array(geometry.groups.length);
} else {
matidsArray = new Array(materials.length);
}
matids = matidsArray.fill(null).map((_, i) => this.processMaterial(materials[i % materials.length]));
node += `${`<instance_geometry url="#${meshid}">` + (matids != null ? `<bind_material><technique_common>${matids.map(
(id, i) => `${`<instance_material symbol="MESH_MATERIAL_${i}" target="#${id}" >`}<bind_vertex_input semantic="TEXCOORD" input_semantic="TEXCOORD" input_set="0" /></instance_material>`
).join("")}</technique_common></bind_material>` : "")}</instance_geometry>`;
}
o.children.forEach((c) => node += this.processObject(c));
node += "</node>";
return node;
}
}
export {
ColladaExporter
};
//# sourceMappingURL=ColladaExporter.js.map
File diff suppressed because one or more lines are too long
+153
View File
@@ -0,0 +1,153 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const DRACOExporter = /* @__PURE__ */ (() => {
const _DRACOExporter = class {
parse(object, options = {
decodeSpeed: 5,
encodeSpeed: 5,
encoderMethod: _DRACOExporter.MESH_EDGEBREAKER_ENCODING,
quantization: [16, 8, 8, 8, 8],
exportUvs: true,
exportNormals: true,
exportColor: false
}) {
if (object instanceof THREE.BufferGeometry && object.isBufferGeometry) {
throw new Error("DRACOExporter: The first parameter of parse() is now an instance of Mesh or Points.");
}
if (DracoEncoderModule === void 0) {
throw new Error("THREE.DRACOExporter: required the draco_encoder to work.");
}
const geometry = object.geometry;
const dracoEncoder = DracoEncoderModule();
const encoder = new dracoEncoder.Encoder();
let builder;
let dracoObject;
if (!geometry.isBufferGeometry) {
throw new Error(
"THREE.DRACOExporter.parse(geometry, options): geometry is not a THREE.BufferGeometry instance."
);
}
if (object instanceof THREE.Mesh && object.isMesh) {
builder = new dracoEncoder.MeshBuilder();
dracoObject = new dracoEncoder.Mesh();
const vertices = geometry.getAttribute("position");
builder.AddFloatAttributeToMesh(
dracoObject,
dracoEncoder.POSITION,
vertices.count,
vertices.itemSize,
vertices.array
);
const faces = geometry.getIndex();
if (faces !== null) {
builder.AddFacesToMesh(dracoObject, faces.count / 3, faces.array);
} else {
const faces2 = new (vertices.count > 65535 ? Uint32Array : Uint16Array)(vertices.count);
for (let i = 0; i < faces2.length; i++) {
faces2[i] = i;
}
builder.AddFacesToMesh(dracoObject, vertices.count, faces2);
}
if (options.exportNormals) {
const normals = geometry.getAttribute("normal");
if (normals !== void 0) {
builder.AddFloatAttributeToMesh(
dracoObject,
dracoEncoder.NORMAL,
normals.count,
normals.itemSize,
normals.array
);
}
}
if (options.exportUvs) {
const uvs = geometry.getAttribute("uv");
if (uvs !== void 0) {
builder.AddFloatAttributeToMesh(dracoObject, dracoEncoder.TEX_COORD, uvs.count, uvs.itemSize, uvs.array);
}
}
if (options.exportColor) {
const colors = geometry.getAttribute("color");
if (colors !== void 0) {
builder.AddFloatAttributeToMesh(
dracoObject,
dracoEncoder.COLOR,
colors.count,
colors.itemSize,
colors.array
);
}
}
} else if (object instanceof THREE.Points && object.isPoints) {
builder = new dracoEncoder.PointCloudBuilder();
dracoObject = new dracoEncoder.PointCloud();
const vertices = geometry.getAttribute("position");
builder.AddFloatAttribute(dracoObject, dracoEncoder.POSITION, vertices.count, vertices.itemSize, vertices.array);
if (options.exportColor) {
const colors = geometry.getAttribute("color");
if (colors !== void 0) {
builder.AddFloatAttribute(dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array);
}
}
} else {
throw new Error("DRACOExporter: Unsupported object type.");
}
const encodedData = new dracoEncoder.DracoInt8Array();
const encodeSpeed = options.encodeSpeed !== void 0 ? options.encodeSpeed : 5;
const decodeSpeed = options.decodeSpeed !== void 0 ? options.decodeSpeed : 5;
encoder.SetSpeedOptions(encodeSpeed, decodeSpeed);
if (options.encoderMethod !== void 0) {
encoder.SetEncodingMethod(options.encoderMethod);
}
if (options.quantization !== void 0) {
for (let i = 0; i < 5; i++) {
if (options.quantization[i] !== void 0) {
encoder.SetAttributeQuantization(i, options.quantization[i]);
}
}
}
let length;
if (object instanceof THREE.Mesh && object.isMesh) {
length = encoder.EncodeMeshToDracoBuffer(dracoObject, encodedData);
} else {
length = encoder.EncodePointCloudToDracoBuffer(dracoObject, true, encodedData);
}
dracoEncoder.destroy(dracoObject);
if (length === 0) {
throw new Error("THREE.DRACOExporter: Draco encoding failed.");
}
const outputData = new Int8Array(new ArrayBuffer(length));
for (let i = 0; i < length; i++) {
outputData[i] = encodedData.GetValue(i);
}
dracoEncoder.destroy(encodedData);
dracoEncoder.destroy(encoder);
dracoEncoder.destroy(builder);
return outputData;
}
};
let DRACOExporter2 = _DRACOExporter;
// Encoder methods
__publicField(DRACOExporter2, "MESH_EDGEBREAKER_ENCODING", 1);
__publicField(DRACOExporter2, "MESH_SEQUENTIAL_ENCODING", 0);
// Geometry type
__publicField(DRACOExporter2, "POINT_CLOUD", 0);
__publicField(DRACOExporter2, "TRIANGULAR_MESH", 1);
// Attribute type
__publicField(DRACOExporter2, "INVALID", -1);
__publicField(DRACOExporter2, "POSITION", 0);
__publicField(DRACOExporter2, "NORMAL", 1);
__publicField(DRACOExporter2, "COLOR", 2);
__publicField(DRACOExporter2, "TEX_COORD", 3);
__publicField(DRACOExporter2, "GENERIC", 4);
return DRACOExporter2;
})();
exports.DRACOExporter = DRACOExporter;
//# sourceMappingURL=DRACOExporter.cjs.map
File diff suppressed because one or more lines are too long
+36
View File
@@ -0,0 +1,36 @@
import * as THREE from 'three'
declare class DRACOExporter {
// Encoder methods
public static MESH_EDGEBREAKER_ENCODING: number
public static MESH_SEQUENTIAL_ENCODING: number
// Geometry type
public static POINT_CLOUD: number
public static TRIANGULAR_MESH: number
// Attribute type
public static INVALID: number
public static POSITION: number
public static NORMAL: number
public static COLOR: number
public static TEX_COORD: number
public static GENERIC: number
public parse(
object: THREE.Mesh | THREE.Points,
options?: {
decodeSpeed?: number
encodeSpeed?: number
encoderMethod?: number
quantization?: [number, number, number, number, number]
exportUvs?: boolean
exportNormals?: boolean
exportColor?: boolean
},
): Int8Array
}
export { DRACOExporter }
+153
View File
@@ -0,0 +1,153 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { BufferGeometry, Mesh, Points } from "three";
const DRACOExporter = /* @__PURE__ */ (() => {
const _DRACOExporter = class {
parse(object, options = {
decodeSpeed: 5,
encodeSpeed: 5,
encoderMethod: _DRACOExporter.MESH_EDGEBREAKER_ENCODING,
quantization: [16, 8, 8, 8, 8],
exportUvs: true,
exportNormals: true,
exportColor: false
}) {
if (object instanceof BufferGeometry && object.isBufferGeometry) {
throw new Error("DRACOExporter: The first parameter of parse() is now an instance of Mesh or Points.");
}
if (DracoEncoderModule === void 0) {
throw new Error("THREE.DRACOExporter: required the draco_encoder to work.");
}
const geometry = object.geometry;
const dracoEncoder = DracoEncoderModule();
const encoder = new dracoEncoder.Encoder();
let builder;
let dracoObject;
if (!geometry.isBufferGeometry) {
throw new Error(
"THREE.DRACOExporter.parse(geometry, options): geometry is not a THREE.BufferGeometry instance."
);
}
if (object instanceof Mesh && object.isMesh) {
builder = new dracoEncoder.MeshBuilder();
dracoObject = new dracoEncoder.Mesh();
const vertices = geometry.getAttribute("position");
builder.AddFloatAttributeToMesh(
dracoObject,
dracoEncoder.POSITION,
vertices.count,
vertices.itemSize,
vertices.array
);
const faces = geometry.getIndex();
if (faces !== null) {
builder.AddFacesToMesh(dracoObject, faces.count / 3, faces.array);
} else {
const faces2 = new (vertices.count > 65535 ? Uint32Array : Uint16Array)(vertices.count);
for (let i = 0; i < faces2.length; i++) {
faces2[i] = i;
}
builder.AddFacesToMesh(dracoObject, vertices.count, faces2);
}
if (options.exportNormals) {
const normals = geometry.getAttribute("normal");
if (normals !== void 0) {
builder.AddFloatAttributeToMesh(
dracoObject,
dracoEncoder.NORMAL,
normals.count,
normals.itemSize,
normals.array
);
}
}
if (options.exportUvs) {
const uvs = geometry.getAttribute("uv");
if (uvs !== void 0) {
builder.AddFloatAttributeToMesh(dracoObject, dracoEncoder.TEX_COORD, uvs.count, uvs.itemSize, uvs.array);
}
}
if (options.exportColor) {
const colors = geometry.getAttribute("color");
if (colors !== void 0) {
builder.AddFloatAttributeToMesh(
dracoObject,
dracoEncoder.COLOR,
colors.count,
colors.itemSize,
colors.array
);
}
}
} else if (object instanceof Points && object.isPoints) {
builder = new dracoEncoder.PointCloudBuilder();
dracoObject = new dracoEncoder.PointCloud();
const vertices = geometry.getAttribute("position");
builder.AddFloatAttribute(dracoObject, dracoEncoder.POSITION, vertices.count, vertices.itemSize, vertices.array);
if (options.exportColor) {
const colors = geometry.getAttribute("color");
if (colors !== void 0) {
builder.AddFloatAttribute(dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array);
}
}
} else {
throw new Error("DRACOExporter: Unsupported object type.");
}
const encodedData = new dracoEncoder.DracoInt8Array();
const encodeSpeed = options.encodeSpeed !== void 0 ? options.encodeSpeed : 5;
const decodeSpeed = options.decodeSpeed !== void 0 ? options.decodeSpeed : 5;
encoder.SetSpeedOptions(encodeSpeed, decodeSpeed);
if (options.encoderMethod !== void 0) {
encoder.SetEncodingMethod(options.encoderMethod);
}
if (options.quantization !== void 0) {
for (let i = 0; i < 5; i++) {
if (options.quantization[i] !== void 0) {
encoder.SetAttributeQuantization(i, options.quantization[i]);
}
}
}
let length;
if (object instanceof Mesh && object.isMesh) {
length = encoder.EncodeMeshToDracoBuffer(dracoObject, encodedData);
} else {
length = encoder.EncodePointCloudToDracoBuffer(dracoObject, true, encodedData);
}
dracoEncoder.destroy(dracoObject);
if (length === 0) {
throw new Error("THREE.DRACOExporter: Draco encoding failed.");
}
const outputData = new Int8Array(new ArrayBuffer(length));
for (let i = 0; i < length; i++) {
outputData[i] = encodedData.GetValue(i);
}
dracoEncoder.destroy(encodedData);
dracoEncoder.destroy(encoder);
dracoEncoder.destroy(builder);
return outputData;
}
};
let DRACOExporter2 = _DRACOExporter;
// Encoder methods
__publicField(DRACOExporter2, "MESH_EDGEBREAKER_ENCODING", 1);
__publicField(DRACOExporter2, "MESH_SEQUENTIAL_ENCODING", 0);
// Geometry type
__publicField(DRACOExporter2, "POINT_CLOUD", 0);
__publicField(DRACOExporter2, "TRIANGULAR_MESH", 1);
// Attribute type
__publicField(DRACOExporter2, "INVALID", -1);
__publicField(DRACOExporter2, "POSITION", 0);
__publicField(DRACOExporter2, "NORMAL", 1);
__publicField(DRACOExporter2, "COLOR", 2);
__publicField(DRACOExporter2, "TEX_COORD", 3);
__publicField(DRACOExporter2, "GENERIC", 4);
return DRACOExporter2;
})();
export {
DRACOExporter
};
//# sourceMappingURL=DRACOExporter.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+114
View File
@@ -0,0 +1,114 @@
import { Object3D, AnimationClip, Texture, Material, Mesh } from 'three'
export interface GLTFExporterOptions {
/**
* Export position, rotation and scale instead of matrix per node. Default is false
*/
trs?: boolean
/**
* Export only visible objects. Default is true.
*/
onlyVisible?: boolean
/**
* Export just the attributes within the drawRange, if defined, instead of exporting the whole array. Default is true.
*/
truncateDrawRange?: boolean
/**
* Export in binary (.glb) format, returning an ArrayBuffer. Default is false.
*/
binary?: boolean
/**
* Export with images embedded into the glTF asset. Default is true.
*/
embedImages?: boolean
/**
* Restricts the image maximum size (both width and height) to the given value. This option works only if embedImages is true. Default is Infinity.
*/
maxTextureSize?: number
/**
* List of animations to be included in the export.
*/
animations?: AnimationClip[]
/**
* Generate indices for non-index geometry and export with them. Default is false.
*/
forceIndices?: boolean
/**
* Export custom glTF extensions defined on an object's userData.gltfExtensions property. Default is false.
*/
includeCustomExtensions?: boolean
}
export class GLTFExporter {
constructor()
register(callback: (writer: GLTFWriter) => GLTFExporterPlugin): this
unregister(callback: (writer: GLTFWriter) => GLTFExporterPlugin): this
/**
* Generates a .gltf (JSON) or .glb (binary) output from the input (Scenes or Objects)
*
* @param input Scenes or objects to export. Valid options:
* - Export scenes
* ```js
* exporter.parse( scene1, ... )
* exporter.parse( [ scene1, scene2 ], ... )
* ```
* - Export objects (It will create a new Scene to hold all the objects)
* ```js
* exporter.parse( object1, ... )
* exporter.parse( [ object1, object2 ], ... )
* ```
* - Mix scenes and objects (It will export the scenes as usual but it will create a new scene to hold all the single objects).
* ```js
* exporter.parse( [ scene1, object1, object2, scene2 ], ... )
* ```
* @param onDone Will be called when the export completes. The argument will be the generated glTF JSON or binary ArrayBuffer.
* @param onError Will be called if there are any errors during the gltf generation.
* @param options Export options
*/
parse(
input: Object3D | Object3D[],
onDone: (gltf: ArrayBuffer | { [key: string]: any }) => void,
onError: (error: ErrorEvent) => void,
options?: GLTFExporterOptions,
): void
parseAsync(input: Object3D | Object3D[], options?: GLTFExporterOptions): Promise<ArrayBuffer | { [key: string]: any }>
}
export class GLTFWriter {
constructor()
setPlugins(plugins: GLTFExporterPlugin[]): void
/**
* Parse scenes and generate GLTF output
*
* @param input Scene or Array of THREE.Scenes
* @param onDone Callback on completed
* @param options options
*/
write(
input: Object3D | Object3D[],
onDone: (gltf: ArrayBuffer | { [key: string]: any }) => void,
options?: GLTFExporterOptions,
): Promise<void>
}
export interface GLTFExporterPlugin {
writeTexture?: (map: Texture, textureDef: { [key: string]: any }) => void
writeMaterial?: (material: Material, materialDef: { [key: string]: any }) => void
writeMesh?: (mesh: Mesh, meshDef: { [key: string]: any }) => void
writeNode?: (object: Object3D, nodeDef: { [key: string]: any }) => void
beforeParse?: (input: Object3D | Object3D[]) => void
afterParse?: (input: Object3D | Object3D[]) => void
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+132
View File
@@ -0,0 +1,132 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const mmdparser = require("../libs/mmdparser.cjs");
class MMDExporter {
constructor() {
// Unicode to Shift_JIS table
__publicField(this, "u2sTable");
}
/* TODO: implement
// mesh -> pmd
this.parsePmd = function ( object ) {
};
*/
/* TODO: implement
// mesh -> pmx
this.parsePmx = function ( object ) {
};
*/
/* TODO: implement
// animation + skeleton -> vmd
this.parseVmd = function ( object ) {
};
*/
/*
* skeleton -> vpd
* Returns Shift_JIS encoded Uint8Array. Otherwise return strings.
*/
parseVpd(skin, outputShiftJis, useOriginalBones) {
if (skin.isSkinnedMesh !== true) {
console.warn("THREE.MMDExporter: parseVpd() requires SkinnedMesh instance.");
return null;
}
function toStringsFromNumber(num) {
if (Math.abs(num) < 1e-6)
num = 0;
let a = num.toString();
if (a.indexOf(".") === -1) {
a += ".";
}
a += "000000";
const index = a.indexOf(".");
const d = a.slice(0, index);
const p = a.slice(index + 1, index + 7);
return d + "." + p;
}
function toStringsFromArray(array2) {
const a = [];
for (let i = 0, il = array2.length; i < il; i++) {
a.push(toStringsFromNumber(array2[i]));
}
return a.join(",");
}
skin.updateMatrixWorld(true);
const bones = skin.skeleton.bones;
const bones2 = this.getBindBones(skin);
const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const quaternion2 = new THREE.Quaternion();
const matrix = new THREE.Matrix4();
const array = [];
array.push("Vocaloid Pose Data file");
array.push("");
array.push((skin.name !== "" ? skin.name.replace(/\s/g, "_") : "skin") + ".osm;");
array.push(bones.length + ";");
array.push("");
for (let i = 0, il = bones.length; i < il; i++) {
const bone = bones[i];
const bone2 = bones2[i];
if (useOriginalBones === true && bone.userData.ik !== void 0 && bone.userData.ik.originalMatrix !== void 0) {
matrix.fromArray(bone.userData.ik.originalMatrix);
} else {
matrix.copy(bone.matrix);
}
position.setFromMatrixPosition(matrix);
quaternion.setFromRotationMatrix(matrix);
const pArray = position.sub(bone2.position).toArray();
const qArray = quaternion2.copy(bone2.quaternion).conjugate().multiply(quaternion).toArray();
pArray[2] = -pArray[2];
qArray[0] = -qArray[0];
qArray[1] = -qArray[1];
array.push("Bone" + i + "{" + bone.name);
array.push(" " + toStringsFromArray(pArray) + ";");
array.push(" " + toStringsFromArray(qArray) + ";");
array.push("}");
array.push("");
}
array.push("");
const lines = array.join("\n");
return outputShiftJis === true ? this.unicodeToShiftjis(lines) : lines;
}
unicodeToShiftjis(str) {
if (this.u2sTable === void 0) {
const encoder = new mmdparser.CharsetEncoder();
const table = encoder.s2uTable;
this.u2sTable = {};
const keys = Object.keys(table);
for (let i = 0, il = keys.length; i < il; i++) {
let key = keys[i];
const value = table[key];
this.u2sTable[value] = parseInt(key);
}
}
const array = [];
for (let i = 0, il = str.length; i < il; i++) {
const code = str.charCodeAt(i);
const value = this.u2sTable[code];
if (value === void 0) {
throw "cannot convert charcode 0x" + code.toString(16);
} else if (value > 255) {
array.push(value >> 8 & 255);
array.push(value & 255);
} else {
array.push(value & 255);
}
}
return new Uint8Array(array);
}
getBindBones(skin) {
const poseSkin = skin.clone();
poseSkin.pose();
return poseSkin.skeleton.bones;
}
}
exports.MMDExporter = MMDExporter;
//# sourceMappingURL=MMDExporter.cjs.map
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
import { SkinnedMesh } from 'three';
/**
* Dependencies
* - mmd-parser https://github.com/takahirox/mmd-parser
*/
declare class MMDExporter {
parseVpd(skin: SkinnedMesh, outputShiftJis: boolean, useOriginalBones: boolean): Uint8Array | string | null;
private u2sTable;
private unicodeToShiftjis;
private getBindBones;
}
export { MMDExporter };
+132
View File
@@ -0,0 +1,132 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, Quaternion, Matrix4 } from "three";
import { CharsetEncoder } from "../libs/mmdparser.js";
class MMDExporter {
constructor() {
// Unicode to Shift_JIS table
__publicField(this, "u2sTable");
}
/* TODO: implement
// mesh -> pmd
this.parsePmd = function ( object ) {
};
*/
/* TODO: implement
// mesh -> pmx
this.parsePmx = function ( object ) {
};
*/
/* TODO: implement
// animation + skeleton -> vmd
this.parseVmd = function ( object ) {
};
*/
/*
* skeleton -> vpd
* Returns Shift_JIS encoded Uint8Array. Otherwise return strings.
*/
parseVpd(skin, outputShiftJis, useOriginalBones) {
if (skin.isSkinnedMesh !== true) {
console.warn("THREE.MMDExporter: parseVpd() requires SkinnedMesh instance.");
return null;
}
function toStringsFromNumber(num) {
if (Math.abs(num) < 1e-6)
num = 0;
let a = num.toString();
if (a.indexOf(".") === -1) {
a += ".";
}
a += "000000";
const index = a.indexOf(".");
const d = a.slice(0, index);
const p = a.slice(index + 1, index + 7);
return d + "." + p;
}
function toStringsFromArray(array2) {
const a = [];
for (let i = 0, il = array2.length; i < il; i++) {
a.push(toStringsFromNumber(array2[i]));
}
return a.join(",");
}
skin.updateMatrixWorld(true);
const bones = skin.skeleton.bones;
const bones2 = this.getBindBones(skin);
const position = new Vector3();
const quaternion = new Quaternion();
const quaternion2 = new Quaternion();
const matrix = new Matrix4();
const array = [];
array.push("Vocaloid Pose Data file");
array.push("");
array.push((skin.name !== "" ? skin.name.replace(/\s/g, "_") : "skin") + ".osm;");
array.push(bones.length + ";");
array.push("");
for (let i = 0, il = bones.length; i < il; i++) {
const bone = bones[i];
const bone2 = bones2[i];
if (useOriginalBones === true && bone.userData.ik !== void 0 && bone.userData.ik.originalMatrix !== void 0) {
matrix.fromArray(bone.userData.ik.originalMatrix);
} else {
matrix.copy(bone.matrix);
}
position.setFromMatrixPosition(matrix);
quaternion.setFromRotationMatrix(matrix);
const pArray = position.sub(bone2.position).toArray();
const qArray = quaternion2.copy(bone2.quaternion).conjugate().multiply(quaternion).toArray();
pArray[2] = -pArray[2];
qArray[0] = -qArray[0];
qArray[1] = -qArray[1];
array.push("Bone" + i + "{" + bone.name);
array.push(" " + toStringsFromArray(pArray) + ";");
array.push(" " + toStringsFromArray(qArray) + ";");
array.push("}");
array.push("");
}
array.push("");
const lines = array.join("\n");
return outputShiftJis === true ? this.unicodeToShiftjis(lines) : lines;
}
unicodeToShiftjis(str) {
if (this.u2sTable === void 0) {
const encoder = new CharsetEncoder();
const table = encoder.s2uTable;
this.u2sTable = {};
const keys = Object.keys(table);
for (let i = 0, il = keys.length; i < il; i++) {
let key = keys[i];
const value = table[key];
this.u2sTable[value] = parseInt(key);
}
}
const array = [];
for (let i = 0, il = str.length; i < il; i++) {
const code = str.charCodeAt(i);
const value = this.u2sTable[code];
if (value === void 0) {
throw "cannot convert charcode 0x" + code.toString(16);
} else if (value > 255) {
array.push(value >> 8 & 255);
array.push(value & 255);
} else {
array.push(value & 255);
}
}
return new Uint8Array(array);
}
getBindBones(skin) {
const poseSkin = skin.clone();
poseSkin.pose();
return poseSkin.skeleton.bones;
}
}
export {
MMDExporter
};
//# sourceMappingURL=MMDExporter.js.map
File diff suppressed because one or more lines are too long
+182
View File
@@ -0,0 +1,182 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
class OBJExporter {
constructor() {
__publicField(this, "output");
__publicField(this, "indexVertex");
__publicField(this, "indexVertexUvs");
__publicField(this, "indexNormals");
__publicField(this, "vertex");
__publicField(this, "color");
__publicField(this, "normal");
__publicField(this, "uv");
__publicField(this, "face");
this.output = "";
this.indexVertex = 0;
this.indexVertexUvs = 0;
this.indexNormals = 0;
this.vertex = new THREE.Vector3();
this.color = new THREE.Color();
this.normal = new THREE.Vector3();
this.uv = new THREE.Vector2();
this.face = [];
}
parse(object) {
object.traverse((child) => {
if (child instanceof THREE.Mesh && child.isMesh) {
this.parseMesh(child);
}
if (child instanceof THREE.Line && child.isLine) {
this.parseLine(child);
}
if (child instanceof THREE.Points && child.isPoints) {
this.parsePoints(child);
}
});
return this.output;
}
parseMesh(mesh) {
let nbVertex = 0;
let nbNormals = 0;
let nbVertexUvs = 0;
const geometry = mesh.geometry;
const normalMatrixWorld = new THREE.Matrix3();
if (!geometry.isBufferGeometry) {
throw new Error("THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const indices = geometry.getIndex();
this.output += `o ${mesh.name}
`;
if (mesh.material && !Array.isArray(mesh.material) && mesh.material.name) {
this.output += `usemtl ${mesh.material.name}
`;
}
if (vertices !== void 0) {
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
this.vertex.x = vertices.getX(i);
this.vertex.y = vertices.getY(i);
this.vertex.z = vertices.getZ(i);
this.vertex.applyMatrix4(mesh.matrixWorld);
this.output += `v ${this.vertex.x} ${this.vertex.y} ${this.vertex.z}
`;
}
}
if (uvs !== void 0) {
for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
this.uv.x = uvs.getX(i);
this.uv.y = uvs.getY(i);
this.output += `vt ${this.uv.x} ${this.uv.y}
`;
}
}
if (normals !== void 0) {
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
this.normal.x = normals.getX(i);
this.normal.y = normals.getY(i);
this.normal.z = normals.getZ(i);
this.normal.applyMatrix3(normalMatrixWorld).normalize();
this.output += `vn ${this.normal.x} ${this.normal.y} ${this.normal.z}
`;
}
}
if (indices !== null) {
for (let i = 0, l = indices.count; i < l; i += 3) {
for (let m = 0; m < 3; m++) {
const j = indices.getX(i + m) + 1;
this.face[m] = this.indexVertex + j + (normals || uvs ? `/${uvs ? this.indexVertexUvs + j : ""}${normals ? `/${this.indexNormals + j}` : ""}` : "");
}
this.output += `f ${this.face.join(" ")}
`;
}
} else {
for (let i = 0, l = vertices.count; i < l; i += 3) {
for (let m = 0; m < 3; m++) {
const j = i + m + 1;
this.face[m] = this.indexVertex + j + (normals || uvs ? `/${uvs ? this.indexVertexUvs + j : ""}${normals ? `/${this.indexNormals + j}` : ""}` : "");
}
this.output += `f ${this.face.join(" ")}
`;
}
}
this.indexVertex += nbVertex;
this.indexVertexUvs += nbVertexUvs;
this.indexNormals += nbNormals;
}
parseLine(line) {
let nbVertex = 0;
const geometry = line.geometry;
const type = line.type;
if (geometry.isBufferGeometry) {
throw new Error("THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
this.output += `o ${line.name}
`;
if (vertices !== void 0) {
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
this.vertex.x = vertices.getX(i);
this.vertex.y = vertices.getY(i);
this.vertex.z = vertices.getZ(i);
this.vertex.applyMatrix4(line.matrixWorld);
this.output += `v ${this.vertex.x} ${this.vertex.y} ${this.vertex.z}
`;
}
}
if (type === "Line") {
this.output += "l ";
for (let j = 1, l = vertices.count; j <= l; j++) {
this.output += `${this.indexVertex + j} `;
}
this.output += "\n";
}
if (type === "LineSegments") {
for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
this.output += `l ${this.indexVertex + j} ${this.indexVertex + k}
`;
}
}
this.indexVertex += nbVertex;
}
parsePoints(points) {
let nbVertex = 0;
const geometry = points.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
const colors = geometry.getAttribute("color");
this.output += `o ${points.name}
`;
if (vertices !== void 0) {
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
this.vertex.fromBufferAttribute(vertices, i);
this.vertex.applyMatrix4(points.matrixWorld);
this.output += `v ${this.vertex.x} ${this.vertex.y} ${this.vertex.z}`;
if (colors !== void 0 && colors instanceof THREE.BufferAttribute) {
this.color.fromBufferAttribute(colors, i);
this.output += ` ${this.color.r} ${this.color.g} ${this.color.b}`;
}
this.output += "\n";
}
}
this.output += "p ";
for (let j = 1, l = vertices.count; j <= l; j++) {
this.output += `${this.indexVertex + j} `;
}
this.output += "\n";
this.indexVertex += nbVertex;
}
}
exports.OBJExporter = OBJExporter;
//# sourceMappingURL=OBJExporter.cjs.map
File diff suppressed because one or more lines are too long
+18
View File
@@ -0,0 +1,18 @@
import { Object3D } from 'three';
declare class OBJExporter {
private output;
private indexVertex;
private indexVertexUvs;
private indexNormals;
private vertex;
private color;
private normal;
private uv;
private face;
constructor();
parse(object: Object3D): string;
private parseMesh;
private parseLine;
private parsePoints;
}
export { OBJExporter };
+182
View File
@@ -0,0 +1,182 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, Color, Vector2, Mesh, Line, Points, Matrix3, BufferAttribute } from "three";
class OBJExporter {
constructor() {
__publicField(this, "output");
__publicField(this, "indexVertex");
__publicField(this, "indexVertexUvs");
__publicField(this, "indexNormals");
__publicField(this, "vertex");
__publicField(this, "color");
__publicField(this, "normal");
__publicField(this, "uv");
__publicField(this, "face");
this.output = "";
this.indexVertex = 0;
this.indexVertexUvs = 0;
this.indexNormals = 0;
this.vertex = new Vector3();
this.color = new Color();
this.normal = new Vector3();
this.uv = new Vector2();
this.face = [];
}
parse(object) {
object.traverse((child) => {
if (child instanceof Mesh && child.isMesh) {
this.parseMesh(child);
}
if (child instanceof Line && child.isLine) {
this.parseLine(child);
}
if (child instanceof Points && child.isPoints) {
this.parsePoints(child);
}
});
return this.output;
}
parseMesh(mesh) {
let nbVertex = 0;
let nbNormals = 0;
let nbVertexUvs = 0;
const geometry = mesh.geometry;
const normalMatrixWorld = new Matrix3();
if (!geometry.isBufferGeometry) {
throw new Error("THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const indices = geometry.getIndex();
this.output += `o ${mesh.name}
`;
if (mesh.material && !Array.isArray(mesh.material) && mesh.material.name) {
this.output += `usemtl ${mesh.material.name}
`;
}
if (vertices !== void 0) {
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
this.vertex.x = vertices.getX(i);
this.vertex.y = vertices.getY(i);
this.vertex.z = vertices.getZ(i);
this.vertex.applyMatrix4(mesh.matrixWorld);
this.output += `v ${this.vertex.x} ${this.vertex.y} ${this.vertex.z}
`;
}
}
if (uvs !== void 0) {
for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
this.uv.x = uvs.getX(i);
this.uv.y = uvs.getY(i);
this.output += `vt ${this.uv.x} ${this.uv.y}
`;
}
}
if (normals !== void 0) {
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
this.normal.x = normals.getX(i);
this.normal.y = normals.getY(i);
this.normal.z = normals.getZ(i);
this.normal.applyMatrix3(normalMatrixWorld).normalize();
this.output += `vn ${this.normal.x} ${this.normal.y} ${this.normal.z}
`;
}
}
if (indices !== null) {
for (let i = 0, l = indices.count; i < l; i += 3) {
for (let m = 0; m < 3; m++) {
const j = indices.getX(i + m) + 1;
this.face[m] = this.indexVertex + j + (normals || uvs ? `/${uvs ? this.indexVertexUvs + j : ""}${normals ? `/${this.indexNormals + j}` : ""}` : "");
}
this.output += `f ${this.face.join(" ")}
`;
}
} else {
for (let i = 0, l = vertices.count; i < l; i += 3) {
for (let m = 0; m < 3; m++) {
const j = i + m + 1;
this.face[m] = this.indexVertex + j + (normals || uvs ? `/${uvs ? this.indexVertexUvs + j : ""}${normals ? `/${this.indexNormals + j}` : ""}` : "");
}
this.output += `f ${this.face.join(" ")}
`;
}
}
this.indexVertex += nbVertex;
this.indexVertexUvs += nbVertexUvs;
this.indexNormals += nbNormals;
}
parseLine(line) {
let nbVertex = 0;
const geometry = line.geometry;
const type = line.type;
if (geometry.isBufferGeometry) {
throw new Error("THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
this.output += `o ${line.name}
`;
if (vertices !== void 0) {
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
this.vertex.x = vertices.getX(i);
this.vertex.y = vertices.getY(i);
this.vertex.z = vertices.getZ(i);
this.vertex.applyMatrix4(line.matrixWorld);
this.output += `v ${this.vertex.x} ${this.vertex.y} ${this.vertex.z}
`;
}
}
if (type === "Line") {
this.output += "l ";
for (let j = 1, l = vertices.count; j <= l; j++) {
this.output += `${this.indexVertex + j} `;
}
this.output += "\n";
}
if (type === "LineSegments") {
for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
this.output += `l ${this.indexVertex + j} ${this.indexVertex + k}
`;
}
}
this.indexVertex += nbVertex;
}
parsePoints(points) {
let nbVertex = 0;
const geometry = points.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
const colors = geometry.getAttribute("color");
this.output += `o ${points.name}
`;
if (vertices !== void 0) {
for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
this.vertex.fromBufferAttribute(vertices, i);
this.vertex.applyMatrix4(points.matrixWorld);
this.output += `v ${this.vertex.x} ${this.vertex.y} ${this.vertex.z}`;
if (colors !== void 0 && colors instanceof BufferAttribute) {
this.color.fromBufferAttribute(colors, i);
this.output += ` ${this.color.r} ${this.color.g} ${this.color.b}`;
}
this.output += "\n";
}
}
this.output += "p ";
for (let j = 1, l = vertices.count; j <= l; j++) {
this.output += `${this.indexVertex + j} `;
}
this.output += "\n";
this.indexVertex += nbVertex;
}
}
export {
OBJExporter
};
//# sourceMappingURL=OBJExporter.js.map
File diff suppressed because one or more lines are too long
+281
View File
@@ -0,0 +1,281 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
class PLYExporter {
parse(object, onDone, options) {
if (onDone && typeof onDone === "object") {
console.warn(
'THREE.PLYExporter: The options parameter is now the third argument to the "parse" function. See the documentation for the new API.'
);
options = onDone;
onDone = void 0;
}
const defaultOptions = {
binary: false,
excludeAttributes: [],
// normal, uv, color, index
littleEndian: false
};
options = Object.assign(defaultOptions, options);
const excludeAttributes = options.excludeAttributes;
let includeNormals = false;
let includeColors = false;
let includeUVs = false;
let vertexCount = 0;
let faceCount = 0;
object.traverse(function(child) {
if (child instanceof THREE.Mesh && child.isMesh) {
const mesh = child;
const geometry = mesh.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const colors = geometry.getAttribute("color");
const indices = geometry.getIndex();
if (vertices === void 0) {
return;
}
vertexCount += vertices.count;
faceCount += indices ? indices.count / 3 : vertices.count / 3;
if (normals !== void 0)
includeNormals = true;
if (uvs !== void 0)
includeUVs = true;
if (colors !== void 0)
includeColors = true;
}
});
const includeIndices = (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("index")) === -1;
includeNormals = includeNormals && (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("normal")) === -1;
includeColors = includeColors && (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("color")) === -1;
includeUVs = includeUVs && (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("uv")) === -1;
if (includeIndices && faceCount !== Math.floor(faceCount)) {
console.error(
"PLYExporter: Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3."
);
return null;
}
const indexByteCount = 4;
let header = `ply
format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
element vertex ${vertexCount}
property float x
property float y
property float z
`;
if (includeNormals) {
header += "property float nx\nproperty float ny\nproperty float nz\n";
}
if (includeUVs) {
header += "property float s\nproperty float t\n";
}
if (includeColors) {
header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
}
if (includeIndices) {
header += `${`element face ${faceCount}
`}property list uchar int vertex_index
`;
}
header += "end_header\n";
const vertex = new THREE.Vector3();
const normalMatrixWorld = new THREE.Matrix3();
let result = null;
if (options.binary) {
const headerBin = new TextEncoder().encode(header);
const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
new Uint8Array(output.buffer).set(headerBin, 0);
let vOffset = headerBin.length;
let fOffset = headerBin.length + vertexListLength;
let writtenVertices = 0;
this.traverseMeshes(object, function(mesh, geometry) {
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const colors = geometry.getAttribute("color");
const indices = geometry.getIndex();
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (let i = 0, l = vertices.count; i < l; i++) {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
vertex.applyMatrix4(mesh.matrixWorld);
output.setFloat32(vOffset, vertex.x, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.y, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.z, options.littleEndian);
vOffset += 4;
if (includeNormals) {
if (normals != null) {
vertex.x = normals.getX(i);
vertex.y = normals.getY(i);
vertex.z = normals.getZ(i);
vertex.applyMatrix3(normalMatrixWorld).normalize();
output.setFloat32(vOffset, vertex.x, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.y, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.z, options.littleEndian);
vOffset += 4;
} else {
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
}
}
if (includeUVs) {
if (uvs != null) {
output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
vOffset += 4;
} else if (!includeUVs) {
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
}
}
if (includeColors) {
if (colors != null) {
output.setUint8(vOffset, Math.floor(colors.getX(i) * 255));
vOffset += 1;
output.setUint8(vOffset, Math.floor(colors.getY(i) * 255));
vOffset += 1;
output.setUint8(vOffset, Math.floor(colors.getZ(i) * 255));
vOffset += 1;
} else {
output.setUint8(vOffset, 255);
vOffset += 1;
output.setUint8(vOffset, 255);
vOffset += 1;
output.setUint8(vOffset, 255);
vOffset += 1;
}
}
}
if (includeIndices) {
if (indices !== null) {
for (let i = 0, l = indices.count; i < l; i += 3) {
output.setUint8(fOffset, 3);
fOffset += 1;
output.setUint32(fOffset, indices.getX(i + 0) + writtenVertices, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, indices.getX(i + 1) + writtenVertices, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, indices.getX(i + 2) + writtenVertices, options.littleEndian);
fOffset += indexByteCount;
}
} else {
for (let i = 0, l = vertices.count; i < l; i += 3) {
output.setUint8(fOffset, 3);
fOffset += 1;
output.setUint32(fOffset, writtenVertices + i, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, writtenVertices + i + 1, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, writtenVertices + i + 2, options.littleEndian);
fOffset += indexByteCount;
}
}
}
writtenVertices += vertices.count;
});
result = output.buffer;
} else {
let writtenVertices = 0;
let vertexList = "";
let faceList = "";
this.traverseMeshes(object, function(mesh, geometry) {
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const colors = geometry.getAttribute("color");
const indices = geometry.getIndex();
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (let i = 0, l = vertices.count; i < l; i++) {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
vertex.applyMatrix4(mesh.matrixWorld);
let line = vertex.x + " " + vertex.y + " " + vertex.z;
if (includeNormals) {
if (normals != null) {
vertex.x = normals.getX(i);
vertex.y = normals.getY(i);
vertex.z = normals.getZ(i);
vertex.applyMatrix3(normalMatrixWorld).normalize();
line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
} else {
line += " 0 0 0";
}
}
if (includeUVs) {
if (uvs != null) {
line += " " + uvs.getX(i) + " " + uvs.getY(i);
} else if (includeUVs) {
line += " 0 0";
}
}
if (includeColors) {
if (colors != null) {
line += " " + Math.floor(colors.getX(i) * 255) + " " + Math.floor(colors.getY(i) * 255) + " " + Math.floor(colors.getZ(i) * 255);
} else {
line += " 255 255 255";
}
}
vertexList += line + "\n";
}
if (includeIndices) {
if (indices !== null) {
for (let i = 0, l = indices.count; i < l; i += 3) {
faceList += `3 ${indices.getX(i + 0) + writtenVertices}`;
faceList += ` ${indices.getX(i + 1) + writtenVertices}`;
faceList += ` ${indices.getX(i + 2) + writtenVertices}
`;
}
} else {
for (let i = 0, l = vertices.count; i < l; i += 3) {
faceList += `3 ${writtenVertices + i} ${writtenVertices + i + 1} ${writtenVertices + i + 2}
`;
}
}
faceCount += indices ? indices.count / 3 : vertices.count / 3;
}
writtenVertices += vertices.count;
});
result = `${header}${vertexList}${includeIndices ? `${faceList}
` : "\n"}`;
}
if (typeof onDone === "function") {
requestAnimationFrame(() => onDone && onDone(typeof result === "string" ? result : ""));
}
return result;
}
// Iterate over the valid meshes in the object
traverseMeshes(object, cb) {
object.traverse(function(child) {
if (child instanceof THREE.Mesh && child.isMesh) {
const mesh = child;
const geometry = mesh.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.");
}
if (geometry.hasAttribute("position")) {
cb(mesh, geometry);
}
}
});
}
}
exports.PLYExporter = PLYExporter;
//# sourceMappingURL=PLYExporter.cjs.map
File diff suppressed because one or more lines are too long
+23
View File
@@ -0,0 +1,23 @@
import { Object3D } from 'three';
/**
* https://github.com/gkjohnson/ply-exporter-js
*
* Usage:
* const exporter = new PLYExporter();
*
* // second argument is a list of options
* exporter.parse(mesh, data => console.log(data), { binary: true, excludeAttributes: [ 'color' ], littleEndian: true });
*
* Format Definition:
* http://paulbourke.net/dataformats/ply/
*/
export interface PLYExporterOptions {
binary?: boolean;
excludeAttributes?: string[];
littleEndian?: boolean;
}
declare class PLYExporter {
parse(object: Object3D, onDone: ((res: string) => void) | undefined, options: PLYExporterOptions): string | ArrayBuffer | null;
private traverseMeshes;
}
export { PLYExporter };
+281
View File
@@ -0,0 +1,281 @@
import { Mesh, Vector3, Matrix3 } from "three";
class PLYExporter {
parse(object, onDone, options) {
if (onDone && typeof onDone === "object") {
console.warn(
'THREE.PLYExporter: The options parameter is now the third argument to the "parse" function. See the documentation for the new API.'
);
options = onDone;
onDone = void 0;
}
const defaultOptions = {
binary: false,
excludeAttributes: [],
// normal, uv, color, index
littleEndian: false
};
options = Object.assign(defaultOptions, options);
const excludeAttributes = options.excludeAttributes;
let includeNormals = false;
let includeColors = false;
let includeUVs = false;
let vertexCount = 0;
let faceCount = 0;
object.traverse(function(child) {
if (child instanceof Mesh && child.isMesh) {
const mesh = child;
const geometry = mesh.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.");
}
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const colors = geometry.getAttribute("color");
const indices = geometry.getIndex();
if (vertices === void 0) {
return;
}
vertexCount += vertices.count;
faceCount += indices ? indices.count / 3 : vertices.count / 3;
if (normals !== void 0)
includeNormals = true;
if (uvs !== void 0)
includeUVs = true;
if (colors !== void 0)
includeColors = true;
}
});
const includeIndices = (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("index")) === -1;
includeNormals = includeNormals && (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("normal")) === -1;
includeColors = includeColors && (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("color")) === -1;
includeUVs = includeUVs && (excludeAttributes == null ? void 0 : excludeAttributes.indexOf("uv")) === -1;
if (includeIndices && faceCount !== Math.floor(faceCount)) {
console.error(
"PLYExporter: Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3."
);
return null;
}
const indexByteCount = 4;
let header = `ply
format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
element vertex ${vertexCount}
property float x
property float y
property float z
`;
if (includeNormals) {
header += "property float nx\nproperty float ny\nproperty float nz\n";
}
if (includeUVs) {
header += "property float s\nproperty float t\n";
}
if (includeColors) {
header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
}
if (includeIndices) {
header += `${`element face ${faceCount}
`}property list uchar int vertex_index
`;
}
header += "end_header\n";
const vertex = new Vector3();
const normalMatrixWorld = new Matrix3();
let result = null;
if (options.binary) {
const headerBin = new TextEncoder().encode(header);
const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
new Uint8Array(output.buffer).set(headerBin, 0);
let vOffset = headerBin.length;
let fOffset = headerBin.length + vertexListLength;
let writtenVertices = 0;
this.traverseMeshes(object, function(mesh, geometry) {
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const colors = geometry.getAttribute("color");
const indices = geometry.getIndex();
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (let i = 0, l = vertices.count; i < l; i++) {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
vertex.applyMatrix4(mesh.matrixWorld);
output.setFloat32(vOffset, vertex.x, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.y, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.z, options.littleEndian);
vOffset += 4;
if (includeNormals) {
if (normals != null) {
vertex.x = normals.getX(i);
vertex.y = normals.getY(i);
vertex.z = normals.getZ(i);
vertex.applyMatrix3(normalMatrixWorld).normalize();
output.setFloat32(vOffset, vertex.x, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.y, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, vertex.z, options.littleEndian);
vOffset += 4;
} else {
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
}
}
if (includeUVs) {
if (uvs != null) {
output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
vOffset += 4;
} else if (!includeUVs) {
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
output.setFloat32(vOffset, 0, options.littleEndian);
vOffset += 4;
}
}
if (includeColors) {
if (colors != null) {
output.setUint8(vOffset, Math.floor(colors.getX(i) * 255));
vOffset += 1;
output.setUint8(vOffset, Math.floor(colors.getY(i) * 255));
vOffset += 1;
output.setUint8(vOffset, Math.floor(colors.getZ(i) * 255));
vOffset += 1;
} else {
output.setUint8(vOffset, 255);
vOffset += 1;
output.setUint8(vOffset, 255);
vOffset += 1;
output.setUint8(vOffset, 255);
vOffset += 1;
}
}
}
if (includeIndices) {
if (indices !== null) {
for (let i = 0, l = indices.count; i < l; i += 3) {
output.setUint8(fOffset, 3);
fOffset += 1;
output.setUint32(fOffset, indices.getX(i + 0) + writtenVertices, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, indices.getX(i + 1) + writtenVertices, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, indices.getX(i + 2) + writtenVertices, options.littleEndian);
fOffset += indexByteCount;
}
} else {
for (let i = 0, l = vertices.count; i < l; i += 3) {
output.setUint8(fOffset, 3);
fOffset += 1;
output.setUint32(fOffset, writtenVertices + i, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, writtenVertices + i + 1, options.littleEndian);
fOffset += indexByteCount;
output.setUint32(fOffset, writtenVertices + i + 2, options.littleEndian);
fOffset += indexByteCount;
}
}
}
writtenVertices += vertices.count;
});
result = output.buffer;
} else {
let writtenVertices = 0;
let vertexList = "";
let faceList = "";
this.traverseMeshes(object, function(mesh, geometry) {
const vertices = geometry.getAttribute("position");
const normals = geometry.getAttribute("normal");
const uvs = geometry.getAttribute("uv");
const colors = geometry.getAttribute("color");
const indices = geometry.getIndex();
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (let i = 0, l = vertices.count; i < l; i++) {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
vertex.applyMatrix4(mesh.matrixWorld);
let line = vertex.x + " " + vertex.y + " " + vertex.z;
if (includeNormals) {
if (normals != null) {
vertex.x = normals.getX(i);
vertex.y = normals.getY(i);
vertex.z = normals.getZ(i);
vertex.applyMatrix3(normalMatrixWorld).normalize();
line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
} else {
line += " 0 0 0";
}
}
if (includeUVs) {
if (uvs != null) {
line += " " + uvs.getX(i) + " " + uvs.getY(i);
} else if (includeUVs) {
line += " 0 0";
}
}
if (includeColors) {
if (colors != null) {
line += " " + Math.floor(colors.getX(i) * 255) + " " + Math.floor(colors.getY(i) * 255) + " " + Math.floor(colors.getZ(i) * 255);
} else {
line += " 255 255 255";
}
}
vertexList += line + "\n";
}
if (includeIndices) {
if (indices !== null) {
for (let i = 0, l = indices.count; i < l; i += 3) {
faceList += `3 ${indices.getX(i + 0) + writtenVertices}`;
faceList += ` ${indices.getX(i + 1) + writtenVertices}`;
faceList += ` ${indices.getX(i + 2) + writtenVertices}
`;
}
} else {
for (let i = 0, l = vertices.count; i < l; i += 3) {
faceList += `3 ${writtenVertices + i} ${writtenVertices + i + 1} ${writtenVertices + i + 2}
`;
}
}
faceCount += indices ? indices.count / 3 : vertices.count / 3;
}
writtenVertices += vertices.count;
});
result = `${header}${vertexList}${includeIndices ? `${faceList}
` : "\n"}`;
}
if (typeof onDone === "function") {
requestAnimationFrame(() => onDone && onDone(typeof result === "string" ? result : ""));
}
return result;
}
// Iterate over the valid meshes in the object
traverseMeshes(object, cb) {
object.traverse(function(child) {
if (child instanceof Mesh && child.isMesh) {
const mesh = child;
const geometry = mesh.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.");
}
if (geometry.hasAttribute("position")) {
cb(mesh, geometry);
}
}
});
}
}
export {
PLYExporter
};
//# sourceMappingURL=PLYExporter.js.map
File diff suppressed because one or more lines are too long
+145
View File
@@ -0,0 +1,145 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const isMesh = (object) => object.isMesh;
class STLExporter {
constructor() {
__publicField(this, "binary", false);
__publicField(this, "output", "");
__publicField(this, "offset", 80);
// skip header
__publicField(this, "objects", []);
__publicField(this, "triangles", 0);
__publicField(this, "vA", new THREE.Vector3());
__publicField(this, "vB", new THREE.Vector3());
__publicField(this, "vC", new THREE.Vector3());
__publicField(this, "cb", new THREE.Vector3());
__publicField(this, "ab", new THREE.Vector3());
__publicField(this, "normal", new THREE.Vector3());
}
parse(scene, options) {
this.binary = (options == null ? void 0 : options.binary) !== void 0 ? options == null ? void 0 : options.binary : false;
scene.traverse((object) => {
if (isMesh(object)) {
const geometry = object.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.");
}
const index = geometry.index;
const positionAttribute = geometry.getAttribute("position") || null;
if (!positionAttribute)
return;
this.triangles += index !== null ? index.count / 3 : positionAttribute.count / 3;
this.objects.push({
object3d: object,
geometry
});
}
});
if (this.binary) {
const bufferLength = this.triangles * 2 + this.triangles * 3 * 4 * 4 + 80 + 4;
const arrayBuffer = new ArrayBuffer(bufferLength);
this.output = new DataView(arrayBuffer);
this.output.setUint32(this.offset, this.triangles, true);
this.offset += 4;
} else {
this.output = "";
this.output += "solid exported\n";
}
for (let i = 0, il = this.objects.length; i < il; i++) {
const object = this.objects[i].object3d;
const geometry = this.objects[i].geometry;
const index = geometry.index;
const positionAttribute = geometry.getAttribute("position");
if (index !== null) {
for (let j = 0; j < index.count; j += 3) {
const a = index.getX(j + 0);
const b = index.getX(j + 1);
const c = index.getX(j + 2);
this.writeFace(a, b, c, positionAttribute, object);
}
} else {
for (let j = 0; j < positionAttribute.count; j += 3) {
const a = j + 0;
const b = j + 1;
const c = j + 2;
this.writeFace(a, b, c, positionAttribute, object);
}
}
}
if (!this.binary) {
this.output += "endsolid exported\n";
}
return this.output;
}
writeFace(a, b, c, positionAttribute, object) {
this.vA.fromBufferAttribute(positionAttribute, a);
this.vB.fromBufferAttribute(positionAttribute, b);
this.vC.fromBufferAttribute(positionAttribute, c);
if (object.isSkinnedMesh) {
const mesh = object;
if ("applyBoneTransform" in mesh) {
mesh.applyBoneTransform(a, this.vA);
mesh.applyBoneTransform(b, this.vB);
mesh.applyBoneTransform(c, this.vC);
} else {
mesh.boneTransform(a, this.vA);
mesh.boneTransform(b, this.vB);
mesh.boneTransform(c, this.vC);
}
}
this.vA.applyMatrix4(object.matrixWorld);
this.vB.applyMatrix4(object.matrixWorld);
this.vC.applyMatrix4(object.matrixWorld);
this.writeNormal(this.vA, this.vB, this.vC);
this.writeVertex(this.vA);
this.writeVertex(this.vB);
this.writeVertex(this.vC);
if (this.binary && this.output instanceof DataView) {
this.output.setUint16(this.offset, 0, true);
this.offset += 2;
} else {
this.output += " endloop\n";
this.output += " endfacet\n";
}
}
writeNormal(vA, vB, vC) {
this.cb.subVectors(vC, vB);
this.ab.subVectors(vA, vB);
this.cb.cross(this.ab).normalize();
this.normal.copy(this.cb).normalize();
if (this.binary && this.output instanceof DataView) {
this.output.setFloat32(this.offset, this.normal.x, true);
this.offset += 4;
this.output.setFloat32(this.offset, this.normal.y, true);
this.offset += 4;
this.output.setFloat32(this.offset, this.normal.z, true);
this.offset += 4;
} else {
this.output += ` facet normal ${this.normal.x} ${this.normal.y} ${this.normal.z}
`;
this.output += " outer loop\n";
}
}
writeVertex(vertex) {
if (this.binary && this.output instanceof DataView) {
this.output.setFloat32(this.offset, vertex.x, true);
this.offset += 4;
this.output.setFloat32(this.offset, vertex.y, true);
this.offset += 4;
this.output.setFloat32(this.offset, vertex.z, true);
this.offset += 4;
} else {
this.output += ` vertex ${vertex.x} ${vertex.y} ${vertex.z}
`;
}
}
}
exports.STLExporter = STLExporter;
//# sourceMappingURL=STLExporter.cjs.map
File diff suppressed because one or more lines are too long
+28
View File
@@ -0,0 +1,28 @@
import { Object3D } from 'three';
export interface STLExporterOptionsBinary {
binary: true;
}
export interface STLExporterOptionsString {
binary?: false;
}
export interface STLExporterOptions {
binary?: boolean;
}
export declare class STLExporter {
private binary;
private output;
private offset;
private objects;
private triangles;
private vA;
private vB;
private vC;
private cb;
private ab;
private normal;
parse(scene: Object3D, options: STLExporterOptionsBinary): DataView;
parse(scene: Object3D, options?: STLExporterOptionsString): string;
private writeFace;
private writeNormal;
private writeVertex;
}
+145
View File
@@ -0,0 +1,145 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3 } from "three";
const isMesh = (object) => object.isMesh;
class STLExporter {
constructor() {
__publicField(this, "binary", false);
__publicField(this, "output", "");
__publicField(this, "offset", 80);
// skip header
__publicField(this, "objects", []);
__publicField(this, "triangles", 0);
__publicField(this, "vA", new Vector3());
__publicField(this, "vB", new Vector3());
__publicField(this, "vC", new Vector3());
__publicField(this, "cb", new Vector3());
__publicField(this, "ab", new Vector3());
__publicField(this, "normal", new Vector3());
}
parse(scene, options) {
this.binary = (options == null ? void 0 : options.binary) !== void 0 ? options == null ? void 0 : options.binary : false;
scene.traverse((object) => {
if (isMesh(object)) {
const geometry = object.geometry;
if (!geometry.isBufferGeometry) {
throw new Error("THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.");
}
const index = geometry.index;
const positionAttribute = geometry.getAttribute("position") || null;
if (!positionAttribute)
return;
this.triangles += index !== null ? index.count / 3 : positionAttribute.count / 3;
this.objects.push({
object3d: object,
geometry
});
}
});
if (this.binary) {
const bufferLength = this.triangles * 2 + this.triangles * 3 * 4 * 4 + 80 + 4;
const arrayBuffer = new ArrayBuffer(bufferLength);
this.output = new DataView(arrayBuffer);
this.output.setUint32(this.offset, this.triangles, true);
this.offset += 4;
} else {
this.output = "";
this.output += "solid exported\n";
}
for (let i = 0, il = this.objects.length; i < il; i++) {
const object = this.objects[i].object3d;
const geometry = this.objects[i].geometry;
const index = geometry.index;
const positionAttribute = geometry.getAttribute("position");
if (index !== null) {
for (let j = 0; j < index.count; j += 3) {
const a = index.getX(j + 0);
const b = index.getX(j + 1);
const c = index.getX(j + 2);
this.writeFace(a, b, c, positionAttribute, object);
}
} else {
for (let j = 0; j < positionAttribute.count; j += 3) {
const a = j + 0;
const b = j + 1;
const c = j + 2;
this.writeFace(a, b, c, positionAttribute, object);
}
}
}
if (!this.binary) {
this.output += "endsolid exported\n";
}
return this.output;
}
writeFace(a, b, c, positionAttribute, object) {
this.vA.fromBufferAttribute(positionAttribute, a);
this.vB.fromBufferAttribute(positionAttribute, b);
this.vC.fromBufferAttribute(positionAttribute, c);
if (object.isSkinnedMesh) {
const mesh = object;
if ("applyBoneTransform" in mesh) {
mesh.applyBoneTransform(a, this.vA);
mesh.applyBoneTransform(b, this.vB);
mesh.applyBoneTransform(c, this.vC);
} else {
mesh.boneTransform(a, this.vA);
mesh.boneTransform(b, this.vB);
mesh.boneTransform(c, this.vC);
}
}
this.vA.applyMatrix4(object.matrixWorld);
this.vB.applyMatrix4(object.matrixWorld);
this.vC.applyMatrix4(object.matrixWorld);
this.writeNormal(this.vA, this.vB, this.vC);
this.writeVertex(this.vA);
this.writeVertex(this.vB);
this.writeVertex(this.vC);
if (this.binary && this.output instanceof DataView) {
this.output.setUint16(this.offset, 0, true);
this.offset += 2;
} else {
this.output += " endloop\n";
this.output += " endfacet\n";
}
}
writeNormal(vA, vB, vC) {
this.cb.subVectors(vC, vB);
this.ab.subVectors(vA, vB);
this.cb.cross(this.ab).normalize();
this.normal.copy(this.cb).normalize();
if (this.binary && this.output instanceof DataView) {
this.output.setFloat32(this.offset, this.normal.x, true);
this.offset += 4;
this.output.setFloat32(this.offset, this.normal.y, true);
this.offset += 4;
this.output.setFloat32(this.offset, this.normal.z, true);
this.offset += 4;
} else {
this.output += ` facet normal ${this.normal.x} ${this.normal.y} ${this.normal.z}
`;
this.output += " outer loop\n";
}
}
writeVertex(vertex) {
if (this.binary && this.output instanceof DataView) {
this.output.setFloat32(this.offset, vertex.x, true);
this.offset += 4;
this.output.setFloat32(this.offset, vertex.y, true);
this.offset += 4;
this.output.setFloat32(this.offset, vertex.z, true);
this.offset += 4;
} else {
this.output += ` vertex ${vertex.x} ${vertex.y} ${vertex.z}
`;
}
}
}
export {
STLExporter
};
//# sourceMappingURL=STLExporter.js.map
File diff suppressed because one or more lines are too long
+350
View File
@@ -0,0 +1,350 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const fflate = require("fflate");
const THREE = require("three");
class USDZExporter {
constructor() {
__publicField(this, "PRECISION", 7);
__publicField(this, "materials");
__publicField(this, "textures");
__publicField(this, "files");
this.materials = {};
this.textures = {};
this.files = {};
}
async parse(scene) {
const modelFileName = "model.usda";
this.files[modelFileName] = null;
let output = this.buildHeader();
scene.traverseVisible((object) => {
if (object instanceof THREE.Mesh && object.isMesh && object.material.isMeshStandardMaterial) {
const geometry = object.geometry;
const material = object.material;
const geometryFileName = "geometries/Geometry_" + geometry.id + ".usd";
if (!(geometryFileName in this.files)) {
const meshObject = this.buildMeshObject(geometry);
this.files[geometryFileName] = this.buildUSDFileAsString(meshObject);
}
if (!(material.uuid in this.materials)) {
this.materials[material.uuid] = material;
}
output += this.buildXform(object, geometry, material);
}
});
output += this.buildMaterials(this.materials);
this.files[modelFileName] = fflate.strToU8(output);
output = null;
for (const id in this.textures) {
const texture = this.textures[id];
const color = id.split("_")[1];
const isRGBA = texture.format === 1023;
const canvas = this.imageToCanvas(texture.image, color);
const blob = await new Promise(
(resolve) => canvas == null ? void 0 : canvas.toBlob(resolve, isRGBA ? "image/png" : "image/jpeg", 1)
);
if (blob) {
this.files[`textures/Texture_${id}.${isRGBA ? "png" : "jpg"}`] = new Uint8Array(await blob.arrayBuffer());
}
}
let offset = 0;
for (const filename in this.files) {
const file = this.files[filename];
const headerSize = 34 + filename.length;
offset += headerSize;
const offsetMod64 = offset & 63;
if (offsetMod64 !== 4 && file !== null && file instanceof Uint8Array) {
const padLength = 64 - offsetMod64;
const padding = new Uint8Array(padLength);
this.files[filename] = [file, { extra: { 12345: padding } }];
}
if (file && typeof file.length === "number") {
offset = file.length;
}
}
return fflate.zipSync(this.files, { level: 0 });
}
imageToCanvas(image, color) {
if (typeof HTMLImageElement !== "undefined" && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== "undefined" && image instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && image instanceof OffscreenCanvas || typeof ImageBitmap !== "undefined" && image instanceof ImageBitmap) {
const scale = 1024 / Math.max(image.width, image.height);
const canvas = document.createElement("canvas");
canvas.width = image.width * Math.min(1, scale);
canvas.height = image.height * Math.min(1, scale);
const context = canvas.getContext("2d");
context == null ? void 0 : context.drawImage(image, 0, 0, canvas.width, canvas.height);
if (color !== void 0) {
const hex = parseInt(color, 16);
const r = (hex >> 16 & 255) / 255;
const g = (hex >> 8 & 255) / 255;
const b = (hex & 255) / 255;
const imagedata = context == null ? void 0 : context.getImageData(0, 0, canvas.width, canvas.height);
if (imagedata) {
const data = imagedata == null ? void 0 : imagedata.data;
for (let i = 0; i < data.length; i += 4) {
data[i + 0] = data[i + 0] * r;
data[i + 1] = data[i + 1] * g;
data[i + 2] = data[i + 2] * b;
}
context == null ? void 0 : context.putImageData(imagedata, 0, 0);
}
}
return canvas;
}
}
buildHeader() {
return `#usda 1.0
(
customLayerData = {
string creator = "Three.js USDZExporter"
}
metersPerUnit = 1
upAxis = "Y"
)
`;
}
buildUSDFileAsString(dataToInsert) {
let output = this.buildHeader();
output += dataToInsert;
return fflate.strToU8(output);
}
// Xform
buildXform(object, geometry, material) {
const name = "Object_" + object.id;
const transform = this.buildMatrix(object.matrixWorld);
if (object.matrixWorld.determinant() < 0) {
console.warn("THREE.USDZExporter: USDZ does not support negative scales", object);
}
return `def Xform "${name}" (
prepend references = @./geometries/Geometry_${geometry.id}.usd@</Geometry>
)
{
matrix4d xformOp:transform = ${transform}
uniform token[] xformOpOrder = ["xformOp:transform"]
rel material:binding = </Materials/Material_${material.id}>
}
`;
}
buildMatrix(matrix) {
const array = matrix.elements;
return `( ${this.buildMatrixRow(array, 0)}, ${this.buildMatrixRow(array, 4)}, ${this.buildMatrixRow(
array,
8
)}, ${this.buildMatrixRow(array, 12)} )`;
}
buildMatrixRow(array, offset) {
return `(${array[offset + 0]}, ${array[offset + 1]}, ${array[offset + 2]}, ${array[offset + 3]})`;
}
// Mesh
buildMeshObject(geometry) {
const mesh = this.buildMesh(geometry);
return `
def "Geometry"
{
${mesh}
}
`;
}
buildMesh(geometry) {
const name = "Geometry";
const attributes = geometry.attributes;
const count = attributes.position.count;
return `
def Mesh "${name}"
{
int[] faceVertexCounts = [${this.buildMeshVertexCount(geometry)}]
int[] faceVertexIndices = [${this.buildMeshVertexIndices(geometry)}]
normal3f[] normals = [${this.buildVector3Array(attributes.normal, count)}] (
interpolation = "vertex"
)
point3f[] points = [${this.buildVector3Array(attributes.position, count)}]
float2[] primvars:st = [${this.buildVector2Array(attributes.uv, count)}] (
interpolation = "vertex"
)
uniform token subdivisionScheme = "none"
}
`;
}
buildMeshVertexCount(geometry) {
const count = geometry.index !== null ? geometry.index.array.length : geometry.attributes.position.count;
return Array(count / 3).fill(3).join(", ");
}
buildMeshVertexIndices(geometry) {
if (geometry.index !== null) {
return geometry.index.array.join(", ");
}
const array = [];
const length = geometry.attributes.position.count;
for (let i = 0; i < length; i++) {
array.push(i);
}
return array.join(", ");
}
buildVector3Array(attribute, count) {
if (attribute === void 0) {
console.warn("USDZExporter: Normals missing.");
return Array(count).fill("(0, 0, 0)").join(", ");
}
const array = [];
const data = attribute.array;
for (let i = 0; i < data.length; i += 3) {
array.push(
`(${data[i + 0].toPrecision(this.PRECISION)}, ${data[i + 1].toPrecision(this.PRECISION)}, ${data[i + 2].toPrecision(this.PRECISION)})`
);
}
return array.join(", ");
}
buildVector2Array(attribute, count) {
if (attribute === void 0) {
console.warn("USDZExporter: UVs missing.");
return Array(count).fill("(0, 0)").join(", ");
}
const array = [];
const data = attribute.array;
for (let i = 0; i < data.length; i += 2) {
array.push(`(${data[i + 0].toPrecision(this.PRECISION)}, ${1 - data[i + 1].toPrecision(this.PRECISION)})`);
}
return array.join(", ");
}
// Materials
buildMaterials(materials) {
const array = [];
for (const uuid in materials) {
const material = materials[uuid];
array.push(this.buildMaterial(material));
}
return `def "Materials"
{
${array.join("")}
}
`;
}
buildMaterial(material) {
const pad = " ";
const inputs = [];
const samplers = [];
if (material.map !== null) {
inputs.push(
`${pad}color3f inputs:diffuseColor.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:rgb>`
);
if (material.transparent || material.alphaTest > 0) {
inputs.push(`${pad}float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:a>`);
}
if (material.alphaTest > 0.01) {
inputs.push(`${pad}float inputs:opacityThreshold = ${material.alphaTest}`);
} else if (material.transparent || material.alphaTest > 0) {
inputs.push(`${pad}float inputs:opacityThreshold = 0.01`);
}
samplers.push(this.buildTexture(material, material.map, "diffuse", material.color));
} else {
inputs.push(`${pad}color3f inputs:diffuseColor = ${this.buildColor(material.color)}`);
}
if (material.emissiveMap !== null) {
inputs.push(
`${pad}color3f inputs:emissiveColor.connect = </Materials/Material_${material.id}/Texture_${material.emissiveMap.id}_emissive.outputs:rgb>`
);
samplers.push(this.buildTexture(material, material.emissiveMap, "emissive"));
} else if (material.emissive.getHex() > 0) {
inputs.push(`${pad}color3f inputs:emissiveColor = ${this.buildColor(material.emissive)}`);
}
if (material.normalMap !== null) {
inputs.push(
`${pad}normal3f inputs:normal.connect = </Materials/Material_${material.id}/Texture_${material.normalMap.id}_normal.outputs:rgb>`
);
samplers.push(this.buildTexture(material, material.normalMap, "normal"));
}
if (material.aoMap !== null) {
inputs.push(
`${pad}float inputs:occlusion.connect = </Materials/Material_${material.id}/Texture_${material.aoMap.id}_occlusion.outputs:r>`
);
samplers.push(this.buildTexture(material, material.aoMap, "occlusion"));
}
if (material.roughnessMap !== null && material.roughness === 1) {
inputs.push(
`${pad}float inputs:roughness.connect = </Materials/Material_${material.id}/Texture_${material.roughnessMap.id}_roughness.outputs:g>`
);
samplers.push(this.buildTexture(material, material.roughnessMap, "roughness"));
} else {
inputs.push(`${pad}float inputs:roughness = ${material.roughness}`);
}
if (material.metalnessMap !== null && material.metalness === 1) {
inputs.push(
`${pad}float inputs:metallic.connect = </Materials/Material_${material.id}/Texture_${material.metalnessMap.id}_metallic.outputs:b>`
);
samplers.push(this.buildTexture(material, material.metalnessMap, "metallic"));
} else {
inputs.push(`${pad}float inputs:metallic = ${material.metalness}`);
}
inputs.push(`${pad}float inputs:opacity = ${material.opacity}`);
if (material instanceof THREE.MeshPhysicalMaterial) {
inputs.push(`${pad}float inputs:clearcoat = ${material.clearcoat}`);
inputs.push(`${pad}float inputs:clearcoatRoughness = ${material.clearcoatRoughness}`);
inputs.push(`${pad}float inputs:ior = ${material.ior}`);
}
return `
def Material "Material_${material.id}"
{
def Shader "PreviewSurface"
{
uniform token info:id = "UsdPreviewSurface"
${inputs.join("\n")}
int inputs:useSpecularWorkflow = 0
token outputs:surface
}
token outputs:surface.connect = </Materials/Material_${material.id}/PreviewSurface.outputs:surface>
token inputs:frame:stPrimvarName = "st"
def Shader "uvReader_st"
{
uniform token info:id = "UsdPrimvarReader_float2"
token inputs:varname.connect = </Materials/Material_${material.id}.inputs:frame:stPrimvarName>
float2 inputs:fallback = (0.0, 0.0)
float2 outputs:result
}
${samplers.join("\n")}
}
`;
}
buildTexture(material, texture, mapType, color) {
const id = texture.id + (color ? "_" + color.getHexString() : "");
const isRGBA = texture.format === 1023;
this.textures[id] = texture;
return `
def Shader "Transform2d_${mapType}" (
sdrMetadata = {
string role = "math"
}
)
{
uniform token info:id = "UsdTransform2d"
float2 inputs:in.connect = </Materials/Material_${material.id}/uvReader_st.outputs:result>
float2 inputs:scale = ${this.buildVector2(texture.repeat)}
float2 inputs:translation = ${this.buildVector2(texture.offset)}
float2 outputs:result
}
def Shader "Texture_${texture.id}_${mapType}"
{
uniform token info:id = "UsdUVTexture"
asset inputs:file = @textures/Texture_${id}.${isRGBA ? "png" : "jpg"}@
float2 inputs:st.connect = </Materials/Material_${material.id}/Transform2d_${mapType}.outputs:result>
token inputs:wrapS = "repeat"
token inputs:wrapT = "repeat"
float outputs:r
float outputs:g
float outputs:b
float3 outputs:rgb
${material.transparent || material.alphaTest > 0 ? "float outputs:a" : ""}
}`;
}
buildColor(color) {
return `(${color.r}, ${color.g}, ${color.b})`;
}
buildVector2(vector) {
return `(${vector.x}, ${vector.y})`;
}
}
exports.USDZExporter = USDZExporter;
//# sourceMappingURL=USDZExporter.cjs.map
File diff suppressed because one or more lines are too long
+27
View File
@@ -0,0 +1,27 @@
import { Object3D } from 'three';
declare class USDZExporter {
private readonly PRECISION;
private materials;
private textures;
private files;
constructor();
parse(scene: Object3D): Promise<Uint8Array>;
private imageToCanvas;
private buildHeader;
private buildUSDFileAsString;
private buildXform;
private buildMatrix;
private buildMatrixRow;
private buildMeshObject;
private buildMesh;
private buildMeshVertexCount;
private buildMeshVertexIndices;
private buildVector3Array;
private buildVector2Array;
private buildMaterials;
private buildMaterial;
private buildTexture;
private buildColor;
private buildVector2;
}
export { USDZExporter };
+350
View File
@@ -0,0 +1,350 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { strToU8, zipSync } from "fflate";
import { Mesh, MeshPhysicalMaterial } from "three";
class USDZExporter {
constructor() {
__publicField(this, "PRECISION", 7);
__publicField(this, "materials");
__publicField(this, "textures");
__publicField(this, "files");
this.materials = {};
this.textures = {};
this.files = {};
}
async parse(scene) {
const modelFileName = "model.usda";
this.files[modelFileName] = null;
let output = this.buildHeader();
scene.traverseVisible((object) => {
if (object instanceof Mesh && object.isMesh && object.material.isMeshStandardMaterial) {
const geometry = object.geometry;
const material = object.material;
const geometryFileName = "geometries/Geometry_" + geometry.id + ".usd";
if (!(geometryFileName in this.files)) {
const meshObject = this.buildMeshObject(geometry);
this.files[geometryFileName] = this.buildUSDFileAsString(meshObject);
}
if (!(material.uuid in this.materials)) {
this.materials[material.uuid] = material;
}
output += this.buildXform(object, geometry, material);
}
});
output += this.buildMaterials(this.materials);
this.files[modelFileName] = strToU8(output);
output = null;
for (const id in this.textures) {
const texture = this.textures[id];
const color = id.split("_")[1];
const isRGBA = texture.format === 1023;
const canvas = this.imageToCanvas(texture.image, color);
const blob = await new Promise(
(resolve) => canvas == null ? void 0 : canvas.toBlob(resolve, isRGBA ? "image/png" : "image/jpeg", 1)
);
if (blob) {
this.files[`textures/Texture_${id}.${isRGBA ? "png" : "jpg"}`] = new Uint8Array(await blob.arrayBuffer());
}
}
let offset = 0;
for (const filename in this.files) {
const file = this.files[filename];
const headerSize = 34 + filename.length;
offset += headerSize;
const offsetMod64 = offset & 63;
if (offsetMod64 !== 4 && file !== null && file instanceof Uint8Array) {
const padLength = 64 - offsetMod64;
const padding = new Uint8Array(padLength);
this.files[filename] = [file, { extra: { 12345: padding } }];
}
if (file && typeof file.length === "number") {
offset = file.length;
}
}
return zipSync(this.files, { level: 0 });
}
imageToCanvas(image, color) {
if (typeof HTMLImageElement !== "undefined" && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== "undefined" && image instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && image instanceof OffscreenCanvas || typeof ImageBitmap !== "undefined" && image instanceof ImageBitmap) {
const scale = 1024 / Math.max(image.width, image.height);
const canvas = document.createElement("canvas");
canvas.width = image.width * Math.min(1, scale);
canvas.height = image.height * Math.min(1, scale);
const context = canvas.getContext("2d");
context == null ? void 0 : context.drawImage(image, 0, 0, canvas.width, canvas.height);
if (color !== void 0) {
const hex = parseInt(color, 16);
const r = (hex >> 16 & 255) / 255;
const g = (hex >> 8 & 255) / 255;
const b = (hex & 255) / 255;
const imagedata = context == null ? void 0 : context.getImageData(0, 0, canvas.width, canvas.height);
if (imagedata) {
const data = imagedata == null ? void 0 : imagedata.data;
for (let i = 0; i < data.length; i += 4) {
data[i + 0] = data[i + 0] * r;
data[i + 1] = data[i + 1] * g;
data[i + 2] = data[i + 2] * b;
}
context == null ? void 0 : context.putImageData(imagedata, 0, 0);
}
}
return canvas;
}
}
buildHeader() {
return `#usda 1.0
(
customLayerData = {
string creator = "Three.js USDZExporter"
}
metersPerUnit = 1
upAxis = "Y"
)
`;
}
buildUSDFileAsString(dataToInsert) {
let output = this.buildHeader();
output += dataToInsert;
return strToU8(output);
}
// Xform
buildXform(object, geometry, material) {
const name = "Object_" + object.id;
const transform = this.buildMatrix(object.matrixWorld);
if (object.matrixWorld.determinant() < 0) {
console.warn("THREE.USDZExporter: USDZ does not support negative scales", object);
}
return `def Xform "${name}" (
prepend references = @./geometries/Geometry_${geometry.id}.usd@</Geometry>
)
{
matrix4d xformOp:transform = ${transform}
uniform token[] xformOpOrder = ["xformOp:transform"]
rel material:binding = </Materials/Material_${material.id}>
}
`;
}
buildMatrix(matrix) {
const array = matrix.elements;
return `( ${this.buildMatrixRow(array, 0)}, ${this.buildMatrixRow(array, 4)}, ${this.buildMatrixRow(
array,
8
)}, ${this.buildMatrixRow(array, 12)} )`;
}
buildMatrixRow(array, offset) {
return `(${array[offset + 0]}, ${array[offset + 1]}, ${array[offset + 2]}, ${array[offset + 3]})`;
}
// Mesh
buildMeshObject(geometry) {
const mesh = this.buildMesh(geometry);
return `
def "Geometry"
{
${mesh}
}
`;
}
buildMesh(geometry) {
const name = "Geometry";
const attributes = geometry.attributes;
const count = attributes.position.count;
return `
def Mesh "${name}"
{
int[] faceVertexCounts = [${this.buildMeshVertexCount(geometry)}]
int[] faceVertexIndices = [${this.buildMeshVertexIndices(geometry)}]
normal3f[] normals = [${this.buildVector3Array(attributes.normal, count)}] (
interpolation = "vertex"
)
point3f[] points = [${this.buildVector3Array(attributes.position, count)}]
float2[] primvars:st = [${this.buildVector2Array(attributes.uv, count)}] (
interpolation = "vertex"
)
uniform token subdivisionScheme = "none"
}
`;
}
buildMeshVertexCount(geometry) {
const count = geometry.index !== null ? geometry.index.array.length : geometry.attributes.position.count;
return Array(count / 3).fill(3).join(", ");
}
buildMeshVertexIndices(geometry) {
if (geometry.index !== null) {
return geometry.index.array.join(", ");
}
const array = [];
const length = geometry.attributes.position.count;
for (let i = 0; i < length; i++) {
array.push(i);
}
return array.join(", ");
}
buildVector3Array(attribute, count) {
if (attribute === void 0) {
console.warn("USDZExporter: Normals missing.");
return Array(count).fill("(0, 0, 0)").join(", ");
}
const array = [];
const data = attribute.array;
for (let i = 0; i < data.length; i += 3) {
array.push(
`(${data[i + 0].toPrecision(this.PRECISION)}, ${data[i + 1].toPrecision(this.PRECISION)}, ${data[i + 2].toPrecision(this.PRECISION)})`
);
}
return array.join(", ");
}
buildVector2Array(attribute, count) {
if (attribute === void 0) {
console.warn("USDZExporter: UVs missing.");
return Array(count).fill("(0, 0)").join(", ");
}
const array = [];
const data = attribute.array;
for (let i = 0; i < data.length; i += 2) {
array.push(`(${data[i + 0].toPrecision(this.PRECISION)}, ${1 - data[i + 1].toPrecision(this.PRECISION)})`);
}
return array.join(", ");
}
// Materials
buildMaterials(materials) {
const array = [];
for (const uuid in materials) {
const material = materials[uuid];
array.push(this.buildMaterial(material));
}
return `def "Materials"
{
${array.join("")}
}
`;
}
buildMaterial(material) {
const pad = " ";
const inputs = [];
const samplers = [];
if (material.map !== null) {
inputs.push(
`${pad}color3f inputs:diffuseColor.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:rgb>`
);
if (material.transparent || material.alphaTest > 0) {
inputs.push(`${pad}float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:a>`);
}
if (material.alphaTest > 0.01) {
inputs.push(`${pad}float inputs:opacityThreshold = ${material.alphaTest}`);
} else if (material.transparent || material.alphaTest > 0) {
inputs.push(`${pad}float inputs:opacityThreshold = 0.01`);
}
samplers.push(this.buildTexture(material, material.map, "diffuse", material.color));
} else {
inputs.push(`${pad}color3f inputs:diffuseColor = ${this.buildColor(material.color)}`);
}
if (material.emissiveMap !== null) {
inputs.push(
`${pad}color3f inputs:emissiveColor.connect = </Materials/Material_${material.id}/Texture_${material.emissiveMap.id}_emissive.outputs:rgb>`
);
samplers.push(this.buildTexture(material, material.emissiveMap, "emissive"));
} else if (material.emissive.getHex() > 0) {
inputs.push(`${pad}color3f inputs:emissiveColor = ${this.buildColor(material.emissive)}`);
}
if (material.normalMap !== null) {
inputs.push(
`${pad}normal3f inputs:normal.connect = </Materials/Material_${material.id}/Texture_${material.normalMap.id}_normal.outputs:rgb>`
);
samplers.push(this.buildTexture(material, material.normalMap, "normal"));
}
if (material.aoMap !== null) {
inputs.push(
`${pad}float inputs:occlusion.connect = </Materials/Material_${material.id}/Texture_${material.aoMap.id}_occlusion.outputs:r>`
);
samplers.push(this.buildTexture(material, material.aoMap, "occlusion"));
}
if (material.roughnessMap !== null && material.roughness === 1) {
inputs.push(
`${pad}float inputs:roughness.connect = </Materials/Material_${material.id}/Texture_${material.roughnessMap.id}_roughness.outputs:g>`
);
samplers.push(this.buildTexture(material, material.roughnessMap, "roughness"));
} else {
inputs.push(`${pad}float inputs:roughness = ${material.roughness}`);
}
if (material.metalnessMap !== null && material.metalness === 1) {
inputs.push(
`${pad}float inputs:metallic.connect = </Materials/Material_${material.id}/Texture_${material.metalnessMap.id}_metallic.outputs:b>`
);
samplers.push(this.buildTexture(material, material.metalnessMap, "metallic"));
} else {
inputs.push(`${pad}float inputs:metallic = ${material.metalness}`);
}
inputs.push(`${pad}float inputs:opacity = ${material.opacity}`);
if (material instanceof MeshPhysicalMaterial) {
inputs.push(`${pad}float inputs:clearcoat = ${material.clearcoat}`);
inputs.push(`${pad}float inputs:clearcoatRoughness = ${material.clearcoatRoughness}`);
inputs.push(`${pad}float inputs:ior = ${material.ior}`);
}
return `
def Material "Material_${material.id}"
{
def Shader "PreviewSurface"
{
uniform token info:id = "UsdPreviewSurface"
${inputs.join("\n")}
int inputs:useSpecularWorkflow = 0
token outputs:surface
}
token outputs:surface.connect = </Materials/Material_${material.id}/PreviewSurface.outputs:surface>
token inputs:frame:stPrimvarName = "st"
def Shader "uvReader_st"
{
uniform token info:id = "UsdPrimvarReader_float2"
token inputs:varname.connect = </Materials/Material_${material.id}.inputs:frame:stPrimvarName>
float2 inputs:fallback = (0.0, 0.0)
float2 outputs:result
}
${samplers.join("\n")}
}
`;
}
buildTexture(material, texture, mapType, color) {
const id = texture.id + (color ? "_" + color.getHexString() : "");
const isRGBA = texture.format === 1023;
this.textures[id] = texture;
return `
def Shader "Transform2d_${mapType}" (
sdrMetadata = {
string role = "math"
}
)
{
uniform token info:id = "UsdTransform2d"
float2 inputs:in.connect = </Materials/Material_${material.id}/uvReader_st.outputs:result>
float2 inputs:scale = ${this.buildVector2(texture.repeat)}
float2 inputs:translation = ${this.buildVector2(texture.offset)}
float2 outputs:result
}
def Shader "Texture_${texture.id}_${mapType}"
{
uniform token info:id = "UsdUVTexture"
asset inputs:file = @textures/Texture_${id}.${isRGBA ? "png" : "jpg"}@
float2 inputs:st.connect = </Materials/Material_${material.id}/Transform2d_${mapType}.outputs:result>
token inputs:wrapS = "repeat"
token inputs:wrapT = "repeat"
float outputs:r
float outputs:g
float outputs:b
float3 outputs:rgb
${material.transparent || material.alphaTest > 0 ? "float outputs:a" : ""}
}`;
}
buildColor(color) {
return `(${color.r}, ${color.g}, ${color.b})`;
}
buildVector2(vector) {
return `(${vector.x}, ${vector.y})`;
}
}
export {
USDZExporter
};
//# sourceMappingURL=USDZExporter.js.map
File diff suppressed because one or more lines are too long