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
+637
View File
@@ -0,0 +1,637 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const helpers = require("../types/helpers.cjs");
const mergeBufferGeometries = (geometries, useGroups) => {
const isIndexed = geometries[0].index !== null;
const attributesUsed = new Set(Object.keys(geometries[0].attributes));
const morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));
const attributes = {};
const morphAttributes = {};
const morphTargetsRelative = geometries[0].morphTargetsRelative;
const mergedGeometry = new THREE.BufferGeometry();
let offset = 0;
geometries.forEach((geom, i) => {
let attributesCount = 0;
if (isIndexed !== (geom.index !== null)) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them."
);
return null;
}
for (let name in geom.attributes) {
if (!attributesUsed.has(name)) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.'
);
return null;
}
if (attributes[name] === void 0) {
attributes[name] = [];
}
attributes[name].push(geom.attributes[name]);
attributesCount++;
}
if (attributesCount !== attributesUsed.size) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". Make sure all geometries have the same number of attributes."
);
return null;
}
if (morphTargetsRelative !== geom.morphTargetsRelative) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". .morphTargetsRelative must be consistent throughout all geometries."
);
return null;
}
for (let name in geom.morphAttributes) {
if (!morphAttributesUsed.has(name)) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". .morphAttributes must be consistent throughout all geometries."
);
return null;
}
if (morphAttributes[name] === void 0)
morphAttributes[name] = [];
morphAttributes[name].push(geom.morphAttributes[name]);
}
mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
mergedGeometry.userData.mergedUserData.push(geom.userData);
if (useGroups) {
let count;
if (geom.index) {
count = geom.index.count;
} else if (geom.attributes.position !== void 0) {
count = geom.attributes.position.count;
} else {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". The geometry must have either an index or a position attribute"
);
return null;
}
mergedGeometry.addGroup(offset, count, i);
offset += count;
}
});
if (isIndexed) {
let indexOffset = 0;
const mergedIndex = [];
geometries.forEach((geom) => {
const index = geom.index;
for (let j = 0; j < index.count; ++j) {
mergedIndex.push(index.getX(j) + indexOffset);
}
indexOffset += geom.attributes.position.count;
});
mergedGeometry.setIndex(mergedIndex);
}
for (let name in attributes) {
const mergedAttribute = mergeBufferAttributes(attributes[name]);
if (!mergedAttribute) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the " + name + " attribute."
);
return null;
}
mergedGeometry.setAttribute(name, mergedAttribute);
}
for (let name in morphAttributes) {
const numMorphTargets = morphAttributes[name][0].length;
if (numMorphTargets === 0)
break;
mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
mergedGeometry.morphAttributes[name] = [];
for (let i = 0; i < numMorphTargets; ++i) {
const morphAttributesToMerge = [];
for (let j = 0; j < morphAttributes[name].length; ++j) {
morphAttributesToMerge.push(morphAttributes[name][j][i]);
}
const mergedMorphAttribute = mergeBufferAttributes(morphAttributesToMerge);
if (!mergedMorphAttribute) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the " + name + " morphAttribute."
);
return null;
}
mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);
}
}
return mergedGeometry;
};
const mergeBufferAttributes = (attributes) => {
let TypedArray = void 0;
let itemSize = void 0;
let normalized = void 0;
let arrayLength = 0;
attributes.forEach((attr) => {
if (TypedArray === void 0) {
TypedArray = attr.array.constructor;
}
if (TypedArray !== attr.array.constructor) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes."
);
return null;
}
if (itemSize === void 0)
itemSize = attr.itemSize;
if (itemSize !== attr.itemSize) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes."
);
return null;
}
if (normalized === void 0)
normalized = attr.normalized;
if (normalized !== attr.normalized) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes."
);
return null;
}
arrayLength += attr.array.length;
});
if (TypedArray && itemSize) {
const array = new TypedArray(arrayLength);
let offset = 0;
attributes.forEach((attr) => {
array.set(attr.array, offset);
offset += attr.array.length;
});
return new THREE.BufferAttribute(array, itemSize, normalized);
}
};
const interleaveAttributes = (attributes) => {
let TypedArray = void 0;
let arrayLength = 0;
let stride = 0;
for (let i = 0, l = attributes.length; i < l; ++i) {
const attribute = attributes[i];
if (TypedArray === void 0)
TypedArray = attribute.array.constructor;
if (TypedArray !== attribute.array.constructor) {
console.error("AttributeBuffers of different types cannot be interleaved");
return null;
}
arrayLength += attribute.array.length;
stride += attribute.itemSize;
}
const interleavedBuffer = new THREE.InterleavedBuffer(new TypedArray(arrayLength), stride);
let offset = 0;
const res = [];
const getters = ["getX", "getY", "getZ", "getW"];
const setters = ["setX", "setY", "setZ", "setW"];
for (let j = 0, l = attributes.length; j < l; j++) {
const attribute = attributes[j];
const itemSize = attribute.itemSize;
const count = attribute.count;
const iba = new THREE.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
res.push(iba);
offset += itemSize;
for (let c = 0; c < count; c++) {
for (let k = 0; k < itemSize; k++) {
const set = helpers.getWithKey(iba, setters[k]);
const get = helpers.getWithKey(attribute, getters[k]);
set(c, get(c));
}
}
}
return res;
};
function estimateBytesUsed(geometry) {
let mem = 0;
for (let name in geometry.attributes) {
const attr = geometry.getAttribute(name);
mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT;
}
const indices = geometry.getIndex();
mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0;
return mem;
}
function mergeVertices(geometry, tolerance = 1e-4) {
tolerance = Math.max(tolerance, Number.EPSILON);
const hashToIndex = {};
const indices = geometry.getIndex();
const positions = geometry.getAttribute("position");
const vertexCount = indices ? indices.count : positions.count;
let nextIndex = 0;
const attributeNames = Object.keys(geometry.attributes);
const attrArrays = {};
const morphAttrsArrays = {};
const newIndices = [];
const getters = ["getX", "getY", "getZ", "getW"];
for (let i = 0, l = attributeNames.length; i < l; i++) {
const name = attributeNames[i];
attrArrays[name] = [];
const morphAttr = geometry.morphAttributes[name];
if (morphAttr) {
morphAttrsArrays[name] = new Array(morphAttr.length).fill(0).map(() => []);
}
}
const decimalShift = Math.log10(1 / tolerance);
const shiftMultiplier = Math.pow(10, decimalShift);
for (let i = 0; i < vertexCount; i++) {
const index = indices ? indices.getX(i) : i;
let hash = "";
for (let j = 0, l = attributeNames.length; j < l; j++) {
const name = attributeNames[j];
const attribute = geometry.getAttribute(name);
const itemSize = attribute.itemSize;
for (let k = 0; k < itemSize; k++) {
hash += `${~~(attribute[getters[k]](index) * shiftMultiplier)},`;
}
}
if (hash in hashToIndex) {
newIndices.push(hashToIndex[hash]);
} else {
for (let j = 0, l = attributeNames.length; j < l; j++) {
const name = attributeNames[j];
const attribute = geometry.getAttribute(name);
const morphAttr = geometry.morphAttributes[name];
const itemSize = attribute.itemSize;
const newarray = attrArrays[name];
const newMorphArrays = morphAttrsArrays[name];
for (let k = 0; k < itemSize; k++) {
const getterFunc = getters[k];
newarray.push(attribute[getterFunc](index));
if (morphAttr) {
for (let m = 0, ml = morphAttr.length; m < ml; m++) {
newMorphArrays[m].push(morphAttr[m][getterFunc](index));
}
}
}
}
hashToIndex[hash] = nextIndex;
newIndices.push(nextIndex);
nextIndex++;
}
}
const result = geometry.clone();
for (let i = 0, l = attributeNames.length; i < l; i++) {
const name = attributeNames[i];
const oldAttribute = geometry.getAttribute(name);
const buffer = new oldAttribute.array.constructor(attrArrays[name]);
const attribute = new THREE.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
result.setAttribute(name, attribute);
if (name in morphAttrsArrays) {
for (let j = 0; j < morphAttrsArrays[name].length; j++) {
const oldMorphAttribute = geometry.morphAttributes[name][j];
const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
const morphAttribute = new THREE.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
result.morphAttributes[name][j] = morphAttribute;
}
}
}
result.setIndex(newIndices);
return result;
}
function toTrianglesDrawMode(geometry, drawMode) {
if (drawMode === THREE.TrianglesDrawMode) {
console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
return geometry;
}
if (drawMode === THREE.TriangleFanDrawMode || drawMode === THREE.TriangleStripDrawMode) {
let index = geometry.getIndex();
if (index === null) {
const indices = [];
const position = geometry.getAttribute("position");
if (position !== void 0) {
for (let i = 0; i < position.count; i++) {
indices.push(i);
}
geometry.setIndex(indices);
index = geometry.getIndex();
} else {
console.error(
"THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible."
);
return geometry;
}
}
const numberOfTriangles = index.count - 2;
const newIndices = [];
if (index) {
if (drawMode === THREE.TriangleFanDrawMode) {
for (let i = 1; i <= numberOfTriangles; i++) {
newIndices.push(index.getX(0));
newIndices.push(index.getX(i));
newIndices.push(index.getX(i + 1));
}
} else {
for (let i = 0; i < numberOfTriangles; i++) {
if (i % 2 === 0) {
newIndices.push(index.getX(i));
newIndices.push(index.getX(i + 1));
newIndices.push(index.getX(i + 2));
} else {
newIndices.push(index.getX(i + 2));
newIndices.push(index.getX(i + 1));
newIndices.push(index.getX(i));
}
}
}
}
if (newIndices.length / 3 !== numberOfTriangles) {
console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.");
}
const newGeometry = geometry.clone();
newGeometry.setIndex(newIndices);
newGeometry.clearGroups();
return newGeometry;
} else {
console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:", drawMode);
return geometry;
}
}
function computeMorphedAttributes(object) {
if (object.geometry.isBufferGeometry !== true) {
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
return null;
}
const _vA = new THREE.Vector3();
const _vB = new THREE.Vector3();
const _vC = new THREE.Vector3();
const _tempA = new THREE.Vector3();
const _tempB = new THREE.Vector3();
const _tempC = new THREE.Vector3();
const _morphA = new THREE.Vector3();
const _morphB = new THREE.Vector3();
const _morphC = new THREE.Vector3();
function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
_vA.fromBufferAttribute(attribute, a2);
_vB.fromBufferAttribute(attribute, b2);
_vC.fromBufferAttribute(attribute, c2);
const morphInfluences = object2.morphTargetInfluences;
if (
// @ts-ignore
material2.morphTargets && morphAttribute && morphInfluences
) {
_morphA.set(0, 0, 0);
_morphB.set(0, 0, 0);
_morphC.set(0, 0, 0);
for (let i2 = 0, il2 = morphAttribute.length; i2 < il2; i2++) {
const influence = morphInfluences[i2];
const morph = morphAttribute[i2];
if (influence === 0)
continue;
_tempA.fromBufferAttribute(morph, a2);
_tempB.fromBufferAttribute(morph, b2);
_tempC.fromBufferAttribute(morph, c2);
if (morphTargetsRelative2) {
_morphA.addScaledVector(_tempA, influence);
_morphB.addScaledVector(_tempB, influence);
_morphC.addScaledVector(_tempC, influence);
} else {
_morphA.addScaledVector(_tempA.sub(_vA), influence);
_morphB.addScaledVector(_tempB.sub(_vB), influence);
_morphC.addScaledVector(_tempC.sub(_vC), influence);
}
}
_vA.add(_morphA);
_vB.add(_morphB);
_vC.add(_morphC);
}
if (object2.isSkinnedMesh) {
object2.boneTransform(a2, _vA);
object2.boneTransform(b2, _vB);
object2.boneTransform(c2, _vC);
}
modifiedAttributeArray[a2 * 3 + 0] = _vA.x;
modifiedAttributeArray[a2 * 3 + 1] = _vA.y;
modifiedAttributeArray[a2 * 3 + 2] = _vA.z;
modifiedAttributeArray[b2 * 3 + 0] = _vB.x;
modifiedAttributeArray[b2 * 3 + 1] = _vB.y;
modifiedAttributeArray[b2 * 3 + 2] = _vB.z;
modifiedAttributeArray[c2 * 3 + 0] = _vC.x;
modifiedAttributeArray[c2 * 3 + 1] = _vC.y;
modifiedAttributeArray[c2 * 3 + 2] = _vC.z;
}
const geometry = object.geometry;
const material = object.material;
let a, b, c;
const index = geometry.index;
const positionAttribute = geometry.attributes.position;
const morphPosition = geometry.morphAttributes.position;
const morphTargetsRelative = geometry.morphTargetsRelative;
const normalAttribute = geometry.attributes.normal;
const morphNormal = geometry.morphAttributes.position;
const groups = geometry.groups;
const drawRange = geometry.drawRange;
let i, j, il, jl;
let group, groupMaterial;
let start, end;
const modifiedPosition = new Float32Array(positionAttribute.count * positionAttribute.itemSize);
const modifiedNormal = new Float32Array(normalAttribute.count * normalAttribute.itemSize);
if (index !== null) {
if (Array.isArray(material)) {
for (i = 0, il = groups.length; i < il; i++) {
group = groups[i];
groupMaterial = material[group.materialIndex];
start = Math.max(group.start, drawRange.start);
end = Math.min(group.start + group.count, drawRange.start + drawRange.count);
for (j = start, jl = end; j < jl; j += 3) {
a = index.getX(j);
b = index.getX(j + 1);
c = index.getX(j + 2);
_calculateMorphedAttributeData(
object,
groupMaterial,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
groupMaterial,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
} else {
start = Math.max(0, drawRange.start);
end = Math.min(index.count, drawRange.start + drawRange.count);
for (i = start, il = end; i < il; i += 3) {
a = index.getX(i);
b = index.getX(i + 1);
c = index.getX(i + 2);
_calculateMorphedAttributeData(
object,
material,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
material,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
} else if (positionAttribute !== void 0) {
if (Array.isArray(material)) {
for (i = 0, il = groups.length; i < il; i++) {
group = groups[i];
groupMaterial = material[group.materialIndex];
start = Math.max(group.start, drawRange.start);
end = Math.min(group.start + group.count, drawRange.start + drawRange.count);
for (j = start, jl = end; j < jl; j += 3) {
a = j;
b = j + 1;
c = j + 2;
_calculateMorphedAttributeData(
object,
groupMaterial,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
groupMaterial,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
} else {
start = Math.max(0, drawRange.start);
end = Math.min(positionAttribute.count, drawRange.start + drawRange.count);
for (i = start, il = end; i < il; i += 3) {
a = i;
b = i + 1;
c = i + 2;
_calculateMorphedAttributeData(
object,
material,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
material,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
}
const morphedPositionAttribute = new THREE.Float32BufferAttribute(modifiedPosition, 3);
const morphedNormalAttribute = new THREE.Float32BufferAttribute(modifiedNormal, 3);
return {
positionAttribute,
normalAttribute,
morphedPositionAttribute,
morphedNormalAttribute
};
}
function toCreasedNormals(geometry, creaseAngle = Math.PI / 3) {
const creaseDot = Math.cos(creaseAngle);
const hashMultiplier = (1 + 1e-10) * 100;
const verts = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];
const tempVec1 = new THREE.Vector3();
const tempVec2 = new THREE.Vector3();
const tempNorm = new THREE.Vector3();
const tempNorm2 = new THREE.Vector3();
function hashVertex(v) {
const x = ~~(v.x * hashMultiplier);
const y = ~~(v.y * hashMultiplier);
const z = ~~(v.z * hashMultiplier);
return `${x},${y},${z}`;
}
const resultGeometry = geometry.index ? geometry.toNonIndexed() : geometry;
const posAttr = resultGeometry.attributes.position;
const vertexMap = {};
for (let i = 0, l = posAttr.count / 3; i < l; i++) {
const i3 = 3 * i;
const a = verts[0].fromBufferAttribute(posAttr, i3 + 0);
const b = verts[1].fromBufferAttribute(posAttr, i3 + 1);
const c = verts[2].fromBufferAttribute(posAttr, i3 + 2);
tempVec1.subVectors(c, b);
tempVec2.subVectors(a, b);
const normal = new THREE.Vector3().crossVectors(tempVec1, tempVec2).normalize();
for (let n = 0; n < 3; n++) {
const vert = verts[n];
const hash = hashVertex(vert);
if (!(hash in vertexMap)) {
vertexMap[hash] = [];
}
vertexMap[hash].push(normal);
}
}
const normalArray = new Float32Array(posAttr.count * 3);
const normAttr = new THREE.BufferAttribute(normalArray, 3, false);
for (let i = 0, l = posAttr.count / 3; i < l; i++) {
const i3 = 3 * i;
const a = verts[0].fromBufferAttribute(posAttr, i3 + 0);
const b = verts[1].fromBufferAttribute(posAttr, i3 + 1);
const c = verts[2].fromBufferAttribute(posAttr, i3 + 2);
tempVec1.subVectors(c, b);
tempVec2.subVectors(a, b);
tempNorm.crossVectors(tempVec1, tempVec2).normalize();
for (let n = 0; n < 3; n++) {
const vert = verts[n];
const hash = hashVertex(vert);
const otherNormals = vertexMap[hash];
tempNorm2.set(0, 0, 0);
for (let k = 0, lk = otherNormals.length; k < lk; k++) {
const otherNorm = otherNormals[k];
if (tempNorm.dot(otherNorm) > creaseDot) {
tempNorm2.add(otherNorm);
}
}
tempNorm2.normalize();
normAttr.setXYZ(i3 + n, tempNorm2.x, tempNorm2.y, tempNorm2.z);
}
}
resultGeometry.setAttribute("normal", normAttr);
return resultGeometry;
}
exports.computeMorphedAttributes = computeMorphedAttributes;
exports.estimateBytesUsed = estimateBytesUsed;
exports.interleaveAttributes = interleaveAttributes;
exports.mergeBufferAttributes = mergeBufferAttributes;
exports.mergeBufferGeometries = mergeBufferGeometries;
exports.mergeVertices = mergeVertices;
exports.toCreasedNormals = toCreasedNormals;
exports.toTrianglesDrawMode = toTrianglesDrawMode;
//# sourceMappingURL=BufferGeometryUtils.cjs.map
File diff suppressed because one or more lines are too long
+63
View File
@@ -0,0 +1,63 @@
import { BufferAttribute, BufferGeometry, Float32BufferAttribute, InterleavedBufferAttribute, Mesh, Line, Points } from 'three';
/**
* @param {Array<BufferGeometry>} geometries
* @param {Boolean} useGroups
* @return {BufferGeometry}
*/
export declare const mergeBufferGeometries: (geometries: BufferGeometry[], useGroups?: boolean) => BufferGeometry | null;
/**
* @param {Array<BufferAttribute>} attributes
* @return {BufferAttribute}
*/
export declare const mergeBufferAttributes: (attributes: BufferAttribute[]) => BufferAttribute | null | undefined;
/**
* @param {Array<BufferAttribute>} attributes
* @return {Array<InterleavedBufferAttribute>}
*/
export declare const interleaveAttributes: (attributes: BufferAttribute[]) => InterleavedBufferAttribute[] | null;
/**
* @param {Array<BufferGeometry>} geometry
* @return {number}
*/
export declare function estimateBytesUsed(geometry: BufferGeometry): number;
/**
* @param {BufferGeometry} geometry
* @param {number} tolerance
* @return {BufferGeometry>}
*/
export declare function mergeVertices(geometry: BufferGeometry, tolerance?: number): BufferGeometry;
/**
* @param {BufferGeometry} geometry
* @param {number} drawMode
* @return {BufferGeometry}
*/
export declare function toTrianglesDrawMode(geometry: BufferGeometry, drawMode: number): BufferGeometry;
/**
* Calculates the morphed attributes of a morphed/skinned BufferGeometry.
* Helpful for Raytracing or Decals.
* @param {Mesh | Line | Points} object An instance of Mesh, Line or Points.
* @return {Object} An Object with original position/normal attributes and morphed ones.
*/
export type ComputedMorphedAttribute = {
positionAttribute: BufferAttribute | InterleavedBufferAttribute;
normalAttribute: BufferAttribute | InterleavedBufferAttribute;
morphedPositionAttribute: Float32BufferAttribute;
morphedNormalAttribute: Float32BufferAttribute;
};
export declare function computeMorphedAttributes(object: Mesh | Line | Points): ComputedMorphedAttribute | null;
/**
* Modifies the supplied geometry if it is non-indexed, otherwise creates a new,
* non-indexed geometry. Returns the geometry with smooth normals everywhere except
* faces that meet at an angle greater than the crease angle.
*
* Backwards compatible with code such as @react-three/drei's `<RoundedBox>`
* which uses this method to operate on the original geometry.
*
* As of this writing, BufferGeometry.toNonIndexed() warns if the geometry is
* non-indexed and returns `this`, i.e. the same geometry on which it was called:
* `BufferGeometry is already non-indexed.`
*
* @param geometry
* @param creaseAngle
*/
export declare function toCreasedNormals(geometry: BufferGeometry, creaseAngle?: number): BufferGeometry;
+637
View File
@@ -0,0 +1,637 @@
import { BufferGeometry, BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, TrianglesDrawMode, TriangleFanDrawMode, TriangleStripDrawMode, Vector3, Float32BufferAttribute } from "three";
import { getWithKey } from "../types/helpers.js";
const mergeBufferGeometries = (geometries, useGroups) => {
const isIndexed = geometries[0].index !== null;
const attributesUsed = new Set(Object.keys(geometries[0].attributes));
const morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));
const attributes = {};
const morphAttributes = {};
const morphTargetsRelative = geometries[0].morphTargetsRelative;
const mergedGeometry = new BufferGeometry();
let offset = 0;
geometries.forEach((geom, i) => {
let attributesCount = 0;
if (isIndexed !== (geom.index !== null)) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them."
);
return null;
}
for (let name in geom.attributes) {
if (!attributesUsed.has(name)) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.'
);
return null;
}
if (attributes[name] === void 0) {
attributes[name] = [];
}
attributes[name].push(geom.attributes[name]);
attributesCount++;
}
if (attributesCount !== attributesUsed.size) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". Make sure all geometries have the same number of attributes."
);
return null;
}
if (morphTargetsRelative !== geom.morphTargetsRelative) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". .morphTargetsRelative must be consistent throughout all geometries."
);
return null;
}
for (let name in geom.morphAttributes) {
if (!morphAttributesUsed.has(name)) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". .morphAttributes must be consistent throughout all geometries."
);
return null;
}
if (morphAttributes[name] === void 0)
morphAttributes[name] = [];
morphAttributes[name].push(geom.morphAttributes[name]);
}
mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
mergedGeometry.userData.mergedUserData.push(geom.userData);
if (useGroups) {
let count;
if (geom.index) {
count = geom.index.count;
} else if (geom.attributes.position !== void 0) {
count = geom.attributes.position.count;
} else {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index " + i + ". The geometry must have either an index or a position attribute"
);
return null;
}
mergedGeometry.addGroup(offset, count, i);
offset += count;
}
});
if (isIndexed) {
let indexOffset = 0;
const mergedIndex = [];
geometries.forEach((geom) => {
const index = geom.index;
for (let j = 0; j < index.count; ++j) {
mergedIndex.push(index.getX(j) + indexOffset);
}
indexOffset += geom.attributes.position.count;
});
mergedGeometry.setIndex(mergedIndex);
}
for (let name in attributes) {
const mergedAttribute = mergeBufferAttributes(attributes[name]);
if (!mergedAttribute) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the " + name + " attribute."
);
return null;
}
mergedGeometry.setAttribute(name, mergedAttribute);
}
for (let name in morphAttributes) {
const numMorphTargets = morphAttributes[name][0].length;
if (numMorphTargets === 0)
break;
mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
mergedGeometry.morphAttributes[name] = [];
for (let i = 0; i < numMorphTargets; ++i) {
const morphAttributesToMerge = [];
for (let j = 0; j < morphAttributes[name].length; ++j) {
morphAttributesToMerge.push(morphAttributes[name][j][i]);
}
const mergedMorphAttribute = mergeBufferAttributes(morphAttributesToMerge);
if (!mergedMorphAttribute) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the " + name + " morphAttribute."
);
return null;
}
mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);
}
}
return mergedGeometry;
};
const mergeBufferAttributes = (attributes) => {
let TypedArray = void 0;
let itemSize = void 0;
let normalized = void 0;
let arrayLength = 0;
attributes.forEach((attr) => {
if (TypedArray === void 0) {
TypedArray = attr.array.constructor;
}
if (TypedArray !== attr.array.constructor) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes."
);
return null;
}
if (itemSize === void 0)
itemSize = attr.itemSize;
if (itemSize !== attr.itemSize) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes."
);
return null;
}
if (normalized === void 0)
normalized = attr.normalized;
if (normalized !== attr.normalized) {
console.error(
"THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes."
);
return null;
}
arrayLength += attr.array.length;
});
if (TypedArray && itemSize) {
const array = new TypedArray(arrayLength);
let offset = 0;
attributes.forEach((attr) => {
array.set(attr.array, offset);
offset += attr.array.length;
});
return new BufferAttribute(array, itemSize, normalized);
}
};
const interleaveAttributes = (attributes) => {
let TypedArray = void 0;
let arrayLength = 0;
let stride = 0;
for (let i = 0, l = attributes.length; i < l; ++i) {
const attribute = attributes[i];
if (TypedArray === void 0)
TypedArray = attribute.array.constructor;
if (TypedArray !== attribute.array.constructor) {
console.error("AttributeBuffers of different types cannot be interleaved");
return null;
}
arrayLength += attribute.array.length;
stride += attribute.itemSize;
}
const interleavedBuffer = new InterleavedBuffer(new TypedArray(arrayLength), stride);
let offset = 0;
const res = [];
const getters = ["getX", "getY", "getZ", "getW"];
const setters = ["setX", "setY", "setZ", "setW"];
for (let j = 0, l = attributes.length; j < l; j++) {
const attribute = attributes[j];
const itemSize = attribute.itemSize;
const count = attribute.count;
const iba = new InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
res.push(iba);
offset += itemSize;
for (let c = 0; c < count; c++) {
for (let k = 0; k < itemSize; k++) {
const set = getWithKey(iba, setters[k]);
const get = getWithKey(attribute, getters[k]);
set(c, get(c));
}
}
}
return res;
};
function estimateBytesUsed(geometry) {
let mem = 0;
for (let name in geometry.attributes) {
const attr = geometry.getAttribute(name);
mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT;
}
const indices = geometry.getIndex();
mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0;
return mem;
}
function mergeVertices(geometry, tolerance = 1e-4) {
tolerance = Math.max(tolerance, Number.EPSILON);
const hashToIndex = {};
const indices = geometry.getIndex();
const positions = geometry.getAttribute("position");
const vertexCount = indices ? indices.count : positions.count;
let nextIndex = 0;
const attributeNames = Object.keys(geometry.attributes);
const attrArrays = {};
const morphAttrsArrays = {};
const newIndices = [];
const getters = ["getX", "getY", "getZ", "getW"];
for (let i = 0, l = attributeNames.length; i < l; i++) {
const name = attributeNames[i];
attrArrays[name] = [];
const morphAttr = geometry.morphAttributes[name];
if (morphAttr) {
morphAttrsArrays[name] = new Array(morphAttr.length).fill(0).map(() => []);
}
}
const decimalShift = Math.log10(1 / tolerance);
const shiftMultiplier = Math.pow(10, decimalShift);
for (let i = 0; i < vertexCount; i++) {
const index = indices ? indices.getX(i) : i;
let hash = "";
for (let j = 0, l = attributeNames.length; j < l; j++) {
const name = attributeNames[j];
const attribute = geometry.getAttribute(name);
const itemSize = attribute.itemSize;
for (let k = 0; k < itemSize; k++) {
hash += `${~~(attribute[getters[k]](index) * shiftMultiplier)},`;
}
}
if (hash in hashToIndex) {
newIndices.push(hashToIndex[hash]);
} else {
for (let j = 0, l = attributeNames.length; j < l; j++) {
const name = attributeNames[j];
const attribute = geometry.getAttribute(name);
const morphAttr = geometry.morphAttributes[name];
const itemSize = attribute.itemSize;
const newarray = attrArrays[name];
const newMorphArrays = morphAttrsArrays[name];
for (let k = 0; k < itemSize; k++) {
const getterFunc = getters[k];
newarray.push(attribute[getterFunc](index));
if (morphAttr) {
for (let m = 0, ml = morphAttr.length; m < ml; m++) {
newMorphArrays[m].push(morphAttr[m][getterFunc](index));
}
}
}
}
hashToIndex[hash] = nextIndex;
newIndices.push(nextIndex);
nextIndex++;
}
}
const result = geometry.clone();
for (let i = 0, l = attributeNames.length; i < l; i++) {
const name = attributeNames[i];
const oldAttribute = geometry.getAttribute(name);
const buffer = new oldAttribute.array.constructor(attrArrays[name]);
const attribute = new BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
result.setAttribute(name, attribute);
if (name in morphAttrsArrays) {
for (let j = 0; j < morphAttrsArrays[name].length; j++) {
const oldMorphAttribute = geometry.morphAttributes[name][j];
const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
const morphAttribute = new BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
result.morphAttributes[name][j] = morphAttribute;
}
}
}
result.setIndex(newIndices);
return result;
}
function toTrianglesDrawMode(geometry, drawMode) {
if (drawMode === TrianglesDrawMode) {
console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
return geometry;
}
if (drawMode === TriangleFanDrawMode || drawMode === TriangleStripDrawMode) {
let index = geometry.getIndex();
if (index === null) {
const indices = [];
const position = geometry.getAttribute("position");
if (position !== void 0) {
for (let i = 0; i < position.count; i++) {
indices.push(i);
}
geometry.setIndex(indices);
index = geometry.getIndex();
} else {
console.error(
"THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible."
);
return geometry;
}
}
const numberOfTriangles = index.count - 2;
const newIndices = [];
if (index) {
if (drawMode === TriangleFanDrawMode) {
for (let i = 1; i <= numberOfTriangles; i++) {
newIndices.push(index.getX(0));
newIndices.push(index.getX(i));
newIndices.push(index.getX(i + 1));
}
} else {
for (let i = 0; i < numberOfTriangles; i++) {
if (i % 2 === 0) {
newIndices.push(index.getX(i));
newIndices.push(index.getX(i + 1));
newIndices.push(index.getX(i + 2));
} else {
newIndices.push(index.getX(i + 2));
newIndices.push(index.getX(i + 1));
newIndices.push(index.getX(i));
}
}
}
}
if (newIndices.length / 3 !== numberOfTriangles) {
console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.");
}
const newGeometry = geometry.clone();
newGeometry.setIndex(newIndices);
newGeometry.clearGroups();
return newGeometry;
} else {
console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:", drawMode);
return geometry;
}
}
function computeMorphedAttributes(object) {
if (object.geometry.isBufferGeometry !== true) {
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
return null;
}
const _vA = new Vector3();
const _vB = new Vector3();
const _vC = new Vector3();
const _tempA = new Vector3();
const _tempB = new Vector3();
const _tempC = new Vector3();
const _morphA = new Vector3();
const _morphB = new Vector3();
const _morphC = new Vector3();
function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
_vA.fromBufferAttribute(attribute, a2);
_vB.fromBufferAttribute(attribute, b2);
_vC.fromBufferAttribute(attribute, c2);
const morphInfluences = object2.morphTargetInfluences;
if (
// @ts-ignore
material2.morphTargets && morphAttribute && morphInfluences
) {
_morphA.set(0, 0, 0);
_morphB.set(0, 0, 0);
_morphC.set(0, 0, 0);
for (let i2 = 0, il2 = morphAttribute.length; i2 < il2; i2++) {
const influence = morphInfluences[i2];
const morph = morphAttribute[i2];
if (influence === 0)
continue;
_tempA.fromBufferAttribute(morph, a2);
_tempB.fromBufferAttribute(morph, b2);
_tempC.fromBufferAttribute(morph, c2);
if (morphTargetsRelative2) {
_morphA.addScaledVector(_tempA, influence);
_morphB.addScaledVector(_tempB, influence);
_morphC.addScaledVector(_tempC, influence);
} else {
_morphA.addScaledVector(_tempA.sub(_vA), influence);
_morphB.addScaledVector(_tempB.sub(_vB), influence);
_morphC.addScaledVector(_tempC.sub(_vC), influence);
}
}
_vA.add(_morphA);
_vB.add(_morphB);
_vC.add(_morphC);
}
if (object2.isSkinnedMesh) {
object2.boneTransform(a2, _vA);
object2.boneTransform(b2, _vB);
object2.boneTransform(c2, _vC);
}
modifiedAttributeArray[a2 * 3 + 0] = _vA.x;
modifiedAttributeArray[a2 * 3 + 1] = _vA.y;
modifiedAttributeArray[a2 * 3 + 2] = _vA.z;
modifiedAttributeArray[b2 * 3 + 0] = _vB.x;
modifiedAttributeArray[b2 * 3 + 1] = _vB.y;
modifiedAttributeArray[b2 * 3 + 2] = _vB.z;
modifiedAttributeArray[c2 * 3 + 0] = _vC.x;
modifiedAttributeArray[c2 * 3 + 1] = _vC.y;
modifiedAttributeArray[c2 * 3 + 2] = _vC.z;
}
const geometry = object.geometry;
const material = object.material;
let a, b, c;
const index = geometry.index;
const positionAttribute = geometry.attributes.position;
const morphPosition = geometry.morphAttributes.position;
const morphTargetsRelative = geometry.morphTargetsRelative;
const normalAttribute = geometry.attributes.normal;
const morphNormal = geometry.morphAttributes.position;
const groups = geometry.groups;
const drawRange = geometry.drawRange;
let i, j, il, jl;
let group, groupMaterial;
let start, end;
const modifiedPosition = new Float32Array(positionAttribute.count * positionAttribute.itemSize);
const modifiedNormal = new Float32Array(normalAttribute.count * normalAttribute.itemSize);
if (index !== null) {
if (Array.isArray(material)) {
for (i = 0, il = groups.length; i < il; i++) {
group = groups[i];
groupMaterial = material[group.materialIndex];
start = Math.max(group.start, drawRange.start);
end = Math.min(group.start + group.count, drawRange.start + drawRange.count);
for (j = start, jl = end; j < jl; j += 3) {
a = index.getX(j);
b = index.getX(j + 1);
c = index.getX(j + 2);
_calculateMorphedAttributeData(
object,
groupMaterial,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
groupMaterial,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
} else {
start = Math.max(0, drawRange.start);
end = Math.min(index.count, drawRange.start + drawRange.count);
for (i = start, il = end; i < il; i += 3) {
a = index.getX(i);
b = index.getX(i + 1);
c = index.getX(i + 2);
_calculateMorphedAttributeData(
object,
material,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
material,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
} else if (positionAttribute !== void 0) {
if (Array.isArray(material)) {
for (i = 0, il = groups.length; i < il; i++) {
group = groups[i];
groupMaterial = material[group.materialIndex];
start = Math.max(group.start, drawRange.start);
end = Math.min(group.start + group.count, drawRange.start + drawRange.count);
for (j = start, jl = end; j < jl; j += 3) {
a = j;
b = j + 1;
c = j + 2;
_calculateMorphedAttributeData(
object,
groupMaterial,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
groupMaterial,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
} else {
start = Math.max(0, drawRange.start);
end = Math.min(positionAttribute.count, drawRange.start + drawRange.count);
for (i = start, il = end; i < il; i += 3) {
a = i;
b = i + 1;
c = i + 2;
_calculateMorphedAttributeData(
object,
material,
positionAttribute,
morphPosition,
morphTargetsRelative,
a,
b,
c,
modifiedPosition
);
_calculateMorphedAttributeData(
object,
material,
normalAttribute,
morphNormal,
morphTargetsRelative,
a,
b,
c,
modifiedNormal
);
}
}
}
const morphedPositionAttribute = new Float32BufferAttribute(modifiedPosition, 3);
const morphedNormalAttribute = new Float32BufferAttribute(modifiedNormal, 3);
return {
positionAttribute,
normalAttribute,
morphedPositionAttribute,
morphedNormalAttribute
};
}
function toCreasedNormals(geometry, creaseAngle = Math.PI / 3) {
const creaseDot = Math.cos(creaseAngle);
const hashMultiplier = (1 + 1e-10) * 100;
const verts = [new Vector3(), new Vector3(), new Vector3()];
const tempVec1 = new Vector3();
const tempVec2 = new Vector3();
const tempNorm = new Vector3();
const tempNorm2 = new Vector3();
function hashVertex(v) {
const x = ~~(v.x * hashMultiplier);
const y = ~~(v.y * hashMultiplier);
const z = ~~(v.z * hashMultiplier);
return `${x},${y},${z}`;
}
const resultGeometry = geometry.index ? geometry.toNonIndexed() : geometry;
const posAttr = resultGeometry.attributes.position;
const vertexMap = {};
for (let i = 0, l = posAttr.count / 3; i < l; i++) {
const i3 = 3 * i;
const a = verts[0].fromBufferAttribute(posAttr, i3 + 0);
const b = verts[1].fromBufferAttribute(posAttr, i3 + 1);
const c = verts[2].fromBufferAttribute(posAttr, i3 + 2);
tempVec1.subVectors(c, b);
tempVec2.subVectors(a, b);
const normal = new Vector3().crossVectors(tempVec1, tempVec2).normalize();
for (let n = 0; n < 3; n++) {
const vert = verts[n];
const hash = hashVertex(vert);
if (!(hash in vertexMap)) {
vertexMap[hash] = [];
}
vertexMap[hash].push(normal);
}
}
const normalArray = new Float32Array(posAttr.count * 3);
const normAttr = new BufferAttribute(normalArray, 3, false);
for (let i = 0, l = posAttr.count / 3; i < l; i++) {
const i3 = 3 * i;
const a = verts[0].fromBufferAttribute(posAttr, i3 + 0);
const b = verts[1].fromBufferAttribute(posAttr, i3 + 1);
const c = verts[2].fromBufferAttribute(posAttr, i3 + 2);
tempVec1.subVectors(c, b);
tempVec2.subVectors(a, b);
tempNorm.crossVectors(tempVec1, tempVec2).normalize();
for (let n = 0; n < 3; n++) {
const vert = verts[n];
const hash = hashVertex(vert);
const otherNormals = vertexMap[hash];
tempNorm2.set(0, 0, 0);
for (let k = 0, lk = otherNormals.length; k < lk; k++) {
const otherNorm = otherNormals[k];
if (tempNorm.dot(otherNorm) > creaseDot) {
tempNorm2.add(otherNorm);
}
}
tempNorm2.normalize();
normAttr.setXYZ(i3 + n, tempNorm2.x, tempNorm2.y, tempNorm2.z);
}
}
resultGeometry.setAttribute("normal", normAttr);
return resultGeometry;
}
export {
computeMorphedAttributes,
estimateBytesUsed,
interleaveAttributes,
mergeBufferAttributes,
mergeBufferGeometries,
mergeVertices,
toCreasedNormals,
toTrianglesDrawMode
};
//# sourceMappingURL=BufferGeometryUtils.js.map
File diff suppressed because one or more lines are too long
+575
View File
@@ -0,0 +1,575 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const constants = require("../_polyfill/constants.cjs");
var GeometryCompressionUtils = {
/**
* Make the input mesh.geometry's normal attribute encoded and compressed by 3 different methods.
* Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the normal data.
*
* @param {THREE.Mesh} mesh
* @param {String} encodeMethod "DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES"
*
*/
compressNormals: function(mesh, encodeMethod) {
if (!mesh.geometry) {
console.error("Mesh must contain geometry. ");
}
const normal = mesh.geometry.attributes.normal;
if (!normal) {
console.error("Geometry must contain normal attribute. ");
}
if (normal.isPacked)
return;
if (normal.itemSize != 3) {
console.error("normal.itemSize is not 3, which cannot be encoded. ");
}
const array = normal.array;
const count = normal.count;
let result;
if (encodeMethod == "DEFAULT") {
result = new Uint8Array(count * 3);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.defaultEncode(array[idx], array[idx + 1], array[idx + 2], 1);
result[idx + 0] = encoded[0];
result[idx + 1] = encoded[1];
result[idx + 2] = encoded[2];
}
mesh.geometry.setAttribute("normal", new THREE.BufferAttribute(result, 3, true));
mesh.geometry.attributes.normal.bytes = result.length * 1;
} else if (encodeMethod == "OCT1Byte") {
result = new Int8Array(count * 2);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.octEncodeBest(array[idx], array[idx + 1], array[idx + 2], 1);
result[idx / 3 * 2 + 0] = encoded[0];
result[idx / 3 * 2 + 1] = encoded[1];
}
mesh.geometry.setAttribute("normal", new THREE.BufferAttribute(result, 2, true));
mesh.geometry.attributes.normal.bytes = result.length * 1;
} else if (encodeMethod == "OCT2Byte") {
result = new Int16Array(count * 2);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.octEncodeBest(array[idx], array[idx + 1], array[idx + 2], 2);
result[idx / 3 * 2 + 0] = encoded[0];
result[idx / 3 * 2 + 1] = encoded[1];
}
mesh.geometry.setAttribute("normal", new THREE.BufferAttribute(result, 2, true));
mesh.geometry.attributes.normal.bytes = result.length * 2;
} else if (encodeMethod == "ANGLES") {
result = new Uint16Array(count * 2);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.anglesEncode(array[idx], array[idx + 1], array[idx + 2]);
result[idx / 3 * 2 + 0] = encoded[0];
result[idx / 3 * 2 + 1] = encoded[1];
}
mesh.geometry.setAttribute("normal", new THREE.BufferAttribute(result, 2, true));
mesh.geometry.attributes.normal.bytes = result.length * 2;
} else {
console.error("Unrecognized encoding method, should be `DEFAULT` or `ANGLES` or `OCT`. ");
}
mesh.geometry.attributes.normal.needsUpdate = true;
mesh.geometry.attributes.normal.isPacked = true;
mesh.geometry.attributes.normal.packingMethod = encodeMethod;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
if (encodeMethod == "ANGLES") {
mesh.material.defines.USE_PACKED_NORMAL = 0;
}
if (encodeMethod == "OCT1Byte") {
mesh.material.defines.USE_PACKED_NORMAL = 1;
}
if (encodeMethod == "OCT2Byte") {
mesh.material.defines.USE_PACKED_NORMAL = 1;
}
if (encodeMethod == "DEFAULT") {
mesh.material.defines.USE_PACKED_NORMAL = 2;
}
},
/**
* Make the input mesh.geometry's position attribute encoded and compressed.
* Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the position data.
*
* @param {THREE.Mesh} mesh
*
*/
compressPositions: function(mesh) {
if (!mesh.geometry) {
console.error("Mesh must contain geometry. ");
}
const position = mesh.geometry.attributes.position;
if (!position) {
console.error("Geometry must contain position attribute. ");
}
if (position.isPacked)
return;
if (position.itemSize != 3) {
console.error("position.itemSize is not 3, which cannot be packed. ");
}
const array = position.array;
const encodingBytes = 2;
const result = this.EncodingFuncs.quantizedEncode(array, encodingBytes);
const quantized = result.quantized;
const decodeMat = result.decodeMat;
if (mesh.geometry.boundingBox == null)
mesh.geometry.computeBoundingBox();
if (mesh.geometry.boundingSphere == null)
mesh.geometry.computeBoundingSphere();
mesh.geometry.setAttribute("position", new THREE.BufferAttribute(quantized, 3));
mesh.geometry.attributes.position.isPacked = true;
mesh.geometry.attributes.position.needsUpdate = true;
mesh.geometry.attributes.position.bytes = quantized.length * encodingBytes;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
mesh.material.defines.USE_PACKED_POSITION = 0;
mesh.material.uniforms.quantizeMatPos.value = decodeMat;
mesh.material.uniforms.quantizeMatPos.needsUpdate = true;
},
/**
* Make the input mesh.geometry's uv attribute encoded and compressed.
* Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the uv data.
*
* @param {THREE.Mesh} mesh
*
*/
compressUvs: function(mesh) {
if (!mesh.geometry) {
console.error("Mesh must contain geometry property. ");
}
const uvs = mesh.geometry.attributes.uv;
if (!uvs) {
console.error("Geometry must contain uv attribute. ");
}
if (uvs.isPacked)
return;
const range = { min: Infinity, max: -Infinity };
const array = uvs.array;
for (let i = 0; i < array.length; i++) {
range.min = Math.min(range.min, array[i]);
range.max = Math.max(range.max, array[i]);
}
let result;
if (range.min >= -1 && range.max <= 1) {
result = new Uint16Array(array.length);
for (let i = 0; i < array.length; i += 2) {
const encoded = this.EncodingFuncs.defaultEncode(array[i], array[i + 1], 0, 2);
result[i] = encoded[0];
result[i + 1] = encoded[1];
}
mesh.geometry.setAttribute("uv", new THREE.BufferAttribute(result, 2, true));
mesh.geometry.attributes.uv.isPacked = true;
mesh.geometry.attributes.uv.needsUpdate = true;
mesh.geometry.attributes.uv.bytes = result.length * 2;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
mesh.material.defines.USE_PACKED_UV = 0;
} else {
result = this.EncodingFuncs.quantizedEncodeUV(array, 2);
mesh.geometry.setAttribute("uv", new THREE.BufferAttribute(result.quantized, 2));
mesh.geometry.attributes.uv.isPacked = true;
mesh.geometry.attributes.uv.needsUpdate = true;
mesh.geometry.attributes.uv.bytes = result.quantized.length * 2;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
mesh.material.defines.USE_PACKED_UV = 1;
mesh.material.uniforms.quantizeMatUV.value = result.decodeMat;
mesh.material.uniforms.quantizeMatUV.needsUpdate = true;
}
},
EncodingFuncs: {
defaultEncode: function(x, y, z, bytes) {
if (bytes == 1) {
const tmpx = Math.round((x + 1) * 0.5 * 255);
const tmpy = Math.round((y + 1) * 0.5 * 255);
const tmpz = Math.round((z + 1) * 0.5 * 255);
return new Uint8Array([tmpx, tmpy, tmpz]);
} else if (bytes == 2) {
const tmpx = Math.round((x + 1) * 0.5 * 65535);
const tmpy = Math.round((y + 1) * 0.5 * 65535);
const tmpz = Math.round((z + 1) * 0.5 * 65535);
return new Uint16Array([tmpx, tmpy, tmpz]);
} else {
console.error("number of bytes must be 1 or 2");
}
},
defaultDecode: function(array, bytes) {
if (bytes == 1) {
return [array[0] / 255 * 2 - 1, array[1] / 255 * 2 - 1, array[2] / 255 * 2 - 1];
} else if (bytes == 2) {
return [array[0] / 65535 * 2 - 1, array[1] / 65535 * 2 - 1, array[2] / 65535 * 2 - 1];
} else {
console.error("number of bytes must be 1 or 2");
}
},
// for `Angles` encoding
anglesEncode: function(x, y, z) {
const normal0 = parseInt(0.5 * (1 + Math.atan2(y, x) / Math.PI) * 65535);
const normal1 = parseInt(0.5 * (1 + z) * 65535);
return new Uint16Array([normal0, normal1]);
},
// for `Octahedron` encoding
octEncodeBest: function(x, y, z, bytes) {
var oct, dec, best, currentCos, bestCos;
best = oct = octEncodeVec3(x, y, z, "floor", "floor");
dec = octDecodeVec2(oct);
bestCos = dot(x, y, z, dec);
oct = octEncodeVec3(x, y, z, "ceil", "floor");
dec = octDecodeVec2(oct);
currentCos = dot(x, y, z, dec);
if (currentCos > bestCos) {
best = oct;
bestCos = currentCos;
}
oct = octEncodeVec3(x, y, z, "floor", "ceil");
dec = octDecodeVec2(oct);
currentCos = dot(x, y, z, dec);
if (currentCos > bestCos) {
best = oct;
bestCos = currentCos;
}
oct = octEncodeVec3(x, y, z, "ceil", "ceil");
dec = octDecodeVec2(oct);
currentCos = dot(x, y, z, dec);
if (currentCos > bestCos) {
best = oct;
}
return best;
function octEncodeVec3(x0, y0, z0, xfunc, yfunc) {
var x2 = x0 / (Math.abs(x0) + Math.abs(y0) + Math.abs(z0));
var y2 = y0 / (Math.abs(x0) + Math.abs(y0) + Math.abs(z0));
if (z < 0) {
var tempx = (1 - Math.abs(y2)) * (x2 >= 0 ? 1 : -1);
var tempy = (1 - Math.abs(x2)) * (y2 >= 0 ? 1 : -1);
x2 = tempx;
y2 = tempy;
var diff = 1 - Math.abs(x2) - Math.abs(y2);
if (diff > 0) {
diff += 1e-3;
x2 += x2 > 0 ? diff / 2 : -diff / 2;
y2 += y2 > 0 ? diff / 2 : -diff / 2;
}
}
if (bytes == 1) {
return new Int8Array([Math[xfunc](x2 * 127.5 + (x2 < 0 ? 1 : 0)), Math[yfunc](y2 * 127.5 + (y2 < 0 ? 1 : 0))]);
}
if (bytes == 2) {
return new Int16Array([
Math[xfunc](x2 * 32767.5 + (x2 < 0 ? 1 : 0)),
Math[yfunc](y2 * 32767.5 + (y2 < 0 ? 1 : 0))
]);
}
}
function octDecodeVec2(oct2) {
var x2 = oct2[0];
var y2 = oct2[1];
if (bytes == 1) {
x2 /= x2 < 0 ? 127 : 128;
y2 /= y2 < 0 ? 127 : 128;
} else if (bytes == 2) {
x2 /= x2 < 0 ? 32767 : 32768;
y2 /= y2 < 0 ? 32767 : 32768;
}
var z2 = 1 - Math.abs(x2) - Math.abs(y2);
if (z2 < 0) {
var tmpx = x2;
x2 = (1 - Math.abs(y2)) * (x2 >= 0 ? 1 : -1);
y2 = (1 - Math.abs(tmpx)) * (y2 >= 0 ? 1 : -1);
}
var length = Math.sqrt(x2 * x2 + y2 * y2 + z2 * z2);
return [x2 / length, y2 / length, z2 / length];
}
function dot(x2, y2, z2, vec3) {
return x2 * vec3[0] + y2 * vec3[1] + z2 * vec3[2];
}
},
quantizedEncode: function(array, bytes) {
let quantized, segments;
if (bytes == 1) {
quantized = new Uint8Array(array.length);
segments = 255;
} else if (bytes == 2) {
quantized = new Uint16Array(array.length);
segments = 65535;
} else {
console.error("number of bytes error! ");
}
const decodeMat = new THREE.Matrix4();
const min = new Float32Array(3);
const max = new Float32Array(3);
min[0] = min[1] = min[2] = Number.MAX_VALUE;
max[0] = max[1] = max[2] = -Number.MAX_VALUE;
for (let i = 0; i < array.length; i += 3) {
min[0] = Math.min(min[0], array[i + 0]);
min[1] = Math.min(min[1], array[i + 1]);
min[2] = Math.min(min[2], array[i + 2]);
max[0] = Math.max(max[0], array[i + 0]);
max[1] = Math.max(max[1], array[i + 1]);
max[2] = Math.max(max[2], array[i + 2]);
}
decodeMat.scale(
new THREE.Vector3((max[0] - min[0]) / segments, (max[1] - min[1]) / segments, (max[2] - min[2]) / segments)
);
decodeMat.elements[12] = min[0];
decodeMat.elements[13] = min[1];
decodeMat.elements[14] = min[2];
decodeMat.transpose();
const multiplier = new Float32Array([
max[0] !== min[0] ? segments / (max[0] - min[0]) : 0,
max[1] !== min[1] ? segments / (max[1] - min[1]) : 0,
max[2] !== min[2] ? segments / (max[2] - min[2]) : 0
]);
for (let i = 0; i < array.length; i += 3) {
quantized[i + 0] = Math.floor((array[i + 0] - min[0]) * multiplier[0]);
quantized[i + 1] = Math.floor((array[i + 1] - min[1]) * multiplier[1]);
quantized[i + 2] = Math.floor((array[i + 2] - min[2]) * multiplier[2]);
}
return {
quantized,
decodeMat
};
},
quantizedEncodeUV: function(array, bytes) {
let quantized, segments;
if (bytes == 1) {
quantized = new Uint8Array(array.length);
segments = 255;
} else if (bytes == 2) {
quantized = new Uint16Array(array.length);
segments = 65535;
} else {
console.error("number of bytes error! ");
}
const decodeMat = new THREE.Matrix3();
const min = new Float32Array(2);
const max = new Float32Array(2);
min[0] = min[1] = Number.MAX_VALUE;
max[0] = max[1] = -Number.MAX_VALUE;
for (let i = 0; i < array.length; i += 2) {
min[0] = Math.min(min[0], array[i + 0]);
min[1] = Math.min(min[1], array[i + 1]);
max[0] = Math.max(max[0], array[i + 0]);
max[1] = Math.max(max[1], array[i + 1]);
}
decodeMat.scale((max[0] - min[0]) / segments, (max[1] - min[1]) / segments);
decodeMat.elements[6] = min[0];
decodeMat.elements[7] = min[1];
decodeMat.transpose();
const multiplier = new Float32Array([
max[0] !== min[0] ? segments / (max[0] - min[0]) : 0,
max[1] !== min[1] ? segments / (max[1] - min[1]) : 0
]);
for (let i = 0; i < array.length; i += 2) {
quantized[i + 0] = Math.floor((array[i + 0] - min[0]) * multiplier[0]);
quantized[i + 1] = Math.floor((array[i + 1] - min[1]) * multiplier[1]);
}
return {
quantized,
decodeMat
};
}
}
};
class PackedPhongMaterial extends THREE.MeshPhongMaterial {
constructor(parameters) {
super();
this.defines = {};
this.type = "PackedPhongMaterial";
this.uniforms = THREE.UniformsUtils.merge([
THREE.ShaderLib.phong.uniforms,
{
quantizeMatPos: { value: null },
quantizeMatUV: { value: null }
}
]);
this.vertexShader = [
"#define PHONG",
"varying vec3 vViewPosition;",
"#ifndef FLAT_SHADED",
"varying vec3 vNormal;",
"#endif",
THREE.ShaderChunk.common,
THREE.ShaderChunk.uv_pars_vertex,
THREE.ShaderChunk.uv2_pars_vertex,
THREE.ShaderChunk.displacementmap_pars_vertex,
THREE.ShaderChunk.envmap_pars_vertex,
THREE.ShaderChunk.color_pars_vertex,
THREE.ShaderChunk.fog_pars_vertex,
THREE.ShaderChunk.morphtarget_pars_vertex,
THREE.ShaderChunk.skinning_pars_vertex,
THREE.ShaderChunk.shadowmap_pars_vertex,
THREE.ShaderChunk.logdepthbuf_pars_vertex,
THREE.ShaderChunk.clipping_planes_pars_vertex,
`#ifdef USE_PACKED_NORMAL
#if USE_PACKED_NORMAL == 0
vec3 decodeNormal(vec3 packedNormal)
{
float x = packedNormal.x * 2.0 - 1.0;
float y = packedNormal.y * 2.0 - 1.0;
vec2 scth = vec2(sin(x * PI), cos(x * PI));
vec2 scphi = vec2(sqrt(1.0 - y * y), y);
return normalize( vec3(scth.y * scphi.x, scth.x * scphi.x, scphi.y) );
}
#endif
#if USE_PACKED_NORMAL == 1
vec3 decodeNormal(vec3 packedNormal)
{
vec3 v = vec3(packedNormal.xy, 1.0 - abs(packedNormal.x) - abs(packedNormal.y));
if (v.z < 0.0)
{
v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
}
return normalize(v);
}
#endif
#if USE_PACKED_NORMAL == 2
vec3 decodeNormal(vec3 packedNormal)
{
vec3 v = (packedNormal * 2.0) - 1.0;
return normalize(v);
}
#endif
#endif`,
`#ifdef USE_PACKED_POSITION
#if USE_PACKED_POSITION == 0
uniform mat4 quantizeMatPos;
#endif
#endif`,
`#ifdef USE_PACKED_UV
#if USE_PACKED_UV == 1
uniform mat3 quantizeMatUV;
#endif
#endif`,
`#ifdef USE_PACKED_UV
#if USE_PACKED_UV == 0
vec2 decodeUV(vec2 packedUV)
{
vec2 uv = (packedUV * 2.0) - 1.0;
return uv;
}
#endif
#if USE_PACKED_UV == 1
vec2 decodeUV(vec2 packedUV)
{
vec2 uv = ( vec3(packedUV, 1.0) * quantizeMatUV ).xy;
return uv;
}
#endif
#endif`,
"void main() {",
THREE.ShaderChunk.uv_vertex,
`#ifdef USE_UV
#ifdef USE_PACKED_UV
vUv = decodeUV(vUv);
#endif
#endif`,
THREE.ShaderChunk.uv2_vertex,
THREE.ShaderChunk.color_vertex,
THREE.ShaderChunk.beginnormal_vertex,
`#ifdef USE_PACKED_NORMAL
objectNormal = decodeNormal(objectNormal);
#endif
#ifdef USE_TANGENT
vec3 objectTangent = vec3( tangent.xyz );
#endif
`,
THREE.ShaderChunk.morphnormal_vertex,
THREE.ShaderChunk.skinbase_vertex,
THREE.ShaderChunk.skinnormal_vertex,
THREE.ShaderChunk.defaultnormal_vertex,
"#ifndef FLAT_SHADED",
" vNormal = normalize( transformedNormal );",
"#endif",
THREE.ShaderChunk.begin_vertex,
`#ifdef USE_PACKED_POSITION
#if USE_PACKED_POSITION == 0
transformed = ( vec4(transformed, 1.0) * quantizeMatPos ).xyz;
#endif
#endif`,
THREE.ShaderChunk.morphtarget_vertex,
THREE.ShaderChunk.skinning_vertex,
THREE.ShaderChunk.displacementmap_vertex,
THREE.ShaderChunk.project_vertex,
THREE.ShaderChunk.logdepthbuf_vertex,
THREE.ShaderChunk.clipping_planes_vertex,
"vViewPosition = - mvPosition.xyz;",
THREE.ShaderChunk.worldpos_vertex,
THREE.ShaderChunk.envmap_vertex,
THREE.ShaderChunk.shadowmap_vertex,
THREE.ShaderChunk.fog_vertex,
"}"
].join("\n");
this.fragmentShader = [
"#define PHONG",
"uniform vec3 diffuse;",
"uniform vec3 emissive;",
"uniform vec3 specular;",
"uniform float shininess;",
"uniform float opacity;",
THREE.ShaderChunk.common,
THREE.ShaderChunk.packing,
THREE.ShaderChunk.dithering_pars_fragment,
THREE.ShaderChunk.color_pars_fragment,
THREE.ShaderChunk.uv_pars_fragment,
THREE.ShaderChunk.uv2_pars_fragment,
THREE.ShaderChunk.map_pars_fragment,
THREE.ShaderChunk.alphamap_pars_fragment,
THREE.ShaderChunk.aomap_pars_fragment,
THREE.ShaderChunk.lightmap_pars_fragment,
THREE.ShaderChunk.emissivemap_pars_fragment,
THREE.ShaderChunk.envmap_common_pars_fragment,
THREE.ShaderChunk.envmap_pars_fragment,
THREE.ShaderChunk.cube_uv_reflection_fragment,
THREE.ShaderChunk.fog_pars_fragment,
THREE.ShaderChunk.bsdfs,
THREE.ShaderChunk.lights_pars_begin,
THREE.ShaderChunk.lights_phong_pars_fragment,
THREE.ShaderChunk.shadowmap_pars_fragment,
THREE.ShaderChunk.bumpmap_pars_fragment,
THREE.ShaderChunk.normalmap_pars_fragment,
THREE.ShaderChunk.specularmap_pars_fragment,
THREE.ShaderChunk.logdepthbuf_pars_fragment,
THREE.ShaderChunk.clipping_planes_pars_fragment,
"void main() {",
THREE.ShaderChunk.clipping_planes_fragment,
"vec4 diffuseColor = vec4( diffuse, opacity );",
"ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
"vec3 totalEmissiveRadiance = emissive;",
THREE.ShaderChunk.logdepthbuf_fragment,
THREE.ShaderChunk.map_fragment,
THREE.ShaderChunk.color_fragment,
THREE.ShaderChunk.alphamap_fragment,
THREE.ShaderChunk.alphatest_fragment,
THREE.ShaderChunk.specularmap_fragment,
THREE.ShaderChunk.normal_fragment_begin,
THREE.ShaderChunk.normal_fragment_maps,
THREE.ShaderChunk.emissivemap_fragment,
// accumulation
THREE.ShaderChunk.lights_phong_fragment,
THREE.ShaderChunk.lights_fragment_begin,
THREE.ShaderChunk.lights_fragment_maps,
THREE.ShaderChunk.lights_fragment_end,
// modulation
THREE.ShaderChunk.aomap_fragment,
"vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",
THREE.ShaderChunk.envmap_fragment,
"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
THREE.ShaderChunk.tonemapping_fragment,
constants.version >= 154 ? THREE.ShaderChunk.colorspace_fragment : THREE.ShaderChunk.encodings_fragment,
THREE.ShaderChunk.fog_fragment,
THREE.ShaderChunk.premultiplied_alpha_fragment,
THREE.ShaderChunk.dithering_fragment,
"}"
].join("\n");
this.setValues(parameters);
}
}
exports.GeometryCompressionUtils = GeometryCompressionUtils;
exports.PackedPhongMaterial = PackedPhongMaterial;
//# sourceMappingURL=GeometryCompressionUtils.cjs.map
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
import { Mesh } from 'three'
export namespace GeometryCompressionUtils {
function compressNormals(mesh: Mesh, encodeMethod: string): void
function compressPositions(mesh: Mesh): void
function compressUvs(mesh: Mesh): void
}
+575
View File
@@ -0,0 +1,575 @@
import { BufferAttribute, Matrix4, Vector3, Matrix3, MeshPhongMaterial, UniformsUtils, ShaderLib, ShaderChunk } from "three";
import { version } from "../_polyfill/constants.js";
var GeometryCompressionUtils = {
/**
* Make the input mesh.geometry's normal attribute encoded and compressed by 3 different methods.
* Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the normal data.
*
* @param {THREE.Mesh} mesh
* @param {String} encodeMethod "DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES"
*
*/
compressNormals: function(mesh, encodeMethod) {
if (!mesh.geometry) {
console.error("Mesh must contain geometry. ");
}
const normal = mesh.geometry.attributes.normal;
if (!normal) {
console.error("Geometry must contain normal attribute. ");
}
if (normal.isPacked)
return;
if (normal.itemSize != 3) {
console.error("normal.itemSize is not 3, which cannot be encoded. ");
}
const array = normal.array;
const count = normal.count;
let result;
if (encodeMethod == "DEFAULT") {
result = new Uint8Array(count * 3);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.defaultEncode(array[idx], array[idx + 1], array[idx + 2], 1);
result[idx + 0] = encoded[0];
result[idx + 1] = encoded[1];
result[idx + 2] = encoded[2];
}
mesh.geometry.setAttribute("normal", new BufferAttribute(result, 3, true));
mesh.geometry.attributes.normal.bytes = result.length * 1;
} else if (encodeMethod == "OCT1Byte") {
result = new Int8Array(count * 2);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.octEncodeBest(array[idx], array[idx + 1], array[idx + 2], 1);
result[idx / 3 * 2 + 0] = encoded[0];
result[idx / 3 * 2 + 1] = encoded[1];
}
mesh.geometry.setAttribute("normal", new BufferAttribute(result, 2, true));
mesh.geometry.attributes.normal.bytes = result.length * 1;
} else if (encodeMethod == "OCT2Byte") {
result = new Int16Array(count * 2);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.octEncodeBest(array[idx], array[idx + 1], array[idx + 2], 2);
result[idx / 3 * 2 + 0] = encoded[0];
result[idx / 3 * 2 + 1] = encoded[1];
}
mesh.geometry.setAttribute("normal", new BufferAttribute(result, 2, true));
mesh.geometry.attributes.normal.bytes = result.length * 2;
} else if (encodeMethod == "ANGLES") {
result = new Uint16Array(count * 2);
for (let idx = 0; idx < array.length; idx += 3) {
const encoded = this.EncodingFuncs.anglesEncode(array[idx], array[idx + 1], array[idx + 2]);
result[idx / 3 * 2 + 0] = encoded[0];
result[idx / 3 * 2 + 1] = encoded[1];
}
mesh.geometry.setAttribute("normal", new BufferAttribute(result, 2, true));
mesh.geometry.attributes.normal.bytes = result.length * 2;
} else {
console.error("Unrecognized encoding method, should be `DEFAULT` or `ANGLES` or `OCT`. ");
}
mesh.geometry.attributes.normal.needsUpdate = true;
mesh.geometry.attributes.normal.isPacked = true;
mesh.geometry.attributes.normal.packingMethod = encodeMethod;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
if (encodeMethod == "ANGLES") {
mesh.material.defines.USE_PACKED_NORMAL = 0;
}
if (encodeMethod == "OCT1Byte") {
mesh.material.defines.USE_PACKED_NORMAL = 1;
}
if (encodeMethod == "OCT2Byte") {
mesh.material.defines.USE_PACKED_NORMAL = 1;
}
if (encodeMethod == "DEFAULT") {
mesh.material.defines.USE_PACKED_NORMAL = 2;
}
},
/**
* Make the input mesh.geometry's position attribute encoded and compressed.
* Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the position data.
*
* @param {THREE.Mesh} mesh
*
*/
compressPositions: function(mesh) {
if (!mesh.geometry) {
console.error("Mesh must contain geometry. ");
}
const position = mesh.geometry.attributes.position;
if (!position) {
console.error("Geometry must contain position attribute. ");
}
if (position.isPacked)
return;
if (position.itemSize != 3) {
console.error("position.itemSize is not 3, which cannot be packed. ");
}
const array = position.array;
const encodingBytes = 2;
const result = this.EncodingFuncs.quantizedEncode(array, encodingBytes);
const quantized = result.quantized;
const decodeMat = result.decodeMat;
if (mesh.geometry.boundingBox == null)
mesh.geometry.computeBoundingBox();
if (mesh.geometry.boundingSphere == null)
mesh.geometry.computeBoundingSphere();
mesh.geometry.setAttribute("position", new BufferAttribute(quantized, 3));
mesh.geometry.attributes.position.isPacked = true;
mesh.geometry.attributes.position.needsUpdate = true;
mesh.geometry.attributes.position.bytes = quantized.length * encodingBytes;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
mesh.material.defines.USE_PACKED_POSITION = 0;
mesh.material.uniforms.quantizeMatPos.value = decodeMat;
mesh.material.uniforms.quantizeMatPos.needsUpdate = true;
},
/**
* Make the input mesh.geometry's uv attribute encoded and compressed.
* Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the uv data.
*
* @param {THREE.Mesh} mesh
*
*/
compressUvs: function(mesh) {
if (!mesh.geometry) {
console.error("Mesh must contain geometry property. ");
}
const uvs = mesh.geometry.attributes.uv;
if (!uvs) {
console.error("Geometry must contain uv attribute. ");
}
if (uvs.isPacked)
return;
const range = { min: Infinity, max: -Infinity };
const array = uvs.array;
for (let i = 0; i < array.length; i++) {
range.min = Math.min(range.min, array[i]);
range.max = Math.max(range.max, array[i]);
}
let result;
if (range.min >= -1 && range.max <= 1) {
result = new Uint16Array(array.length);
for (let i = 0; i < array.length; i += 2) {
const encoded = this.EncodingFuncs.defaultEncode(array[i], array[i + 1], 0, 2);
result[i] = encoded[0];
result[i + 1] = encoded[1];
}
mesh.geometry.setAttribute("uv", new BufferAttribute(result, 2, true));
mesh.geometry.attributes.uv.isPacked = true;
mesh.geometry.attributes.uv.needsUpdate = true;
mesh.geometry.attributes.uv.bytes = result.length * 2;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
mesh.material.defines.USE_PACKED_UV = 0;
} else {
result = this.EncodingFuncs.quantizedEncodeUV(array, 2);
mesh.geometry.setAttribute("uv", new BufferAttribute(result.quantized, 2));
mesh.geometry.attributes.uv.isPacked = true;
mesh.geometry.attributes.uv.needsUpdate = true;
mesh.geometry.attributes.uv.bytes = result.quantized.length * 2;
if (!(mesh.material instanceof PackedPhongMaterial)) {
mesh.material = new PackedPhongMaterial().copy(mesh.material);
}
mesh.material.defines.USE_PACKED_UV = 1;
mesh.material.uniforms.quantizeMatUV.value = result.decodeMat;
mesh.material.uniforms.quantizeMatUV.needsUpdate = true;
}
},
EncodingFuncs: {
defaultEncode: function(x, y, z, bytes) {
if (bytes == 1) {
const tmpx = Math.round((x + 1) * 0.5 * 255);
const tmpy = Math.round((y + 1) * 0.5 * 255);
const tmpz = Math.round((z + 1) * 0.5 * 255);
return new Uint8Array([tmpx, tmpy, tmpz]);
} else if (bytes == 2) {
const tmpx = Math.round((x + 1) * 0.5 * 65535);
const tmpy = Math.round((y + 1) * 0.5 * 65535);
const tmpz = Math.round((z + 1) * 0.5 * 65535);
return new Uint16Array([tmpx, tmpy, tmpz]);
} else {
console.error("number of bytes must be 1 or 2");
}
},
defaultDecode: function(array, bytes) {
if (bytes == 1) {
return [array[0] / 255 * 2 - 1, array[1] / 255 * 2 - 1, array[2] / 255 * 2 - 1];
} else if (bytes == 2) {
return [array[0] / 65535 * 2 - 1, array[1] / 65535 * 2 - 1, array[2] / 65535 * 2 - 1];
} else {
console.error("number of bytes must be 1 or 2");
}
},
// for `Angles` encoding
anglesEncode: function(x, y, z) {
const normal0 = parseInt(0.5 * (1 + Math.atan2(y, x) / Math.PI) * 65535);
const normal1 = parseInt(0.5 * (1 + z) * 65535);
return new Uint16Array([normal0, normal1]);
},
// for `Octahedron` encoding
octEncodeBest: function(x, y, z, bytes) {
var oct, dec, best, currentCos, bestCos;
best = oct = octEncodeVec3(x, y, z, "floor", "floor");
dec = octDecodeVec2(oct);
bestCos = dot(x, y, z, dec);
oct = octEncodeVec3(x, y, z, "ceil", "floor");
dec = octDecodeVec2(oct);
currentCos = dot(x, y, z, dec);
if (currentCos > bestCos) {
best = oct;
bestCos = currentCos;
}
oct = octEncodeVec3(x, y, z, "floor", "ceil");
dec = octDecodeVec2(oct);
currentCos = dot(x, y, z, dec);
if (currentCos > bestCos) {
best = oct;
bestCos = currentCos;
}
oct = octEncodeVec3(x, y, z, "ceil", "ceil");
dec = octDecodeVec2(oct);
currentCos = dot(x, y, z, dec);
if (currentCos > bestCos) {
best = oct;
}
return best;
function octEncodeVec3(x0, y0, z0, xfunc, yfunc) {
var x2 = x0 / (Math.abs(x0) + Math.abs(y0) + Math.abs(z0));
var y2 = y0 / (Math.abs(x0) + Math.abs(y0) + Math.abs(z0));
if (z < 0) {
var tempx = (1 - Math.abs(y2)) * (x2 >= 0 ? 1 : -1);
var tempy = (1 - Math.abs(x2)) * (y2 >= 0 ? 1 : -1);
x2 = tempx;
y2 = tempy;
var diff = 1 - Math.abs(x2) - Math.abs(y2);
if (diff > 0) {
diff += 1e-3;
x2 += x2 > 0 ? diff / 2 : -diff / 2;
y2 += y2 > 0 ? diff / 2 : -diff / 2;
}
}
if (bytes == 1) {
return new Int8Array([Math[xfunc](x2 * 127.5 + (x2 < 0 ? 1 : 0)), Math[yfunc](y2 * 127.5 + (y2 < 0 ? 1 : 0))]);
}
if (bytes == 2) {
return new Int16Array([
Math[xfunc](x2 * 32767.5 + (x2 < 0 ? 1 : 0)),
Math[yfunc](y2 * 32767.5 + (y2 < 0 ? 1 : 0))
]);
}
}
function octDecodeVec2(oct2) {
var x2 = oct2[0];
var y2 = oct2[1];
if (bytes == 1) {
x2 /= x2 < 0 ? 127 : 128;
y2 /= y2 < 0 ? 127 : 128;
} else if (bytes == 2) {
x2 /= x2 < 0 ? 32767 : 32768;
y2 /= y2 < 0 ? 32767 : 32768;
}
var z2 = 1 - Math.abs(x2) - Math.abs(y2);
if (z2 < 0) {
var tmpx = x2;
x2 = (1 - Math.abs(y2)) * (x2 >= 0 ? 1 : -1);
y2 = (1 - Math.abs(tmpx)) * (y2 >= 0 ? 1 : -1);
}
var length = Math.sqrt(x2 * x2 + y2 * y2 + z2 * z2);
return [x2 / length, y2 / length, z2 / length];
}
function dot(x2, y2, z2, vec3) {
return x2 * vec3[0] + y2 * vec3[1] + z2 * vec3[2];
}
},
quantizedEncode: function(array, bytes) {
let quantized, segments;
if (bytes == 1) {
quantized = new Uint8Array(array.length);
segments = 255;
} else if (bytes == 2) {
quantized = new Uint16Array(array.length);
segments = 65535;
} else {
console.error("number of bytes error! ");
}
const decodeMat = new Matrix4();
const min = new Float32Array(3);
const max = new Float32Array(3);
min[0] = min[1] = min[2] = Number.MAX_VALUE;
max[0] = max[1] = max[2] = -Number.MAX_VALUE;
for (let i = 0; i < array.length; i += 3) {
min[0] = Math.min(min[0], array[i + 0]);
min[1] = Math.min(min[1], array[i + 1]);
min[2] = Math.min(min[2], array[i + 2]);
max[0] = Math.max(max[0], array[i + 0]);
max[1] = Math.max(max[1], array[i + 1]);
max[2] = Math.max(max[2], array[i + 2]);
}
decodeMat.scale(
new Vector3((max[0] - min[0]) / segments, (max[1] - min[1]) / segments, (max[2] - min[2]) / segments)
);
decodeMat.elements[12] = min[0];
decodeMat.elements[13] = min[1];
decodeMat.elements[14] = min[2];
decodeMat.transpose();
const multiplier = new Float32Array([
max[0] !== min[0] ? segments / (max[0] - min[0]) : 0,
max[1] !== min[1] ? segments / (max[1] - min[1]) : 0,
max[2] !== min[2] ? segments / (max[2] - min[2]) : 0
]);
for (let i = 0; i < array.length; i += 3) {
quantized[i + 0] = Math.floor((array[i + 0] - min[0]) * multiplier[0]);
quantized[i + 1] = Math.floor((array[i + 1] - min[1]) * multiplier[1]);
quantized[i + 2] = Math.floor((array[i + 2] - min[2]) * multiplier[2]);
}
return {
quantized,
decodeMat
};
},
quantizedEncodeUV: function(array, bytes) {
let quantized, segments;
if (bytes == 1) {
quantized = new Uint8Array(array.length);
segments = 255;
} else if (bytes == 2) {
quantized = new Uint16Array(array.length);
segments = 65535;
} else {
console.error("number of bytes error! ");
}
const decodeMat = new Matrix3();
const min = new Float32Array(2);
const max = new Float32Array(2);
min[0] = min[1] = Number.MAX_VALUE;
max[0] = max[1] = -Number.MAX_VALUE;
for (let i = 0; i < array.length; i += 2) {
min[0] = Math.min(min[0], array[i + 0]);
min[1] = Math.min(min[1], array[i + 1]);
max[0] = Math.max(max[0], array[i + 0]);
max[1] = Math.max(max[1], array[i + 1]);
}
decodeMat.scale((max[0] - min[0]) / segments, (max[1] - min[1]) / segments);
decodeMat.elements[6] = min[0];
decodeMat.elements[7] = min[1];
decodeMat.transpose();
const multiplier = new Float32Array([
max[0] !== min[0] ? segments / (max[0] - min[0]) : 0,
max[1] !== min[1] ? segments / (max[1] - min[1]) : 0
]);
for (let i = 0; i < array.length; i += 2) {
quantized[i + 0] = Math.floor((array[i + 0] - min[0]) * multiplier[0]);
quantized[i + 1] = Math.floor((array[i + 1] - min[1]) * multiplier[1]);
}
return {
quantized,
decodeMat
};
}
}
};
class PackedPhongMaterial extends MeshPhongMaterial {
constructor(parameters) {
super();
this.defines = {};
this.type = "PackedPhongMaterial";
this.uniforms = UniformsUtils.merge([
ShaderLib.phong.uniforms,
{
quantizeMatPos: { value: null },
quantizeMatUV: { value: null }
}
]);
this.vertexShader = [
"#define PHONG",
"varying vec3 vViewPosition;",
"#ifndef FLAT_SHADED",
"varying vec3 vNormal;",
"#endif",
ShaderChunk.common,
ShaderChunk.uv_pars_vertex,
ShaderChunk.uv2_pars_vertex,
ShaderChunk.displacementmap_pars_vertex,
ShaderChunk.envmap_pars_vertex,
ShaderChunk.color_pars_vertex,
ShaderChunk.fog_pars_vertex,
ShaderChunk.morphtarget_pars_vertex,
ShaderChunk.skinning_pars_vertex,
ShaderChunk.shadowmap_pars_vertex,
ShaderChunk.logdepthbuf_pars_vertex,
ShaderChunk.clipping_planes_pars_vertex,
`#ifdef USE_PACKED_NORMAL
#if USE_PACKED_NORMAL == 0
vec3 decodeNormal(vec3 packedNormal)
{
float x = packedNormal.x * 2.0 - 1.0;
float y = packedNormal.y * 2.0 - 1.0;
vec2 scth = vec2(sin(x * PI), cos(x * PI));
vec2 scphi = vec2(sqrt(1.0 - y * y), y);
return normalize( vec3(scth.y * scphi.x, scth.x * scphi.x, scphi.y) );
}
#endif
#if USE_PACKED_NORMAL == 1
vec3 decodeNormal(vec3 packedNormal)
{
vec3 v = vec3(packedNormal.xy, 1.0 - abs(packedNormal.x) - abs(packedNormal.y));
if (v.z < 0.0)
{
v.xy = (1.0 - abs(v.yx)) * vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
}
return normalize(v);
}
#endif
#if USE_PACKED_NORMAL == 2
vec3 decodeNormal(vec3 packedNormal)
{
vec3 v = (packedNormal * 2.0) - 1.0;
return normalize(v);
}
#endif
#endif`,
`#ifdef USE_PACKED_POSITION
#if USE_PACKED_POSITION == 0
uniform mat4 quantizeMatPos;
#endif
#endif`,
`#ifdef USE_PACKED_UV
#if USE_PACKED_UV == 1
uniform mat3 quantizeMatUV;
#endif
#endif`,
`#ifdef USE_PACKED_UV
#if USE_PACKED_UV == 0
vec2 decodeUV(vec2 packedUV)
{
vec2 uv = (packedUV * 2.0) - 1.0;
return uv;
}
#endif
#if USE_PACKED_UV == 1
vec2 decodeUV(vec2 packedUV)
{
vec2 uv = ( vec3(packedUV, 1.0) * quantizeMatUV ).xy;
return uv;
}
#endif
#endif`,
"void main() {",
ShaderChunk.uv_vertex,
`#ifdef USE_UV
#ifdef USE_PACKED_UV
vUv = decodeUV(vUv);
#endif
#endif`,
ShaderChunk.uv2_vertex,
ShaderChunk.color_vertex,
ShaderChunk.beginnormal_vertex,
`#ifdef USE_PACKED_NORMAL
objectNormal = decodeNormal(objectNormal);
#endif
#ifdef USE_TANGENT
vec3 objectTangent = vec3( tangent.xyz );
#endif
`,
ShaderChunk.morphnormal_vertex,
ShaderChunk.skinbase_vertex,
ShaderChunk.skinnormal_vertex,
ShaderChunk.defaultnormal_vertex,
"#ifndef FLAT_SHADED",
" vNormal = normalize( transformedNormal );",
"#endif",
ShaderChunk.begin_vertex,
`#ifdef USE_PACKED_POSITION
#if USE_PACKED_POSITION == 0
transformed = ( vec4(transformed, 1.0) * quantizeMatPos ).xyz;
#endif
#endif`,
ShaderChunk.morphtarget_vertex,
ShaderChunk.skinning_vertex,
ShaderChunk.displacementmap_vertex,
ShaderChunk.project_vertex,
ShaderChunk.logdepthbuf_vertex,
ShaderChunk.clipping_planes_vertex,
"vViewPosition = - mvPosition.xyz;",
ShaderChunk.worldpos_vertex,
ShaderChunk.envmap_vertex,
ShaderChunk.shadowmap_vertex,
ShaderChunk.fog_vertex,
"}"
].join("\n");
this.fragmentShader = [
"#define PHONG",
"uniform vec3 diffuse;",
"uniform vec3 emissive;",
"uniform vec3 specular;",
"uniform float shininess;",
"uniform float opacity;",
ShaderChunk.common,
ShaderChunk.packing,
ShaderChunk.dithering_pars_fragment,
ShaderChunk.color_pars_fragment,
ShaderChunk.uv_pars_fragment,
ShaderChunk.uv2_pars_fragment,
ShaderChunk.map_pars_fragment,
ShaderChunk.alphamap_pars_fragment,
ShaderChunk.aomap_pars_fragment,
ShaderChunk.lightmap_pars_fragment,
ShaderChunk.emissivemap_pars_fragment,
ShaderChunk.envmap_common_pars_fragment,
ShaderChunk.envmap_pars_fragment,
ShaderChunk.cube_uv_reflection_fragment,
ShaderChunk.fog_pars_fragment,
ShaderChunk.bsdfs,
ShaderChunk.lights_pars_begin,
ShaderChunk.lights_phong_pars_fragment,
ShaderChunk.shadowmap_pars_fragment,
ShaderChunk.bumpmap_pars_fragment,
ShaderChunk.normalmap_pars_fragment,
ShaderChunk.specularmap_pars_fragment,
ShaderChunk.logdepthbuf_pars_fragment,
ShaderChunk.clipping_planes_pars_fragment,
"void main() {",
ShaderChunk.clipping_planes_fragment,
"vec4 diffuseColor = vec4( diffuse, opacity );",
"ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
"vec3 totalEmissiveRadiance = emissive;",
ShaderChunk.logdepthbuf_fragment,
ShaderChunk.map_fragment,
ShaderChunk.color_fragment,
ShaderChunk.alphamap_fragment,
ShaderChunk.alphatest_fragment,
ShaderChunk.specularmap_fragment,
ShaderChunk.normal_fragment_begin,
ShaderChunk.normal_fragment_maps,
ShaderChunk.emissivemap_fragment,
// accumulation
ShaderChunk.lights_phong_fragment,
ShaderChunk.lights_fragment_begin,
ShaderChunk.lights_fragment_maps,
ShaderChunk.lights_fragment_end,
// modulation
ShaderChunk.aomap_fragment,
"vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",
ShaderChunk.envmap_fragment,
"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
ShaderChunk.tonemapping_fragment,
version >= 154 ? ShaderChunk.colorspace_fragment : ShaderChunk.encodings_fragment,
ShaderChunk.fog_fragment,
ShaderChunk.premultiplied_alpha_fragment,
ShaderChunk.dithering_fragment,
"}"
].join("\n");
this.setValues(parameters);
}
}
export {
GeometryCompressionUtils,
PackedPhongMaterial
};
//# sourceMappingURL=GeometryCompressionUtils.js.map
File diff suppressed because one or more lines are too long
+110
View File
@@ -0,0 +1,110 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const hilbert2D = (center = new THREE.Vector3(0, 0, 0), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3) => {
const half = size / 2;
const vec_s = [
new THREE.Vector3(center.x - half, center.y, center.z - half),
new THREE.Vector3(center.x - half, center.y, center.z + half),
new THREE.Vector3(center.x + half, center.y, center.z + half),
new THREE.Vector3(center.x + half, center.y, center.z - half)
];
const vec = [vec_s[v0], vec_s[v1], vec_s[v2], vec_s[v3]];
if (0 <= --iterations) {
const tmp = [];
Array.prototype.push.apply(tmp, hilbert2D(vec[0], half, iterations, v0, v3, v2, v1));
Array.prototype.push.apply(tmp, hilbert2D(vec[1], half, iterations, v0, v1, v2, v3));
Array.prototype.push.apply(tmp, hilbert2D(vec[2], half, iterations, v0, v1, v2, v3));
Array.prototype.push.apply(tmp, hilbert2D(vec[3], half, iterations, v2, v1, v0, v3));
return tmp;
}
return vec;
};
const hilbert3D = (center = new THREE.Vector3(0, 0, 0), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7) => {
const half = size / 2;
const vec_s = [
new THREE.Vector3(center.x - half, center.y + half, center.z - half),
new THREE.Vector3(center.x - half, center.y + half, center.z + half),
new THREE.Vector3(center.x - half, center.y - half, center.z + half),
new THREE.Vector3(center.x - half, center.y - half, center.z - half),
new THREE.Vector3(center.x + half, center.y - half, center.z - half),
new THREE.Vector3(center.x + half, center.y - half, center.z + half),
new THREE.Vector3(center.x + half, center.y + half, center.z + half),
new THREE.Vector3(center.x + half, center.y + half, center.z - half)
];
const vec = [vec_s[v0], vec_s[v1], vec_s[v2], vec_s[v3], vec_s[v4], vec_s[v5], vec_s[v6], vec_s[v7]];
if (--iterations >= 0) {
const tmp = [];
Array.prototype.push.apply(tmp, hilbert3D(vec[0], half, iterations, v0, v3, v4, v7, v6, v5, v2, v1));
Array.prototype.push.apply(tmp, hilbert3D(vec[1], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3));
Array.prototype.push.apply(tmp, hilbert3D(vec[2], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3));
Array.prototype.push.apply(tmp, hilbert3D(vec[3], half, iterations, v2, v3, v0, v1, v6, v7, v4, v5));
Array.prototype.push.apply(tmp, hilbert3D(vec[4], half, iterations, v2, v3, v0, v1, v6, v7, v4, v5));
Array.prototype.push.apply(tmp, hilbert3D(vec[5], half, iterations, v4, v3, v2, v5, v6, v1, v0, v7));
Array.prototype.push.apply(tmp, hilbert3D(vec[6], half, iterations, v4, v3, v2, v5, v6, v1, v0, v7));
Array.prototype.push.apply(tmp, hilbert3D(vec[7], half, iterations, v6, v5, v2, v1, v0, v3, v4, v7));
return tmp;
}
return vec;
};
const gosper = (size = 1) => {
function fractalize(config) {
let output = "";
let input = config.axiom;
for (let i = 0, il = config.steps; 0 <= il ? i < il : i > il; 0 <= il ? i++ : i--) {
output = "";
for (let j = 0, jl = input.length; j < jl; j++) {
const char = input[j];
if (char in config.rules) {
output += config.rules[char];
} else {
output += char;
}
}
input = output;
}
return output;
}
function toPoints(config) {
let currX = 0;
let currY = 0;
let angle = 0;
const path = [0, 0, 0];
const fractal = config.fractal;
for (let i = 0, l = fractal.length; i < l; i++) {
const char = fractal[i];
if (char === "+") {
angle += config.angle;
} else if (char === "-") {
angle -= config.angle;
} else if (char === "F") {
currX += config.size * Math.cos(angle);
currY += -config.size * Math.sin(angle);
path.push(currX, currY, 0);
}
}
return path;
}
const gosper2 = fractalize({
axiom: "A",
steps: 4,
rules: {
A: "A+BF++BF-FA--FAFA-BF+",
B: "-FA+BFBF++BF+FA--FA-B"
}
});
const points = toPoints({
fractal: gosper2,
size,
angle: Math.PI / 3
// 60 degrees
});
return points;
};
const GeometryUtils = {
hilbert3D,
gosper,
hilbert2D
};
exports.GeometryUtils = GeometryUtils;
//# sourceMappingURL=GeometryUtils.cjs.map
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
import { Vector3 } from 'three';
export declare const GeometryUtils: {
hilbert3D: (center?: Vector3, size?: number, iterations?: number, v0?: number, v1?: number, v2?: number, v3?: number, v4?: number, v5?: number, v6?: number, v7?: number) => Vector3[];
gosper: (size?: number) => number[];
hilbert2D: (center?: Vector3, size?: number, iterations?: number, v0?: number, v1?: number, v2?: number, v3?: number) => Vector3[];
};
+110
View File
@@ -0,0 +1,110 @@
import { Vector3 } from "three";
const hilbert2D = (center = new Vector3(0, 0, 0), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3) => {
const half = size / 2;
const vec_s = [
new Vector3(center.x - half, center.y, center.z - half),
new Vector3(center.x - half, center.y, center.z + half),
new Vector3(center.x + half, center.y, center.z + half),
new Vector3(center.x + half, center.y, center.z - half)
];
const vec = [vec_s[v0], vec_s[v1], vec_s[v2], vec_s[v3]];
if (0 <= --iterations) {
const tmp = [];
Array.prototype.push.apply(tmp, hilbert2D(vec[0], half, iterations, v0, v3, v2, v1));
Array.prototype.push.apply(tmp, hilbert2D(vec[1], half, iterations, v0, v1, v2, v3));
Array.prototype.push.apply(tmp, hilbert2D(vec[2], half, iterations, v0, v1, v2, v3));
Array.prototype.push.apply(tmp, hilbert2D(vec[3], half, iterations, v2, v1, v0, v3));
return tmp;
}
return vec;
};
const hilbert3D = (center = new Vector3(0, 0, 0), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7) => {
const half = size / 2;
const vec_s = [
new Vector3(center.x - half, center.y + half, center.z - half),
new Vector3(center.x - half, center.y + half, center.z + half),
new Vector3(center.x - half, center.y - half, center.z + half),
new Vector3(center.x - half, center.y - half, center.z - half),
new Vector3(center.x + half, center.y - half, center.z - half),
new Vector3(center.x + half, center.y - half, center.z + half),
new Vector3(center.x + half, center.y + half, center.z + half),
new Vector3(center.x + half, center.y + half, center.z - half)
];
const vec = [vec_s[v0], vec_s[v1], vec_s[v2], vec_s[v3], vec_s[v4], vec_s[v5], vec_s[v6], vec_s[v7]];
if (--iterations >= 0) {
const tmp = [];
Array.prototype.push.apply(tmp, hilbert3D(vec[0], half, iterations, v0, v3, v4, v7, v6, v5, v2, v1));
Array.prototype.push.apply(tmp, hilbert3D(vec[1], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3));
Array.prototype.push.apply(tmp, hilbert3D(vec[2], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3));
Array.prototype.push.apply(tmp, hilbert3D(vec[3], half, iterations, v2, v3, v0, v1, v6, v7, v4, v5));
Array.prototype.push.apply(tmp, hilbert3D(vec[4], half, iterations, v2, v3, v0, v1, v6, v7, v4, v5));
Array.prototype.push.apply(tmp, hilbert3D(vec[5], half, iterations, v4, v3, v2, v5, v6, v1, v0, v7));
Array.prototype.push.apply(tmp, hilbert3D(vec[6], half, iterations, v4, v3, v2, v5, v6, v1, v0, v7));
Array.prototype.push.apply(tmp, hilbert3D(vec[7], half, iterations, v6, v5, v2, v1, v0, v3, v4, v7));
return tmp;
}
return vec;
};
const gosper = (size = 1) => {
function fractalize(config) {
let output = "";
let input = config.axiom;
for (let i = 0, il = config.steps; 0 <= il ? i < il : i > il; 0 <= il ? i++ : i--) {
output = "";
for (let j = 0, jl = input.length; j < jl; j++) {
const char = input[j];
if (char in config.rules) {
output += config.rules[char];
} else {
output += char;
}
}
input = output;
}
return output;
}
function toPoints(config) {
let currX = 0;
let currY = 0;
let angle = 0;
const path = [0, 0, 0];
const fractal = config.fractal;
for (let i = 0, l = fractal.length; i < l; i++) {
const char = fractal[i];
if (char === "+") {
angle += config.angle;
} else if (char === "-") {
angle -= config.angle;
} else if (char === "F") {
currX += config.size * Math.cos(angle);
currY += -config.size * Math.sin(angle);
path.push(currX, currY, 0);
}
}
return path;
}
const gosper2 = fractalize({
axiom: "A",
steps: 4,
rules: {
A: "A+BF++BF-FA--FAFA-BF+",
B: "-FA+BFBF++BF+FA--FA-B"
}
});
const points = toPoints({
fractal: gosper2,
size,
angle: Math.PI / 3
// 60 degrees
});
return points;
};
const GeometryUtils = {
hilbert3D,
gosper,
hilbert2D
};
export {
GeometryUtils
};
//# sourceMappingURL=GeometryUtils.js.map
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
import { Group, Object3D } from 'three'
export namespace LDrawUtils {
function mergeObject(object: Object3D): Group
}
+224
View File
@@ -0,0 +1,224 @@
"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");
var _mipmapMaterial = /* @__PURE__ */ _getMipmapMaterial();
var _mesh = /* @__PURE__ */ new THREE.Mesh(/* @__PURE__ */ new THREE.PlaneGeometry(2, 2), _mipmapMaterial);
var _flatCamera = /* @__PURE__ */ new THREE.OrthographicCamera(0, 1, 0, 1, 0, 1);
var _tempTarget = null;
class RoughnessMipmapper {
constructor(renderer) {
__publicField(this, "generateMipmaps", function(material) {
if ("roughnessMap" in material === false)
return;
var { roughnessMap, normalMap } = material;
if (roughnessMap === null || normalMap === null || !roughnessMap.generateMipmaps || material.userData.roughnessUpdated) {
return;
}
material.userData.roughnessUpdated = true;
var width = Math.max(roughnessMap.image.width, normalMap.image.width);
var height = Math.max(roughnessMap.image.height, normalMap.image.height);
if (!THREE.MathUtils.isPowerOfTwo(width) || !THREE.MathUtils.isPowerOfTwo(height))
return;
var oldTarget = this._renderer.getRenderTarget();
var autoClear = this._renderer.autoClear;
this._renderer.autoClear = false;
if (_tempTarget === null || _tempTarget.width !== width || _tempTarget.height !== height) {
if (_tempTarget !== null)
_tempTarget.dispose();
_tempTarget = new THREE.WebGLRenderTarget(width, height, {
depthBuffer: false
});
_tempTarget.scissorTest = true;
}
if (width !== roughnessMap.image.width || height !== roughnessMap.image.height) {
var params = {
wrapS: roughnessMap.wrapS,
wrapT: roughnessMap.wrapT,
magFilter: roughnessMap.magFilter,
minFilter: roughnessMap.minFilter,
depthBuffer: false
};
var newRoughnessTarget = new THREE.WebGLRenderTarget(width, height, params);
newRoughnessTarget.texture.generateMipmaps = true;
this._renderer.setRenderTarget(newRoughnessTarget);
material.roughnessMap = newRoughnessTarget.texture;
if (material.metalnessMap == roughnessMap)
material.metalnessMap = material.roughnessMap;
if (material.aoMap == roughnessMap)
material.aoMap = material.roughnessMap;
}
_mipmapMaterial.uniforms.roughnessMap.value = roughnessMap;
_mipmapMaterial.uniforms.normalMap.value = normalMap;
var position = new THREE.Vector2(0, 0);
var texelSize = _mipmapMaterial.uniforms.texelSize.value;
for (let mip = 0; width >= 1 && height >= 1; ++mip, width /= 2, height /= 2) {
texelSize.set(1 / width, 1 / height);
if (mip == 0)
texelSize.set(0, 0);
_tempTarget.viewport.set(position.x, position.y, width, height);
_tempTarget.scissor.set(position.x, position.y, width, height);
this._renderer.setRenderTarget(_tempTarget);
this._renderer.render(_mesh, _flatCamera);
this._renderer.copyFramebufferToTexture(position, material.roughnessMap, mip);
_mipmapMaterial.uniforms.roughnessMap.value = material.roughnessMap;
}
if (roughnessMap !== material.roughnessMap)
roughnessMap.dispose();
this._renderer.setRenderTarget(oldTarget);
this._renderer.autoClear = autoClear;
});
__publicField(this, "dispose", function() {
_mipmapMaterial.dispose();
_mesh.geometry.dispose();
if (_tempTarget != null)
_tempTarget.dispose();
});
this._renderer = renderer;
this._renderer.compile(_mesh, _flatCamera);
}
}
function _getMipmapMaterial() {
var shaderMaterial = new THREE.RawShaderMaterial({
uniforms: {
roughnessMap: { value: null },
normalMap: { value: null },
texelSize: { value: new THREE.Vector2(1, 1) }
},
vertexShader: (
/* glsl */
`
precision mediump float;
precision mediump int;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4( position, 1.0 );
}
`
),
fragmentShader: (
/* glsl */
`
precision mediump float;
precision mediump int;
varying vec2 vUv;
uniform sampler2D roughnessMap;
uniform sampler2D normalMap;
uniform vec2 texelSize;
#define ENVMAP_TYPE_CUBE_UV
vec4 envMapTexelToLinear( vec4 a ) { return a; }
#include <cube_uv_reflection_fragment>
float roughnessToVariance( float roughness ) {
float variance = 0.0;
if ( roughness >= r1 ) {
variance = ( r0 - roughness ) * ( v1 - v0 ) / ( r0 - r1 ) + v0;
} else if ( roughness >= r4 ) {
variance = ( r1 - roughness ) * ( v4 - v1 ) / ( r1 - r4 ) + v1;
} else if ( roughness >= r5 ) {
variance = ( r4 - roughness ) * ( v5 - v4 ) / ( r4 - r5 ) + v4;
} else {
float roughness2 = roughness * roughness;
variance = 1.79 * roughness2 * roughness2;
}
return variance;
}
float varianceToRoughness( float variance ) {
float roughness = 0.0;
if ( variance >= v1 ) {
roughness = ( v0 - variance ) * ( r1 - r0 ) / ( v0 - v1 ) + r0;
} else if ( variance >= v4 ) {
roughness = ( v1 - variance ) * ( r4 - r1 ) / ( v1 - v4 ) + r1;
} else if ( variance >= v5 ) {
roughness = ( v4 - variance ) * ( r5 - r4 ) / ( v4 - v5 ) + r4;
} else {
roughness = pow( 0.559 * variance, 0.25 ); // 0.559 = 1.0 / 1.79
}
return roughness;
}
void main() {
gl_FragColor = texture2D( roughnessMap, vUv, - 1.0 );
if ( texelSize.x == 0.0 ) return;
float roughness = gl_FragColor.g;
float variance = roughnessToVariance( roughness );
vec3 avgNormal;
for ( float x = - 1.0; x < 2.0; x += 2.0 ) {
for ( float y = - 1.0; y < 2.0; y += 2.0 ) {
vec2 uv = vUv + vec2( x, y ) * 0.25 * texelSize;
avgNormal += normalize( texture2D( normalMap, uv, - 1.0 ).xyz - 0.5 );
}
}
variance += 1.0 - 0.25 * length( avgNormal );
gl_FragColor.g = varianceToRoughness( variance );
}
`
),
blending: THREE.NoBlending,
depthTest: false,
depthWrite: false
});
shaderMaterial.type = "RoughnessMipmapper";
return shaderMaterial;
}
exports.RoughnessMipmapper = RoughnessMipmapper;
//# sourceMappingURL=RoughnessMipmapper.cjs.map
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
import { Material, WebGLRenderer } from 'three'
export class RoughnessMipmapper {
constructor(renderer: WebGLRenderer)
generateMipmaps(material: Material): void
dispose(): void
}
+224
View File
@@ -0,0 +1,224 @@
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 { MathUtils, WebGLRenderTarget, Vector2, Mesh, PlaneGeometry, OrthographicCamera, RawShaderMaterial, NoBlending } from "three";
var _mipmapMaterial = /* @__PURE__ */ _getMipmapMaterial();
var _mesh = /* @__PURE__ */ new Mesh(/* @__PURE__ */ new PlaneGeometry(2, 2), _mipmapMaterial);
var _flatCamera = /* @__PURE__ */ new OrthographicCamera(0, 1, 0, 1, 0, 1);
var _tempTarget = null;
class RoughnessMipmapper {
constructor(renderer) {
__publicField(this, "generateMipmaps", function(material) {
if ("roughnessMap" in material === false)
return;
var { roughnessMap, normalMap } = material;
if (roughnessMap === null || normalMap === null || !roughnessMap.generateMipmaps || material.userData.roughnessUpdated) {
return;
}
material.userData.roughnessUpdated = true;
var width = Math.max(roughnessMap.image.width, normalMap.image.width);
var height = Math.max(roughnessMap.image.height, normalMap.image.height);
if (!MathUtils.isPowerOfTwo(width) || !MathUtils.isPowerOfTwo(height))
return;
var oldTarget = this._renderer.getRenderTarget();
var autoClear = this._renderer.autoClear;
this._renderer.autoClear = false;
if (_tempTarget === null || _tempTarget.width !== width || _tempTarget.height !== height) {
if (_tempTarget !== null)
_tempTarget.dispose();
_tempTarget = new WebGLRenderTarget(width, height, {
depthBuffer: false
});
_tempTarget.scissorTest = true;
}
if (width !== roughnessMap.image.width || height !== roughnessMap.image.height) {
var params = {
wrapS: roughnessMap.wrapS,
wrapT: roughnessMap.wrapT,
magFilter: roughnessMap.magFilter,
minFilter: roughnessMap.minFilter,
depthBuffer: false
};
var newRoughnessTarget = new WebGLRenderTarget(width, height, params);
newRoughnessTarget.texture.generateMipmaps = true;
this._renderer.setRenderTarget(newRoughnessTarget);
material.roughnessMap = newRoughnessTarget.texture;
if (material.metalnessMap == roughnessMap)
material.metalnessMap = material.roughnessMap;
if (material.aoMap == roughnessMap)
material.aoMap = material.roughnessMap;
}
_mipmapMaterial.uniforms.roughnessMap.value = roughnessMap;
_mipmapMaterial.uniforms.normalMap.value = normalMap;
var position = new Vector2(0, 0);
var texelSize = _mipmapMaterial.uniforms.texelSize.value;
for (let mip = 0; width >= 1 && height >= 1; ++mip, width /= 2, height /= 2) {
texelSize.set(1 / width, 1 / height);
if (mip == 0)
texelSize.set(0, 0);
_tempTarget.viewport.set(position.x, position.y, width, height);
_tempTarget.scissor.set(position.x, position.y, width, height);
this._renderer.setRenderTarget(_tempTarget);
this._renderer.render(_mesh, _flatCamera);
this._renderer.copyFramebufferToTexture(position, material.roughnessMap, mip);
_mipmapMaterial.uniforms.roughnessMap.value = material.roughnessMap;
}
if (roughnessMap !== material.roughnessMap)
roughnessMap.dispose();
this._renderer.setRenderTarget(oldTarget);
this._renderer.autoClear = autoClear;
});
__publicField(this, "dispose", function() {
_mipmapMaterial.dispose();
_mesh.geometry.dispose();
if (_tempTarget != null)
_tempTarget.dispose();
});
this._renderer = renderer;
this._renderer.compile(_mesh, _flatCamera);
}
}
function _getMipmapMaterial() {
var shaderMaterial = new RawShaderMaterial({
uniforms: {
roughnessMap: { value: null },
normalMap: { value: null },
texelSize: { value: new Vector2(1, 1) }
},
vertexShader: (
/* glsl */
`
precision mediump float;
precision mediump int;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4( position, 1.0 );
}
`
),
fragmentShader: (
/* glsl */
`
precision mediump float;
precision mediump int;
varying vec2 vUv;
uniform sampler2D roughnessMap;
uniform sampler2D normalMap;
uniform vec2 texelSize;
#define ENVMAP_TYPE_CUBE_UV
vec4 envMapTexelToLinear( vec4 a ) { return a; }
#include <cube_uv_reflection_fragment>
float roughnessToVariance( float roughness ) {
float variance = 0.0;
if ( roughness >= r1 ) {
variance = ( r0 - roughness ) * ( v1 - v0 ) / ( r0 - r1 ) + v0;
} else if ( roughness >= r4 ) {
variance = ( r1 - roughness ) * ( v4 - v1 ) / ( r1 - r4 ) + v1;
} else if ( roughness >= r5 ) {
variance = ( r4 - roughness ) * ( v5 - v4 ) / ( r4 - r5 ) + v4;
} else {
float roughness2 = roughness * roughness;
variance = 1.79 * roughness2 * roughness2;
}
return variance;
}
float varianceToRoughness( float variance ) {
float roughness = 0.0;
if ( variance >= v1 ) {
roughness = ( v0 - variance ) * ( r1 - r0 ) / ( v0 - v1 ) + r0;
} else if ( variance >= v4 ) {
roughness = ( v1 - variance ) * ( r4 - r1 ) / ( v1 - v4 ) + r1;
} else if ( variance >= v5 ) {
roughness = ( v4 - variance ) * ( r5 - r4 ) / ( v4 - v5 ) + r4;
} else {
roughness = pow( 0.559 * variance, 0.25 ); // 0.559 = 1.0 / 1.79
}
return roughness;
}
void main() {
gl_FragColor = texture2D( roughnessMap, vUv, - 1.0 );
if ( texelSize.x == 0.0 ) return;
float roughness = gl_FragColor.g;
float variance = roughnessToVariance( roughness );
vec3 avgNormal;
for ( float x = - 1.0; x < 2.0; x += 2.0 ) {
for ( float y = - 1.0; y < 2.0; y += 2.0 ) {
vec2 uv = vUv + vec2( x, y ) * 0.25 * texelSize;
avgNormal += normalize( texture2D( normalMap, uv, - 1.0 ).xyz - 0.5 );
}
}
variance += 1.0 - 0.25 * length( avgNormal );
gl_FragColor.g = varianceToRoughness( variance );
}
`
),
blending: NoBlending,
depthTest: false,
depthWrite: false
});
shaderMaterial.type = "RoughnessMipmapper";
return shaderMaterial;
}
export {
RoughnessMipmapper
};
//# sourceMappingURL=RoughnessMipmapper.js.map
File diff suppressed because one or more lines are too long
+37
View File
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const SceneUtils = {
createMeshesFromInstancedMesh: function(instancedMesh) {
const group = new THREE.Group();
const count = instancedMesh.count;
const geometry = instancedMesh.geometry;
const material = instancedMesh.material;
for (let i = 0; i < count; i++) {
const mesh = new THREE.Mesh(geometry, material);
instancedMesh.getMatrixAt(i, mesh.matrix);
mesh.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale);
group.add(mesh);
}
group.copy(instancedMesh);
group.updateMatrixWorld();
return group;
},
createMultiMaterialObject: function(geometry, materials) {
const group = new THREE.Group();
for (let i = 0, l = materials.length; i < l; i++) {
group.add(new THREE.Mesh(geometry, materials[i]));
}
return group;
},
detach: function(child, parent, scene) {
console.warn("THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.");
scene.attach(child);
},
attach: function(child, scene, parent) {
console.warn("THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.");
parent.attach(child);
}
};
exports.SceneUtils = SceneUtils;
//# sourceMappingURL=SceneUtils.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"SceneUtils.cjs","sources":["../../src/utils/SceneUtils.ts"],"sourcesContent":["import { Group, Mesh } from 'three'\nimport type { BufferGeometry, InstancedMesh, Material, Object3D, Scene } from 'three'\n\nconst SceneUtils = {\n createMeshesFromInstancedMesh: function (instancedMesh: InstancedMesh): Group {\n const group = new Group()\n\n const count = instancedMesh.count\n const geometry = instancedMesh.geometry\n const material = instancedMesh.material\n\n for (let i = 0; i < count; i++) {\n const mesh = new Mesh(geometry, material)\n\n instancedMesh.getMatrixAt(i, mesh.matrix)\n mesh.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale)\n\n group.add(mesh)\n }\n\n group.copy((instancedMesh as unknown) as Group)\n group.updateMatrixWorld() // ensure correct world matrices of meshes\n\n return group\n },\n\n createMultiMaterialObject: function (geometry: BufferGeometry, materials: Material[]): Group {\n const group = new Group()\n\n for (let i = 0, l = materials.length; i < l; i++) {\n group.add(new Mesh(geometry, materials[i]))\n }\n\n return group\n },\n\n detach: function (child: Object3D, parent: Object3D, scene: Scene): void {\n console.warn('THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.')\n\n scene.attach(child)\n },\n\n attach: function (child: Object3D, scene: Scene, parent: Object3D): void {\n console.warn('THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.')\n\n parent.attach(child)\n },\n}\n\nexport { SceneUtils }\n"],"names":["Group","Mesh"],"mappings":";;;AAGA,MAAM,aAAa;AAAA,EACjB,+BAA+B,SAAU,eAAqC;AACtE,UAAA,QAAQ,IAAIA,MAAAA;AAElB,UAAM,QAAQ,cAAc;AAC5B,UAAM,WAAW,cAAc;AAC/B,UAAM,WAAW,cAAc;AAE/B,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAM,OAAO,IAAIC,MAAAA,KAAK,UAAU,QAAQ;AAE1B,oBAAA,YAAY,GAAG,KAAK,MAAM;AACxC,WAAK,OAAO,UAAU,KAAK,UAAU,KAAK,YAAY,KAAK,KAAK;AAEhE,YAAM,IAAI,IAAI;AAAA,IAChB;AAEA,UAAM,KAAM,aAAkC;AAC9C,UAAM,kBAAkB;AAEjB,WAAA;AAAA,EACT;AAAA,EAEA,2BAA2B,SAAU,UAA0B,WAA8B;AACrF,UAAA,QAAQ,IAAID,MAAAA;AAElB,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,KAAK;AAChD,YAAM,IAAI,IAAIC,MAAA,KAAK,UAAU,UAAU,CAAC,CAAC,CAAC;AAAA,IAC5C;AAEO,WAAA;AAAA,EACT;AAAA,EAEA,QAAQ,SAAU,OAAiB,QAAkB,OAAoB;AACvE,YAAQ,KAAK,oFAAoF;AAEjG,UAAM,OAAO,KAAK;AAAA,EACpB;AAAA,EAEA,QAAQ,SAAU,OAAiB,OAAc,QAAwB;AACvE,YAAQ,KAAK,qFAAqF;AAElG,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;;"}
+9
View File
@@ -0,0 +1,9 @@
import { Group } from 'three';
import type { BufferGeometry, InstancedMesh, Material, Object3D, Scene } from 'three';
declare const SceneUtils: {
createMeshesFromInstancedMesh: (instancedMesh: InstancedMesh) => Group;
createMultiMaterialObject: (geometry: BufferGeometry, materials: Material[]) => Group;
detach: (child: Object3D, parent: Object3D, scene: Scene) => void;
attach: (child: Object3D, scene: Scene, parent: Object3D) => void;
};
export { SceneUtils };
+37
View File
@@ -0,0 +1,37 @@
import { Group, Mesh } from "three";
const SceneUtils = {
createMeshesFromInstancedMesh: function(instancedMesh) {
const group = new Group();
const count = instancedMesh.count;
const geometry = instancedMesh.geometry;
const material = instancedMesh.material;
for (let i = 0; i < count; i++) {
const mesh = new Mesh(geometry, material);
instancedMesh.getMatrixAt(i, mesh.matrix);
mesh.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale);
group.add(mesh);
}
group.copy(instancedMesh);
group.updateMatrixWorld();
return group;
},
createMultiMaterialObject: function(geometry, materials) {
const group = new Group();
for (let i = 0, l = materials.length; i < l; i++) {
group.add(new Mesh(geometry, materials[i]));
}
return group;
},
detach: function(child, parent, scene) {
console.warn("THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.");
scene.attach(child);
},
attach: function(child, scene, parent) {
console.warn("THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.");
parent.attach(child);
}
};
export {
SceneUtils
};
//# sourceMappingURL=SceneUtils.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"SceneUtils.js","sources":["../../src/utils/SceneUtils.ts"],"sourcesContent":["import { Group, Mesh } from 'three'\nimport type { BufferGeometry, InstancedMesh, Material, Object3D, Scene } from 'three'\n\nconst SceneUtils = {\n createMeshesFromInstancedMesh: function (instancedMesh: InstancedMesh): Group {\n const group = new Group()\n\n const count = instancedMesh.count\n const geometry = instancedMesh.geometry\n const material = instancedMesh.material\n\n for (let i = 0; i < count; i++) {\n const mesh = new Mesh(geometry, material)\n\n instancedMesh.getMatrixAt(i, mesh.matrix)\n mesh.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale)\n\n group.add(mesh)\n }\n\n group.copy((instancedMesh as unknown) as Group)\n group.updateMatrixWorld() // ensure correct world matrices of meshes\n\n return group\n },\n\n createMultiMaterialObject: function (geometry: BufferGeometry, materials: Material[]): Group {\n const group = new Group()\n\n for (let i = 0, l = materials.length; i < l; i++) {\n group.add(new Mesh(geometry, materials[i]))\n }\n\n return group\n },\n\n detach: function (child: Object3D, parent: Object3D, scene: Scene): void {\n console.warn('THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.')\n\n scene.attach(child)\n },\n\n attach: function (child: Object3D, scene: Scene, parent: Object3D): void {\n console.warn('THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.')\n\n parent.attach(child)\n },\n}\n\nexport { SceneUtils }\n"],"names":[],"mappings":";AAGA,MAAM,aAAa;AAAA,EACjB,+BAA+B,SAAU,eAAqC;AACtE,UAAA,QAAQ,IAAI;AAElB,UAAM,QAAQ,cAAc;AAC5B,UAAM,WAAW,cAAc;AAC/B,UAAM,WAAW,cAAc;AAE/B,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAM,OAAO,IAAI,KAAK,UAAU,QAAQ;AAE1B,oBAAA,YAAY,GAAG,KAAK,MAAM;AACxC,WAAK,OAAO,UAAU,KAAK,UAAU,KAAK,YAAY,KAAK,KAAK;AAEhE,YAAM,IAAI,IAAI;AAAA,IAChB;AAEA,UAAM,KAAM,aAAkC;AAC9C,UAAM,kBAAkB;AAEjB,WAAA;AAAA,EACT;AAAA,EAEA,2BAA2B,SAAU,UAA0B,WAA8B;AACrF,UAAA,QAAQ,IAAI;AAElB,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,KAAK;AAChD,YAAM,IAAI,IAAI,KAAK,UAAU,UAAU,CAAC,CAAC,CAAC;AAAA,IAC5C;AAEO,WAAA;AAAA,EACT;AAAA,EAEA,QAAQ,SAAU,OAAiB,QAAkB,OAAoB;AACvE,YAAQ,KAAK,oFAAoF;AAEjG,UAAM,OAAO,KAAK;AAAA,EACpB;AAAA,EAEA,QAAQ,SAAU,OAAiB,OAAc,QAAwB;AACvE,YAAQ,KAAK,qFAAqF;AAElG,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;"}
+112
View File
@@ -0,0 +1,112 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const UnpackDepthRGBAShader = require("../shaders/UnpackDepthRGBAShader.cjs");
class ShadowMapViewer {
constructor(light) {
const scope = this;
const doRenderLabel = light.name !== void 0 && light.name !== "";
let userAutoClearSetting;
const frame = {
x: 10,
y: 10,
width: 256,
height: 256
};
const camera = new THREE.OrthographicCamera(
window.innerWidth / -2,
window.innerWidth / 2,
window.innerHeight / 2,
window.innerHeight / -2,
1,
10
);
camera.position.set(0, 0, 2);
const scene = new THREE.Scene();
const shader = UnpackDepthRGBAShader.UnpackDepthRGBAShader;
const uniforms = THREE.UniformsUtils.clone(shader.uniforms);
const material = new THREE.ShaderMaterial({
uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
});
const plane = new THREE.PlaneGeometry(frame.width, frame.height);
const mesh = new THREE.Mesh(plane, material);
scene.add(mesh);
let labelCanvas, labelMesh;
if (doRenderLabel) {
labelCanvas = document.createElement("canvas");
const context = labelCanvas.getContext("2d");
context.font = "Bold 20px Arial";
const labelWidth = context.measureText(light.name).width;
labelCanvas.width = labelWidth;
labelCanvas.height = 25;
context.font = "Bold 20px Arial";
context.fillStyle = "rgba( 255, 0, 0, 1 )";
context.fillText(light.name, 0, 20);
const labelTexture = new THREE.Texture(labelCanvas);
labelTexture.magFilter = THREE.LinearFilter;
labelTexture.minFilter = THREE.LinearFilter;
labelTexture.needsUpdate = true;
const labelMaterial = new THREE.MeshBasicMaterial({ map: labelTexture, side: THREE.DoubleSide });
labelMaterial.transparent = true;
const labelPlane = new THREE.PlaneGeometry(labelCanvas.width, labelCanvas.height);
labelMesh = new THREE.Mesh(labelPlane, labelMaterial);
scene.add(labelMesh);
}
function resetPosition() {
scope.position.set(scope.position.x, scope.position.y);
}
this.enabled = true;
this.size = {
width: frame.width,
height: frame.height,
set: function(width, height) {
this.width = width;
this.height = height;
mesh.scale.set(this.width / frame.width, this.height / frame.height, 1);
resetPosition();
}
};
this.position = {
x: frame.x,
y: frame.y,
set: function(x, y) {
this.x = x;
this.y = y;
const width = scope.size.width;
const height = scope.size.height;
mesh.position.set(-window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0);
if (doRenderLabel)
labelMesh.position.set(mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0);
}
};
this.render = function(renderer) {
if (this.enabled) {
uniforms.tDiffuse.value = light.shadow.map.texture;
userAutoClearSetting = renderer.autoClear;
renderer.autoClear = false;
renderer.clearDepth();
renderer.render(scene, camera);
renderer.autoClear = userAutoClearSetting;
}
};
this.updateForWindowResize = function() {
if (this.enabled) {
camera.left = window.innerWidth / -2;
camera.right = window.innerWidth / 2;
camera.top = window.innerHeight / 2;
camera.bottom = window.innerHeight / -2;
camera.updateProjectionMatrix();
this.update();
}
};
this.update = function() {
this.position.set(this.position.x, this.position.y);
this.size.set(this.size.width, this.size.height);
};
this.update();
}
}
exports.ShadowMapViewer = ShadowMapViewer;
//# sourceMappingURL=ShadowMapViewer.cjs.map
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
import { Light, WebGLRenderer } from 'three'
export interface Size {
width: number
height: number
set: (width: number, height: number) => void
}
export interface Position {
x: number
y: number
set: (x: number, y: number) => void
}
export class ShadowMapViewer {
constructor(light: Light)
enabled: boolean
size: Size
position: Position
render(renderer: WebGLRenderer): void
updateForWindowResize(): void
update(): void
}
+112
View File
@@ -0,0 +1,112 @@
import { OrthographicCamera, Scene, UniformsUtils, ShaderMaterial, PlaneGeometry, Mesh, Texture, LinearFilter, MeshBasicMaterial, DoubleSide } from "three";
import { UnpackDepthRGBAShader } from "../shaders/UnpackDepthRGBAShader.js";
class ShadowMapViewer {
constructor(light) {
const scope = this;
const doRenderLabel = light.name !== void 0 && light.name !== "";
let userAutoClearSetting;
const frame = {
x: 10,
y: 10,
width: 256,
height: 256
};
const camera = new OrthographicCamera(
window.innerWidth / -2,
window.innerWidth / 2,
window.innerHeight / 2,
window.innerHeight / -2,
1,
10
);
camera.position.set(0, 0, 2);
const scene = new Scene();
const shader = UnpackDepthRGBAShader;
const uniforms = UniformsUtils.clone(shader.uniforms);
const material = new ShaderMaterial({
uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
});
const plane = new PlaneGeometry(frame.width, frame.height);
const mesh = new Mesh(plane, material);
scene.add(mesh);
let labelCanvas, labelMesh;
if (doRenderLabel) {
labelCanvas = document.createElement("canvas");
const context = labelCanvas.getContext("2d");
context.font = "Bold 20px Arial";
const labelWidth = context.measureText(light.name).width;
labelCanvas.width = labelWidth;
labelCanvas.height = 25;
context.font = "Bold 20px Arial";
context.fillStyle = "rgba( 255, 0, 0, 1 )";
context.fillText(light.name, 0, 20);
const labelTexture = new Texture(labelCanvas);
labelTexture.magFilter = LinearFilter;
labelTexture.minFilter = LinearFilter;
labelTexture.needsUpdate = true;
const labelMaterial = new MeshBasicMaterial({ map: labelTexture, side: DoubleSide });
labelMaterial.transparent = true;
const labelPlane = new PlaneGeometry(labelCanvas.width, labelCanvas.height);
labelMesh = new Mesh(labelPlane, labelMaterial);
scene.add(labelMesh);
}
function resetPosition() {
scope.position.set(scope.position.x, scope.position.y);
}
this.enabled = true;
this.size = {
width: frame.width,
height: frame.height,
set: function(width, height) {
this.width = width;
this.height = height;
mesh.scale.set(this.width / frame.width, this.height / frame.height, 1);
resetPosition();
}
};
this.position = {
x: frame.x,
y: frame.y,
set: function(x, y) {
this.x = x;
this.y = y;
const width = scope.size.width;
const height = scope.size.height;
mesh.position.set(-window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0);
if (doRenderLabel)
labelMesh.position.set(mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0);
}
};
this.render = function(renderer) {
if (this.enabled) {
uniforms.tDiffuse.value = light.shadow.map.texture;
userAutoClearSetting = renderer.autoClear;
renderer.autoClear = false;
renderer.clearDepth();
renderer.render(scene, camera);
renderer.autoClear = userAutoClearSetting;
}
};
this.updateForWindowResize = function() {
if (this.enabled) {
camera.left = window.innerWidth / -2;
camera.right = window.innerWidth / 2;
camera.top = window.innerHeight / 2;
camera.bottom = window.innerHeight / -2;
camera.updateProjectionMatrix();
this.update();
}
};
this.update = function() {
this.position.set(this.position.x, this.position.y);
this.size.set(this.size.width, this.size.height);
};
this.update();
}
}
export {
ShadowMapViewer
};
//# sourceMappingURL=ShadowMapViewer.js.map
File diff suppressed because one or more lines are too long
+212
View File
@@ -0,0 +1,212 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
function retarget(target, source, options = {}) {
const pos = new THREE.Vector3(), quat = new THREE.Quaternion(), scale = new THREE.Vector3(), bindBoneMatrix = new THREE.Matrix4(), relativeMatrix = new THREE.Matrix4(), globalMatrix = new THREE.Matrix4();
options.preserveMatrix = options.preserveMatrix !== void 0 ? options.preserveMatrix : true;
options.preservePosition = options.preservePosition !== void 0 ? options.preservePosition : true;
options.preserveHipPosition = options.preserveHipPosition !== void 0 ? options.preserveHipPosition : false;
options.useTargetMatrix = options.useTargetMatrix !== void 0 ? options.useTargetMatrix : false;
options.hip = options.hip !== void 0 ? options.hip : "hip";
options.names = options.names || {};
const sourceBones = source.isObject3D ? source.skeleton.bones : getBones(source), bones = target.isObject3D ? target.skeleton.bones : getBones(target);
let bindBones, bone, name, boneTo, bonesPosition;
if (target.isObject3D) {
target.skeleton.pose();
} else {
options.useTargetMatrix = true;
options.preserveMatrix = false;
}
if (options.preservePosition) {
bonesPosition = [];
for (let i = 0; i < bones.length; i++) {
bonesPosition.push(bones[i].position.clone());
}
}
if (options.preserveMatrix) {
target.updateMatrixWorld();
target.matrixWorld.identity();
for (let i = 0; i < target.children.length; ++i) {
target.children[i].updateMatrixWorld(true);
}
}
if (options.offsets) {
bindBones = [];
for (let i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
if (options.offsets[name]) {
bone.matrix.multiply(options.offsets[name]);
bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
bone.updateMatrixWorld();
}
bindBones.push(bone.matrixWorld.clone());
}
}
for (let i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
boneTo = getBoneByName(name, sourceBones);
globalMatrix.copy(bone.matrixWorld);
if (boneTo) {
boneTo.updateMatrixWorld();
if (options.useTargetMatrix) {
relativeMatrix.copy(boneTo.matrixWorld);
} else {
relativeMatrix.copy(target.matrixWorld).invert();
relativeMatrix.multiply(boneTo.matrixWorld);
}
scale.setFromMatrixScale(relativeMatrix);
relativeMatrix.scale(scale.set(1 / scale.x, 1 / scale.y, 1 / scale.z));
globalMatrix.makeRotationFromQuaternion(quat.setFromRotationMatrix(relativeMatrix));
if (target.isObject3D) {
const boneIndex = bones.indexOf(bone), wBindMatrix = bindBones ? bindBones[boneIndex] : bindBoneMatrix.copy(target.skeleton.boneInverses[boneIndex]).invert();
globalMatrix.multiply(wBindMatrix);
}
globalMatrix.copyPosition(relativeMatrix);
}
if (bone.parent && bone.parent.isBone) {
bone.matrix.copy(bone.parent.matrixWorld).invert();
bone.matrix.multiply(globalMatrix);
} else {
bone.matrix.copy(globalMatrix);
}
if (options.preserveHipPosition && name === options.hip) {
bone.matrix.setPosition(pos.set(0, bone.position.y, 0));
}
bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
bone.updateMatrixWorld();
}
if (options.preservePosition) {
for (let i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
if (name !== options.hip) {
bone.position.copy(bonesPosition[i]);
}
}
}
if (options.preserveMatrix) {
target.updateMatrixWorld(true);
}
}
function retargetClip(target, source, clip, options = {}) {
options.useFirstFramePosition = options.useFirstFramePosition !== void 0 ? options.useFirstFramePosition : false;
options.fps = options.fps !== void 0 ? options.fps : 30;
options.names = options.names || [];
if (!source.isObject3D) {
source = getHelperFromSkeleton(source);
}
const numFrames = Math.round(clip.duration * (options.fps / 1e3) * 1e3), delta = 1 / options.fps, convertedTracks = [], mixer = new THREE.AnimationMixer(source), bones = getBones(target.skeleton), boneDatas = [];
let positionOffset, bone, boneTo, boneData, name;
mixer.clipAction(clip).play();
mixer.update(0);
source.updateMatrixWorld();
for (let i = 0; i < numFrames; ++i) {
const time = i * delta;
retarget(target, source, options);
for (let j = 0; j < bones.length; ++j) {
name = options.names[bones[j].name] || bones[j].name;
boneTo = getBoneByName(name, source.skeleton);
if (boneTo) {
bone = bones[j];
boneData = boneDatas[j] = boneDatas[j] || { bone };
if (options.hip === name) {
if (!boneData.pos) {
boneData.pos = {
times: new Float32Array(numFrames),
values: new Float32Array(numFrames * 3)
};
}
if (options.useFirstFramePosition) {
if (i === 0) {
positionOffset = bone.position.clone();
}
bone.position.sub(positionOffset);
}
boneData.pos.times[i] = time;
bone.position.toArray(boneData.pos.values, i * 3);
}
if (!boneData.quat) {
boneData.quat = {
times: new Float32Array(numFrames),
values: new Float32Array(numFrames * 4)
};
}
boneData.quat.times[i] = time;
bone.quaternion.toArray(boneData.quat.values, i * 4);
}
}
mixer.update(delta);
source.updateMatrixWorld();
}
for (let i = 0; i < boneDatas.length; ++i) {
boneData = boneDatas[i];
if (boneData) {
if (boneData.pos) {
convertedTracks.push(
new THREE.VectorKeyframeTrack(
".bones[" + boneData.bone.name + "].position",
boneData.pos.times,
boneData.pos.values
)
);
}
convertedTracks.push(
new THREE.QuaternionKeyframeTrack(
".bones[" + boneData.bone.name + "].quaternion",
boneData.quat.times,
boneData.quat.values
)
);
}
}
mixer.uncacheAction(clip);
return new THREE.AnimationClip(clip.name, -1, convertedTracks);
}
function clone(source) {
const sourceLookup = /* @__PURE__ */ new Map();
const cloneLookup = /* @__PURE__ */ new Map();
const clone2 = source.clone();
parallelTraverse(source, clone2, function(sourceNode, clonedNode) {
sourceLookup.set(clonedNode, sourceNode);
cloneLookup.set(sourceNode, clonedNode);
});
clone2.traverse(function(node) {
if (!node.isSkinnedMesh)
return;
const clonedMesh = node;
const sourceMesh = sourceLookup.get(node);
const sourceBones = sourceMesh.skeleton.bones;
clonedMesh.skeleton = sourceMesh.skeleton.clone();
clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix);
clonedMesh.skeleton.bones = sourceBones.map(function(bone) {
return cloneLookup.get(bone);
});
clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix);
});
return clone2;
}
function getBoneByName(name, skeleton) {
for (let i = 0, bones = getBones(skeleton); i < bones.length; i++) {
if (name === bones[i].name)
return bones[i];
}
}
function getBones(skeleton) {
return Array.isArray(skeleton) ? skeleton : skeleton.bones;
}
function getHelperFromSkeleton(skeleton) {
const source = new THREE.SkeletonHelper(skeleton.bones[0]);
source.skeleton = skeleton;
return source;
}
function parallelTraverse(a, b, callback) {
callback(a, b);
for (let i = 0; i < a.children.length; i++) {
parallelTraverse(a.children[i], b.children[i], callback);
}
}
const SkeletonUtils = { retarget, retargetClip, clone };
exports.SkeletonUtils = SkeletonUtils;
//# sourceMappingURL=SkeletonUtils.cjs.map
File diff suppressed because one or more lines are too long
+14
View File
@@ -0,0 +1,14 @@
import { AnimationClip, Object3D, Skeleton } from 'three'
export namespace SkeletonUtils {
export function clone(source: Object3D): Object3D
export function retarget(target: Object3D | Skeleton, source: Object3D | Skeleton, options: {}): void
export function retargetClip(
target: Skeleton | Object3D,
source: Skeleton | Object3D,
clip: AnimationClip,
options: {},
): AnimationClip
}
+212
View File
@@ -0,0 +1,212 @@
import { Vector3, Quaternion, Matrix4, AnimationMixer, VectorKeyframeTrack, QuaternionKeyframeTrack, AnimationClip, SkeletonHelper } from "three";
function retarget(target, source, options = {}) {
const pos = new Vector3(), quat = new Quaternion(), scale = new Vector3(), bindBoneMatrix = new Matrix4(), relativeMatrix = new Matrix4(), globalMatrix = new Matrix4();
options.preserveMatrix = options.preserveMatrix !== void 0 ? options.preserveMatrix : true;
options.preservePosition = options.preservePosition !== void 0 ? options.preservePosition : true;
options.preserveHipPosition = options.preserveHipPosition !== void 0 ? options.preserveHipPosition : false;
options.useTargetMatrix = options.useTargetMatrix !== void 0 ? options.useTargetMatrix : false;
options.hip = options.hip !== void 0 ? options.hip : "hip";
options.names = options.names || {};
const sourceBones = source.isObject3D ? source.skeleton.bones : getBones(source), bones = target.isObject3D ? target.skeleton.bones : getBones(target);
let bindBones, bone, name, boneTo, bonesPosition;
if (target.isObject3D) {
target.skeleton.pose();
} else {
options.useTargetMatrix = true;
options.preserveMatrix = false;
}
if (options.preservePosition) {
bonesPosition = [];
for (let i = 0; i < bones.length; i++) {
bonesPosition.push(bones[i].position.clone());
}
}
if (options.preserveMatrix) {
target.updateMatrixWorld();
target.matrixWorld.identity();
for (let i = 0; i < target.children.length; ++i) {
target.children[i].updateMatrixWorld(true);
}
}
if (options.offsets) {
bindBones = [];
for (let i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
if (options.offsets[name]) {
bone.matrix.multiply(options.offsets[name]);
bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
bone.updateMatrixWorld();
}
bindBones.push(bone.matrixWorld.clone());
}
}
for (let i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
boneTo = getBoneByName(name, sourceBones);
globalMatrix.copy(bone.matrixWorld);
if (boneTo) {
boneTo.updateMatrixWorld();
if (options.useTargetMatrix) {
relativeMatrix.copy(boneTo.matrixWorld);
} else {
relativeMatrix.copy(target.matrixWorld).invert();
relativeMatrix.multiply(boneTo.matrixWorld);
}
scale.setFromMatrixScale(relativeMatrix);
relativeMatrix.scale(scale.set(1 / scale.x, 1 / scale.y, 1 / scale.z));
globalMatrix.makeRotationFromQuaternion(quat.setFromRotationMatrix(relativeMatrix));
if (target.isObject3D) {
const boneIndex = bones.indexOf(bone), wBindMatrix = bindBones ? bindBones[boneIndex] : bindBoneMatrix.copy(target.skeleton.boneInverses[boneIndex]).invert();
globalMatrix.multiply(wBindMatrix);
}
globalMatrix.copyPosition(relativeMatrix);
}
if (bone.parent && bone.parent.isBone) {
bone.matrix.copy(bone.parent.matrixWorld).invert();
bone.matrix.multiply(globalMatrix);
} else {
bone.matrix.copy(globalMatrix);
}
if (options.preserveHipPosition && name === options.hip) {
bone.matrix.setPosition(pos.set(0, bone.position.y, 0));
}
bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
bone.updateMatrixWorld();
}
if (options.preservePosition) {
for (let i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
if (name !== options.hip) {
bone.position.copy(bonesPosition[i]);
}
}
}
if (options.preserveMatrix) {
target.updateMatrixWorld(true);
}
}
function retargetClip(target, source, clip, options = {}) {
options.useFirstFramePosition = options.useFirstFramePosition !== void 0 ? options.useFirstFramePosition : false;
options.fps = options.fps !== void 0 ? options.fps : 30;
options.names = options.names || [];
if (!source.isObject3D) {
source = getHelperFromSkeleton(source);
}
const numFrames = Math.round(clip.duration * (options.fps / 1e3) * 1e3), delta = 1 / options.fps, convertedTracks = [], mixer = new AnimationMixer(source), bones = getBones(target.skeleton), boneDatas = [];
let positionOffset, bone, boneTo, boneData, name;
mixer.clipAction(clip).play();
mixer.update(0);
source.updateMatrixWorld();
for (let i = 0; i < numFrames; ++i) {
const time = i * delta;
retarget(target, source, options);
for (let j = 0; j < bones.length; ++j) {
name = options.names[bones[j].name] || bones[j].name;
boneTo = getBoneByName(name, source.skeleton);
if (boneTo) {
bone = bones[j];
boneData = boneDatas[j] = boneDatas[j] || { bone };
if (options.hip === name) {
if (!boneData.pos) {
boneData.pos = {
times: new Float32Array(numFrames),
values: new Float32Array(numFrames * 3)
};
}
if (options.useFirstFramePosition) {
if (i === 0) {
positionOffset = bone.position.clone();
}
bone.position.sub(positionOffset);
}
boneData.pos.times[i] = time;
bone.position.toArray(boneData.pos.values, i * 3);
}
if (!boneData.quat) {
boneData.quat = {
times: new Float32Array(numFrames),
values: new Float32Array(numFrames * 4)
};
}
boneData.quat.times[i] = time;
bone.quaternion.toArray(boneData.quat.values, i * 4);
}
}
mixer.update(delta);
source.updateMatrixWorld();
}
for (let i = 0; i < boneDatas.length; ++i) {
boneData = boneDatas[i];
if (boneData) {
if (boneData.pos) {
convertedTracks.push(
new VectorKeyframeTrack(
".bones[" + boneData.bone.name + "].position",
boneData.pos.times,
boneData.pos.values
)
);
}
convertedTracks.push(
new QuaternionKeyframeTrack(
".bones[" + boneData.bone.name + "].quaternion",
boneData.quat.times,
boneData.quat.values
)
);
}
}
mixer.uncacheAction(clip);
return new AnimationClip(clip.name, -1, convertedTracks);
}
function clone(source) {
const sourceLookup = /* @__PURE__ */ new Map();
const cloneLookup = /* @__PURE__ */ new Map();
const clone2 = source.clone();
parallelTraverse(source, clone2, function(sourceNode, clonedNode) {
sourceLookup.set(clonedNode, sourceNode);
cloneLookup.set(sourceNode, clonedNode);
});
clone2.traverse(function(node) {
if (!node.isSkinnedMesh)
return;
const clonedMesh = node;
const sourceMesh = sourceLookup.get(node);
const sourceBones = sourceMesh.skeleton.bones;
clonedMesh.skeleton = sourceMesh.skeleton.clone();
clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix);
clonedMesh.skeleton.bones = sourceBones.map(function(bone) {
return cloneLookup.get(bone);
});
clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix);
});
return clone2;
}
function getBoneByName(name, skeleton) {
for (let i = 0, bones = getBones(skeleton); i < bones.length; i++) {
if (name === bones[i].name)
return bones[i];
}
}
function getBones(skeleton) {
return Array.isArray(skeleton) ? skeleton : skeleton.bones;
}
function getHelperFromSkeleton(skeleton) {
const source = new SkeletonHelper(skeleton.bones[0]);
source.skeleton = skeleton;
return source;
}
function parallelTraverse(a, b, callback) {
callback(a, b);
for (let i = 0; i < a.children.length; i++) {
parallelTraverse(a.children[i], b.children[i], callback);
}
}
const SkeletonUtils = { retarget, retargetClip, clone };
export {
SkeletonUtils
};
//# sourceMappingURL=SkeletonUtils.js.map
File diff suppressed because one or more lines are too long
+81
View File
@@ -0,0 +1,81 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
function UVsDebug(geometry, size = 1024) {
const abc = "abc";
const a = new THREE.Vector2();
const b = new THREE.Vector2();
const uvs = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()];
const face = [];
const canvas = document.createElement("canvas");
const width = size;
const height = size;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
ctx.lineWidth = 1;
ctx.strokeStyle = "rgb( 63, 63, 63 )";
ctx.textAlign = "center";
ctx.fillStyle = "rgb( 255, 255, 255 )";
ctx.fillRect(0, 0, width, height);
const index = geometry.index;
const uvAttribute = geometry.attributes.uv;
if (index) {
for (let i = 0, il = index.count; i < il; i += 3) {
face[0] = index.getX(i);
face[1] = index.getX(i + 1);
face[2] = index.getX(i + 2);
uvs[0].fromBufferAttribute(uvAttribute, face[0]);
uvs[1].fromBufferAttribute(uvAttribute, face[1]);
uvs[2].fromBufferAttribute(uvAttribute, face[2]);
processFace(face, uvs, i / 3);
}
} else {
for (let i = 0, il = uvAttribute.count; i < il; i += 3) {
face[0] = i;
face[1] = i + 1;
face[2] = i + 2;
uvs[0].fromBufferAttribute(uvAttribute, face[0]);
uvs[1].fromBufferAttribute(uvAttribute, face[1]);
uvs[2].fromBufferAttribute(uvAttribute, face[2]);
processFace(face, uvs, i / 3);
}
}
return canvas;
function processFace(face2, uvs2, index2) {
ctx.beginPath();
a.set(0, 0);
for (let j = 0, jl = uvs2.length; j < jl; j++) {
const uv = uvs2[j];
a.x += uv.x;
a.y += uv.y;
if (j === 0) {
ctx.moveTo(uv.x * (width - 2) + 0.5, (1 - uv.y) * (height - 2) + 0.5);
} else {
ctx.lineTo(uv.x * (width - 2) + 0.5, (1 - uv.y) * (height - 2) + 0.5);
}
}
ctx.closePath();
ctx.stroke();
a.divideScalar(uvs2.length);
ctx.font = "18px Arial";
ctx.fillStyle = "rgb( 63, 63, 63 )";
ctx.fillText(index2, a.x * width, (1 - a.y) * height);
if (a.x > 0.95) {
ctx.fillText(index2, a.x % 1 * width, (1 - a.y) * height);
}
ctx.font = "12px Arial";
ctx.fillStyle = "rgb( 191, 191, 191 )";
for (let j = 0, jl = uvs2.length; j < jl; j++) {
const uv = uvs2[j];
b.addVectors(a, uv).divideScalar(2);
const vnum = face2[j];
ctx.fillText(abc[j] + vnum, b.x * width, (1 - b.y) * height);
if (b.x > 0.95) {
ctx.fillText(abc[j] + vnum, b.x % 1 * width, (1 - b.y) * height);
}
}
}
}
exports.UVsDebug = UVsDebug;
//# sourceMappingURL=UVsDebug.cjs.map
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
import { BufferGeometry } from 'three'
export function UVsDebug(geometry: BufferGeometry, size: number): HTMLCanvasElement
+81
View File
@@ -0,0 +1,81 @@
import { Vector2 } from "three";
function UVsDebug(geometry, size = 1024) {
const abc = "abc";
const a = new Vector2();
const b = new Vector2();
const uvs = [new Vector2(), new Vector2(), new Vector2()];
const face = [];
const canvas = document.createElement("canvas");
const width = size;
const height = size;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
ctx.lineWidth = 1;
ctx.strokeStyle = "rgb( 63, 63, 63 )";
ctx.textAlign = "center";
ctx.fillStyle = "rgb( 255, 255, 255 )";
ctx.fillRect(0, 0, width, height);
const index = geometry.index;
const uvAttribute = geometry.attributes.uv;
if (index) {
for (let i = 0, il = index.count; i < il; i += 3) {
face[0] = index.getX(i);
face[1] = index.getX(i + 1);
face[2] = index.getX(i + 2);
uvs[0].fromBufferAttribute(uvAttribute, face[0]);
uvs[1].fromBufferAttribute(uvAttribute, face[1]);
uvs[2].fromBufferAttribute(uvAttribute, face[2]);
processFace(face, uvs, i / 3);
}
} else {
for (let i = 0, il = uvAttribute.count; i < il; i += 3) {
face[0] = i;
face[1] = i + 1;
face[2] = i + 2;
uvs[0].fromBufferAttribute(uvAttribute, face[0]);
uvs[1].fromBufferAttribute(uvAttribute, face[1]);
uvs[2].fromBufferAttribute(uvAttribute, face[2]);
processFace(face, uvs, i / 3);
}
}
return canvas;
function processFace(face2, uvs2, index2) {
ctx.beginPath();
a.set(0, 0);
for (let j = 0, jl = uvs2.length; j < jl; j++) {
const uv = uvs2[j];
a.x += uv.x;
a.y += uv.y;
if (j === 0) {
ctx.moveTo(uv.x * (width - 2) + 0.5, (1 - uv.y) * (height - 2) + 0.5);
} else {
ctx.lineTo(uv.x * (width - 2) + 0.5, (1 - uv.y) * (height - 2) + 0.5);
}
}
ctx.closePath();
ctx.stroke();
a.divideScalar(uvs2.length);
ctx.font = "18px Arial";
ctx.fillStyle = "rgb( 63, 63, 63 )";
ctx.fillText(index2, a.x * width, (1 - a.y) * height);
if (a.x > 0.95) {
ctx.fillText(index2, a.x % 1 * width, (1 - a.y) * height);
}
ctx.font = "12px Arial";
ctx.fillStyle = "rgb( 191, 191, 191 )";
for (let j = 0, jl = uvs2.length; j < jl; j++) {
const uv = uvs2[j];
b.addVectors(a, uv).divideScalar(2);
const vnum = face2[j];
ctx.fillText(abc[j] + vnum, b.x * width, (1 - b.y) * height);
if (b.x > 0.95) {
ctx.fillText(abc[j] + vnum, b.x % 1 * width, (1 - b.y) * height);
}
}
}
}
export {
UVsDebug
};
//# sourceMappingURL=UVsDebug.js.map
File diff suppressed because one or more lines are too long
+63
View File
@@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
class WorkerPool {
constructor(pool = 4) {
this.pool = pool;
this.queue = [];
this.workers = [];
this.workersResolve = [];
this.workerStatus = 0;
}
_initWorker(workerId) {
if (!this.workers[workerId]) {
const worker = this.workerCreator();
worker.addEventListener("message", this._onMessage.bind(this, workerId));
this.workers[workerId] = worker;
}
}
_getIdleWorker() {
for (let i = 0; i < this.pool; i++)
if (!(this.workerStatus & 1 << i))
return i;
return -1;
}
_onMessage(workerId, msg) {
const resolve = this.workersResolve[workerId];
resolve && resolve(msg);
if (this.queue.length) {
const { resolve: resolve2, msg: msg2, transfer } = this.queue.shift();
this.workersResolve[workerId] = resolve2;
this.workers[workerId].postMessage(msg2, transfer);
} else {
this.workerStatus ^= 1 << workerId;
}
}
setWorkerCreator(workerCreator) {
this.workerCreator = workerCreator;
}
setWorkerLimit(pool) {
this.pool = pool;
}
postMessage(msg, transfer) {
return new Promise((resolve) => {
const workerId = this._getIdleWorker();
if (workerId !== -1) {
this._initWorker(workerId);
this.workerStatus |= 1 << workerId;
this.workersResolve[workerId] = resolve;
this.workers[workerId].postMessage(msg, transfer);
} else {
this.queue.push({ resolve, msg, transfer });
}
});
}
dispose() {
this.workers.forEach((worker) => worker.terminate());
this.workersResolve.length = 0;
this.workers.length = 0;
this.queue.length = 0;
this.workerStatus = 0;
}
}
exports.WorkerPool = WorkerPool;
//# sourceMappingURL=WorkerPool.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"WorkerPool.cjs","sources":["../../src/utils/WorkerPool.js"],"sourcesContent":["/**\n * @author Deepkolos / https://github.com/deepkolos\n */\n\nexport class WorkerPool {\n constructor(pool = 4) {\n this.pool = pool\n this.queue = []\n this.workers = []\n this.workersResolve = []\n this.workerStatus = 0\n }\n\n _initWorker(workerId) {\n if (!this.workers[workerId]) {\n const worker = this.workerCreator()\n worker.addEventListener('message', this._onMessage.bind(this, workerId))\n this.workers[workerId] = worker\n }\n }\n\n _getIdleWorker() {\n for (let i = 0; i < this.pool; i++) if (!(this.workerStatus & (1 << i))) return i\n\n return -1\n }\n\n _onMessage(workerId, msg) {\n const resolve = this.workersResolve[workerId]\n resolve && resolve(msg)\n\n if (this.queue.length) {\n const { resolve, msg, transfer } = this.queue.shift()\n this.workersResolve[workerId] = resolve\n this.workers[workerId].postMessage(msg, transfer)\n } else {\n this.workerStatus ^= 1 << workerId\n }\n }\n\n setWorkerCreator(workerCreator) {\n this.workerCreator = workerCreator\n }\n\n setWorkerLimit(pool) {\n this.pool = pool\n }\n\n postMessage(msg, transfer) {\n return new Promise((resolve) => {\n const workerId = this._getIdleWorker()\n\n if (workerId !== -1) {\n this._initWorker(workerId)\n this.workerStatus |= 1 << workerId\n this.workersResolve[workerId] = resolve\n this.workers[workerId].postMessage(msg, transfer)\n } else {\n this.queue.push({ resolve, msg, transfer })\n }\n })\n }\n\n dispose() {\n this.workers.forEach((worker) => worker.terminate())\n this.workersResolve.length = 0\n this.workers.length = 0\n this.queue.length = 0\n this.workerStatus = 0\n }\n}\n"],"names":["resolve","msg"],"mappings":";;AAIO,MAAM,WAAW;AAAA,EACtB,YAAY,OAAO,GAAG;AACpB,SAAK,OAAO;AACZ,SAAK,QAAQ,CAAE;AACf,SAAK,UAAU,CAAE;AACjB,SAAK,iBAAiB,CAAE;AACxB,SAAK,eAAe;AAAA,EACrB;AAAA,EAED,YAAY,UAAU;AACpB,QAAI,CAAC,KAAK,QAAQ,QAAQ,GAAG;AAC3B,YAAM,SAAS,KAAK,cAAe;AACnC,aAAO,iBAAiB,WAAW,KAAK,WAAW,KAAK,MAAM,QAAQ,CAAC;AACvE,WAAK,QAAQ,QAAQ,IAAI;AAAA,IAC1B;AAAA,EACF;AAAA,EAED,iBAAiB;AACf,aAAS,IAAI,GAAG,IAAI,KAAK,MAAM;AAAK,UAAI,EAAE,KAAK,eAAgB,KAAK;AAAK,eAAO;AAEhF,WAAO;AAAA,EACR;AAAA,EAED,WAAW,UAAU,KAAK;AACxB,UAAM,UAAU,KAAK,eAAe,QAAQ;AAC5C,eAAW,QAAQ,GAAG;AAEtB,QAAI,KAAK,MAAM,QAAQ;AACrB,YAAM,EAAE,SAAAA,UAAS,KAAAC,MAAK,SAAU,IAAG,KAAK,MAAM,MAAO;AACrD,WAAK,eAAe,QAAQ,IAAID;AAChC,WAAK,QAAQ,QAAQ,EAAE,YAAYC,MAAK,QAAQ;AAAA,IACtD,OAAW;AACL,WAAK,gBAAgB,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA,EAED,iBAAiB,eAAe;AAC9B,SAAK,gBAAgB;AAAA,EACtB;AAAA,EAED,eAAe,MAAM;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAED,YAAY,KAAK,UAAU;AACzB,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,WAAW,KAAK,eAAgB;AAEtC,UAAI,aAAa,IAAI;AACnB,aAAK,YAAY,QAAQ;AACzB,aAAK,gBAAgB,KAAK;AAC1B,aAAK,eAAe,QAAQ,IAAI;AAChC,aAAK,QAAQ,QAAQ,EAAE,YAAY,KAAK,QAAQ;AAAA,MACxD,OAAa;AACL,aAAK,MAAM,KAAK,EAAE,SAAS,KAAK,UAAU;AAAA,MAC3C;AAAA,IACP,CAAK;AAAA,EACF;AAAA,EAED,UAAU;AACR,SAAK,QAAQ,QAAQ,CAAC,WAAW,OAAO,WAAW;AACnD,SAAK,eAAe,SAAS;AAC7B,SAAK,QAAQ,SAAS;AACtB,SAAK,MAAM,SAAS;AACpB,SAAK,eAAe;AAAA,EACrB;AACH;;"}
+63
View File
@@ -0,0 +1,63 @@
class WorkerPool {
constructor(pool = 4) {
this.pool = pool;
this.queue = [];
this.workers = [];
this.workersResolve = [];
this.workerStatus = 0;
}
_initWorker(workerId) {
if (!this.workers[workerId]) {
const worker = this.workerCreator();
worker.addEventListener("message", this._onMessage.bind(this, workerId));
this.workers[workerId] = worker;
}
}
_getIdleWorker() {
for (let i = 0; i < this.pool; i++)
if (!(this.workerStatus & 1 << i))
return i;
return -1;
}
_onMessage(workerId, msg) {
const resolve = this.workersResolve[workerId];
resolve && resolve(msg);
if (this.queue.length) {
const { resolve: resolve2, msg: msg2, transfer } = this.queue.shift();
this.workersResolve[workerId] = resolve2;
this.workers[workerId].postMessage(msg2, transfer);
} else {
this.workerStatus ^= 1 << workerId;
}
}
setWorkerCreator(workerCreator) {
this.workerCreator = workerCreator;
}
setWorkerLimit(pool) {
this.pool = pool;
}
postMessage(msg, transfer) {
return new Promise((resolve) => {
const workerId = this._getIdleWorker();
if (workerId !== -1) {
this._initWorker(workerId);
this.workerStatus |= 1 << workerId;
this.workersResolve[workerId] = resolve;
this.workers[workerId].postMessage(msg, transfer);
} else {
this.queue.push({ resolve, msg, transfer });
}
});
}
dispose() {
this.workers.forEach((worker) => worker.terminate());
this.workersResolve.length = 0;
this.workers.length = 0;
this.queue.length = 0;
this.workerStatus = 0;
}
}
export {
WorkerPool
};
//# sourceMappingURL=WorkerPool.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"WorkerPool.js","sources":["../../src/utils/WorkerPool.js"],"sourcesContent":["/**\n * @author Deepkolos / https://github.com/deepkolos\n */\n\nexport class WorkerPool {\n constructor(pool = 4) {\n this.pool = pool\n this.queue = []\n this.workers = []\n this.workersResolve = []\n this.workerStatus = 0\n }\n\n _initWorker(workerId) {\n if (!this.workers[workerId]) {\n const worker = this.workerCreator()\n worker.addEventListener('message', this._onMessage.bind(this, workerId))\n this.workers[workerId] = worker\n }\n }\n\n _getIdleWorker() {\n for (let i = 0; i < this.pool; i++) if (!(this.workerStatus & (1 << i))) return i\n\n return -1\n }\n\n _onMessage(workerId, msg) {\n const resolve = this.workersResolve[workerId]\n resolve && resolve(msg)\n\n if (this.queue.length) {\n const { resolve, msg, transfer } = this.queue.shift()\n this.workersResolve[workerId] = resolve\n this.workers[workerId].postMessage(msg, transfer)\n } else {\n this.workerStatus ^= 1 << workerId\n }\n }\n\n setWorkerCreator(workerCreator) {\n this.workerCreator = workerCreator\n }\n\n setWorkerLimit(pool) {\n this.pool = pool\n }\n\n postMessage(msg, transfer) {\n return new Promise((resolve) => {\n const workerId = this._getIdleWorker()\n\n if (workerId !== -1) {\n this._initWorker(workerId)\n this.workerStatus |= 1 << workerId\n this.workersResolve[workerId] = resolve\n this.workers[workerId].postMessage(msg, transfer)\n } else {\n this.queue.push({ resolve, msg, transfer })\n }\n })\n }\n\n dispose() {\n this.workers.forEach((worker) => worker.terminate())\n this.workersResolve.length = 0\n this.workers.length = 0\n this.queue.length = 0\n this.workerStatus = 0\n }\n}\n"],"names":["resolve","msg"],"mappings":"AAIO,MAAM,WAAW;AAAA,EACtB,YAAY,OAAO,GAAG;AACpB,SAAK,OAAO;AACZ,SAAK,QAAQ,CAAE;AACf,SAAK,UAAU,CAAE;AACjB,SAAK,iBAAiB,CAAE;AACxB,SAAK,eAAe;AAAA,EACrB;AAAA,EAED,YAAY,UAAU;AACpB,QAAI,CAAC,KAAK,QAAQ,QAAQ,GAAG;AAC3B,YAAM,SAAS,KAAK,cAAe;AACnC,aAAO,iBAAiB,WAAW,KAAK,WAAW,KAAK,MAAM,QAAQ,CAAC;AACvE,WAAK,QAAQ,QAAQ,IAAI;AAAA,IAC1B;AAAA,EACF;AAAA,EAED,iBAAiB;AACf,aAAS,IAAI,GAAG,IAAI,KAAK,MAAM;AAAK,UAAI,EAAE,KAAK,eAAgB,KAAK;AAAK,eAAO;AAEhF,WAAO;AAAA,EACR;AAAA,EAED,WAAW,UAAU,KAAK;AACxB,UAAM,UAAU,KAAK,eAAe,QAAQ;AAC5C,eAAW,QAAQ,GAAG;AAEtB,QAAI,KAAK,MAAM,QAAQ;AACrB,YAAM,EAAE,SAAAA,UAAS,KAAAC,MAAK,SAAU,IAAG,KAAK,MAAM,MAAO;AACrD,WAAK,eAAe,QAAQ,IAAID;AAChC,WAAK,QAAQ,QAAQ,EAAE,YAAYC,MAAK,QAAQ;AAAA,IACtD,OAAW;AACL,WAAK,gBAAgB,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA,EAED,iBAAiB,eAAe;AAC9B,SAAK,gBAAgB;AAAA,EACtB;AAAA,EAED,eAAe,MAAM;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAED,YAAY,KAAK,UAAU;AACzB,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,WAAW,KAAK,eAAgB;AAEtC,UAAI,aAAa,IAAI;AACnB,aAAK,YAAY,QAAQ;AACzB,aAAK,gBAAgB,KAAK;AAC1B,aAAK,eAAe,QAAQ,IAAI;AAChC,aAAK,QAAQ,QAAQ,EAAE,YAAY,KAAK,QAAQ;AAAA,MACxD,OAAa;AACL,aAAK,MAAM,KAAK,EAAE,SAAS,KAAK,UAAU;AAAA,MAC3C;AAAA,IACP,CAAK;AAAA,EACF;AAAA,EAED,UAAU;AACR,SAAK,QAAQ,QAAQ,CAAC,WAAW,OAAO,WAAW;AACnD,SAAK,eAAe,SAAS;AAC7B,SAAK,QAAQ,SAAS;AACtB,SAAK,MAAM,SAAS;AACpB,SAAK,eAAe;AAAA,EACrB;AACH;"}