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
+233
View File
@@ -0,0 +1,233 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const CHANNELS = 4;
const TEXTURE_WIDTH = 1024;
const TEXTURE_HEIGHT = 4;
const initSplineTexture = (numberOfCurves = 1) => {
const dataArray = new Float32Array(TEXTURE_WIDTH * TEXTURE_HEIGHT * numberOfCurves * CHANNELS);
const dataTexture = new THREE.DataTexture(dataArray, TEXTURE_WIDTH, TEXTURE_HEIGHT * numberOfCurves, THREE.RGBAFormat, THREE.FloatType);
dataTexture.wrapS = THREE.RepeatWrapping;
dataTexture.wrapT = THREE.RepeatWrapping;
dataTexture.magFilter = THREE.NearestFilter;
dataTexture.needsUpdate = true;
return dataTexture;
};
const updateSplineTexture = (texture, splineCurve, offset = 0) => {
const numberOfPoints = Math.floor(TEXTURE_WIDTH * (TEXTURE_HEIGHT / 4));
splineCurve.arcLengthDivisions = numberOfPoints / 2;
splineCurve.updateArcLengths();
const points = splineCurve.getSpacedPoints(numberOfPoints);
const frenetFrames = splineCurve.computeFrenetFrames(numberOfPoints, true);
for (let i = 0; i < numberOfPoints; i++) {
const rowOffset = Math.floor(i / TEXTURE_WIDTH);
const rowIndex = i % TEXTURE_WIDTH;
let pt = points[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 0 + rowOffset + TEXTURE_HEIGHT * offset);
pt = frenetFrames.tangents[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 1 + rowOffset + TEXTURE_HEIGHT * offset);
pt = frenetFrames.normals[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 2 + rowOffset + TEXTURE_HEIGHT * offset);
pt = frenetFrames.binormals[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 3 + rowOffset + TEXTURE_HEIGHT * offset);
}
texture.needsUpdate = true;
};
const setTextureValue = (texture, index, x, y, z, o) => {
const image = texture.image;
const { data } = image;
const i = CHANNELS * TEXTURE_WIDTH * o;
data[index * CHANNELS + i + 0] = x;
data[index * CHANNELS + i + 1] = y;
data[index * CHANNELS + i + 2] = z;
data[index * CHANNELS + i + 3] = 1;
};
const getUniforms = (splineTexture) => ({
spineTexture: { value: splineTexture },
pathOffset: { type: "f", value: 0 },
// time of path curve
pathSegment: { type: "f", value: 1 },
// fractional length of path
spineOffset: { type: "f", value: 161 },
spineLength: { type: "f", value: 400 },
flow: { type: "i", value: 1 }
});
function modifyShader(material, uniforms, numberOfCurves = 1) {
if (material.__ok)
return;
material.__ok = true;
material.onBeforeCompile = (shader) => {
if (shader.__modified)
return;
shader.__modified = true;
Object.assign(shader.uniforms, uniforms);
const vertexShader = (
/* glsl */
`
uniform sampler2D spineTexture;
uniform float pathOffset;
uniform float pathSegment;
uniform float spineOffset;
uniform float spineLength;
uniform int flow;
float textureLayers = ${TEXTURE_HEIGHT * numberOfCurves}.;
float textureStacks = ${TEXTURE_HEIGHT / 4}.;
${shader.vertexShader}
`.replace("#include <beginnormal_vertex>", "").replace("#include <defaultnormal_vertex>", "").replace("#include <begin_vertex>", "").replace(
/void\s*main\s*\(\)\s*\{/,
/* glsl */
`
void main() {
#include <beginnormal_vertex>
vec4 worldPos = modelMatrix * vec4(position, 1.);
bool bend = flow > 0;
float xWeight = bend ? 0. : 1.;
#ifdef USE_INSTANCING
float pathOffsetFromInstanceMatrix = instanceMatrix[3][2];
float spineLengthFromInstanceMatrix = instanceMatrix[3][0];
float spinePortion = bend ? (worldPos.x + spineOffset) / spineLengthFromInstanceMatrix : 0.;
float mt = (spinePortion * pathSegment + pathOffset + pathOffsetFromInstanceMatrix)*textureStacks;
#else
float spinePortion = bend ? (worldPos.x + spineOffset) / spineLength : 0.;
float mt = (spinePortion * pathSegment + pathOffset)*textureStacks;
#endif
mt = mod(mt, textureStacks);
float rowOffset = floor(mt);
#ifdef USE_INSTANCING
rowOffset += instanceMatrix[3][1] * ${TEXTURE_HEIGHT}.;
#endif
vec3 spinePos = texture2D(spineTexture, vec2(mt, (0. + rowOffset + 0.5) / textureLayers)).xyz;
vec3 a = texture2D(spineTexture, vec2(mt, (1. + rowOffset + 0.5) / textureLayers)).xyz;
vec3 b = texture2D(spineTexture, vec2(mt, (2. + rowOffset + 0.5) / textureLayers)).xyz;
vec3 c = texture2D(spineTexture, vec2(mt, (3. + rowOffset + 0.5) / textureLayers)).xyz;
mat3 basis = mat3(a, b, c);
vec3 transformed = basis
* vec3(worldPos.x * xWeight, worldPos.y * 1., worldPos.z * 1.)
+ spinePos;
vec3 transformedNormal = normalMatrix * (basis * objectNormal);
`
).replace(
"#include <project_vertex>",
/* glsl */
`vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
gl_Position = projectionMatrix * mvPosition;`
)
);
shader.vertexShader = vertexShader;
};
}
class Flow {
/**
* @param {Mesh} mesh The mesh to clone and modify to bend around the curve
* @param {number} numberOfCurves The amount of space that should preallocated for additional curves
*/
constructor(mesh, numberOfCurves = 1) {
__publicField(this, "curveArray");
__publicField(this, "curveLengthArray");
__publicField(this, "object3D");
__publicField(this, "splineTexure");
__publicField(this, "uniforms");
const obj3D = mesh.clone();
const splineTexure = initSplineTexture(numberOfCurves);
const uniforms = getUniforms(splineTexure);
obj3D.traverse((child) => {
if (child instanceof THREE.Mesh || child instanceof THREE.InstancedMesh) {
child.material = child.material.clone();
modifyShader(child.material, uniforms, numberOfCurves);
}
});
this.curveArray = new Array(numberOfCurves);
this.curveLengthArray = new Array(numberOfCurves);
this.object3D = obj3D;
this.splineTexure = splineTexure;
this.uniforms = uniforms;
}
updateCurve(index, curve) {
if (index >= this.curveArray.length)
throw Error("Index out of range for Flow");
const curveLength = curve.getLength();
this.uniforms.spineLength.value = curveLength;
this.curveLengthArray[index] = curveLength;
this.curveArray[index] = curve;
updateSplineTexture(this.splineTexure, curve, index);
}
moveAlongCurve(amount) {
this.uniforms.pathOffset.value += amount;
}
}
const matrix = /* @__PURE__ */ new THREE.Matrix4();
class InstancedFlow extends Flow {
/**
*
* @param {number} count The number of instanced elements
* @param {number} curveCount The number of curves to preallocate for
* @param {Geometry} geometry The geometry to use for the instanced mesh
* @param {Material} material The material to use for the instanced mesh
*/
constructor(count, curveCount, geometry, material) {
const mesh = new THREE.InstancedMesh(geometry, material, count);
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
mesh.frustumCulled = false;
super(mesh, curveCount);
__publicField(this, "offsets");
__publicField(this, "whichCurve");
this.offsets = new Array(count).fill(0);
this.whichCurve = new Array(count).fill(0);
}
/**
* The extra information about which curve and curve position is stored in the translation components of the matrix for the instanced objects
* This writes that information to the matrix and marks it as needing update.
*
* @param {number} index of the instanced element to update
*/
writeChanges(index) {
matrix.makeTranslation(this.curveLengthArray[this.whichCurve[index]], this.whichCurve[index], this.offsets[index]);
this.object3D.setMatrixAt(index, matrix);
this.object3D.instanceMatrix.needsUpdate = true;
}
/**
* Move an individual element along the curve by a specific amount
*
* @param {number} index Which element to update
* @param {number} offset Move by how much
*/
moveIndividualAlongCurve(index, offset) {
this.offsets[index] += offset;
this.writeChanges(index);
}
/**
* Select which curve to use for an element
*
* @param {number} index the index of the instanced element to update
* @param {number} curveNo the index of the curve it should use
*/
setCurve(index, curveNo) {
if (isNaN(curveNo))
throw Error("curve index being set is Not a Number (NaN)");
this.whichCurve[index] = curveNo;
this.writeChanges(index);
}
}
exports.Flow = Flow;
exports.InstancedFlow = InstancedFlow;
exports.getUniforms = getUniforms;
exports.initSplineTexture = initSplineTexture;
exports.modifyShader = modifyShader;
exports.updateSplineTexture = updateSplineTexture;
//# sourceMappingURL=CurveModifier.cjs.map
File diff suppressed because one or more lines are too long
+91
View File
@@ -0,0 +1,91 @@
import { DataTexture, Mesh, InstancedMesh, Material, Curve, BufferGeometry } from 'three';
import type { IUniform } from 'three';
/**
* Make a new DataTexture to store the descriptions of the curves.
*
* @param { number } numberOfCurves the number of curves needed to be described by this texture.
*/
export declare const initSplineTexture: (numberOfCurves?: number) => DataTexture;
/**
* Write the curve description to the data texture
*
* @param { DataTexture } texture The DataTexture to write to
* @param { Curve } splineCurve The curve to describe
* @param { number } offset Which curve slot to write to
*/
export declare const updateSplineTexture: <TCurve extends Curve<any>>(texture: DataTexture, splineCurve: TCurve, offset?: number) => void;
export interface INumericUniform extends IUniform {
type: 'f' | 'i';
value: number;
}
export type CurveModifierUniforms = {
spineTexture: IUniform<DataTexture>;
pathOffset: INumericUniform;
pathSegment: INumericUniform;
spineOffset: INumericUniform;
spineLength: INumericUniform;
flow: INumericUniform;
};
/**
* Create a new set of uniforms for describing the curve modifier
*
* @param { DataTexture } Texture which holds the curve description
*/
export declare const getUniforms: (splineTexture: DataTexture) => CurveModifierUniforms;
export type ModifiedMaterial<TMaterial extends Material> = TMaterial & {
__ok: boolean;
};
export declare function modifyShader<TMaterial extends Material = Material>(material: ModifiedMaterial<TMaterial>, uniforms: CurveModifierUniforms, numberOfCurves?: number): void;
/**
* A helper class for making meshes bend aroudn curves
*/
export declare class Flow<TMesh extends Mesh = Mesh> {
curveArray: Curve<any>[];
curveLengthArray: number[];
object3D: TMesh;
splineTexure: DataTexture;
uniforms: CurveModifierUniforms;
/**
* @param {Mesh} mesh The mesh to clone and modify to bend around the curve
* @param {number} numberOfCurves The amount of space that should preallocated for additional curves
*/
constructor(mesh: TMesh, numberOfCurves?: number);
updateCurve<TCurve extends Curve<any>>(index: number, curve: TCurve): void;
moveAlongCurve(amount: number): void;
}
/**
* A helper class for creating instanced versions of flow, where the instances are placed on the curve.
*/
export declare class InstancedFlow<TGeometry extends BufferGeometry = BufferGeometry, TMaterial extends Material = Material> extends Flow<InstancedMesh<TGeometry, TMaterial>> {
offsets: number[];
whichCurve: number[];
/**
*
* @param {number} count The number of instanced elements
* @param {number} curveCount The number of curves to preallocate for
* @param {Geometry} geometry The geometry to use for the instanced mesh
* @param {Material} material The material to use for the instanced mesh
*/
constructor(count: number, curveCount: number, geometry: TGeometry, material: TMaterial);
/**
* The extra information about which curve and curve position is stored in the translation components of the matrix for the instanced objects
* This writes that information to the matrix and marks it as needing update.
*
* @param {number} index of the instanced element to update
*/
private writeChanges;
/**
* Move an individual element along the curve by a specific amount
*
* @param {number} index Which element to update
* @param {number} offset Move by how much
*/
moveIndividualAlongCurve(index: number, offset: number): void;
/**
* Select which curve to use for an element
*
* @param {number} index the index of the instanced element to update
* @param {number} curveNo the index of the curve it should use
*/
setCurve(index: number, curveNo: number): void;
}
+233
View File
@@ -0,0 +1,233 @@
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 { DataTexture, RGBAFormat, FloatType, RepeatWrapping, NearestFilter, Mesh, InstancedMesh, DynamicDrawUsage, Matrix4 } from "three";
const CHANNELS = 4;
const TEXTURE_WIDTH = 1024;
const TEXTURE_HEIGHT = 4;
const initSplineTexture = (numberOfCurves = 1) => {
const dataArray = new Float32Array(TEXTURE_WIDTH * TEXTURE_HEIGHT * numberOfCurves * CHANNELS);
const dataTexture = new DataTexture(dataArray, TEXTURE_WIDTH, TEXTURE_HEIGHT * numberOfCurves, RGBAFormat, FloatType);
dataTexture.wrapS = RepeatWrapping;
dataTexture.wrapT = RepeatWrapping;
dataTexture.magFilter = NearestFilter;
dataTexture.needsUpdate = true;
return dataTexture;
};
const updateSplineTexture = (texture, splineCurve, offset = 0) => {
const numberOfPoints = Math.floor(TEXTURE_WIDTH * (TEXTURE_HEIGHT / 4));
splineCurve.arcLengthDivisions = numberOfPoints / 2;
splineCurve.updateArcLengths();
const points = splineCurve.getSpacedPoints(numberOfPoints);
const frenetFrames = splineCurve.computeFrenetFrames(numberOfPoints, true);
for (let i = 0; i < numberOfPoints; i++) {
const rowOffset = Math.floor(i / TEXTURE_WIDTH);
const rowIndex = i % TEXTURE_WIDTH;
let pt = points[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 0 + rowOffset + TEXTURE_HEIGHT * offset);
pt = frenetFrames.tangents[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 1 + rowOffset + TEXTURE_HEIGHT * offset);
pt = frenetFrames.normals[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 2 + rowOffset + TEXTURE_HEIGHT * offset);
pt = frenetFrames.binormals[i];
setTextureValue(texture, rowIndex, pt.x, pt.y, pt.z, 3 + rowOffset + TEXTURE_HEIGHT * offset);
}
texture.needsUpdate = true;
};
const setTextureValue = (texture, index, x, y, z, o) => {
const image = texture.image;
const { data } = image;
const i = CHANNELS * TEXTURE_WIDTH * o;
data[index * CHANNELS + i + 0] = x;
data[index * CHANNELS + i + 1] = y;
data[index * CHANNELS + i + 2] = z;
data[index * CHANNELS + i + 3] = 1;
};
const getUniforms = (splineTexture) => ({
spineTexture: { value: splineTexture },
pathOffset: { type: "f", value: 0 },
// time of path curve
pathSegment: { type: "f", value: 1 },
// fractional length of path
spineOffset: { type: "f", value: 161 },
spineLength: { type: "f", value: 400 },
flow: { type: "i", value: 1 }
});
function modifyShader(material, uniforms, numberOfCurves = 1) {
if (material.__ok)
return;
material.__ok = true;
material.onBeforeCompile = (shader) => {
if (shader.__modified)
return;
shader.__modified = true;
Object.assign(shader.uniforms, uniforms);
const vertexShader = (
/* glsl */
`
uniform sampler2D spineTexture;
uniform float pathOffset;
uniform float pathSegment;
uniform float spineOffset;
uniform float spineLength;
uniform int flow;
float textureLayers = ${TEXTURE_HEIGHT * numberOfCurves}.;
float textureStacks = ${TEXTURE_HEIGHT / 4}.;
${shader.vertexShader}
`.replace("#include <beginnormal_vertex>", "").replace("#include <defaultnormal_vertex>", "").replace("#include <begin_vertex>", "").replace(
/void\s*main\s*\(\)\s*\{/,
/* glsl */
`
void main() {
#include <beginnormal_vertex>
vec4 worldPos = modelMatrix * vec4(position, 1.);
bool bend = flow > 0;
float xWeight = bend ? 0. : 1.;
#ifdef USE_INSTANCING
float pathOffsetFromInstanceMatrix = instanceMatrix[3][2];
float spineLengthFromInstanceMatrix = instanceMatrix[3][0];
float spinePortion = bend ? (worldPos.x + spineOffset) / spineLengthFromInstanceMatrix : 0.;
float mt = (spinePortion * pathSegment + pathOffset + pathOffsetFromInstanceMatrix)*textureStacks;
#else
float spinePortion = bend ? (worldPos.x + spineOffset) / spineLength : 0.;
float mt = (spinePortion * pathSegment + pathOffset)*textureStacks;
#endif
mt = mod(mt, textureStacks);
float rowOffset = floor(mt);
#ifdef USE_INSTANCING
rowOffset += instanceMatrix[3][1] * ${TEXTURE_HEIGHT}.;
#endif
vec3 spinePos = texture2D(spineTexture, vec2(mt, (0. + rowOffset + 0.5) / textureLayers)).xyz;
vec3 a = texture2D(spineTexture, vec2(mt, (1. + rowOffset + 0.5) / textureLayers)).xyz;
vec3 b = texture2D(spineTexture, vec2(mt, (2. + rowOffset + 0.5) / textureLayers)).xyz;
vec3 c = texture2D(spineTexture, vec2(mt, (3. + rowOffset + 0.5) / textureLayers)).xyz;
mat3 basis = mat3(a, b, c);
vec3 transformed = basis
* vec3(worldPos.x * xWeight, worldPos.y * 1., worldPos.z * 1.)
+ spinePos;
vec3 transformedNormal = normalMatrix * (basis * objectNormal);
`
).replace(
"#include <project_vertex>",
/* glsl */
`vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
gl_Position = projectionMatrix * mvPosition;`
)
);
shader.vertexShader = vertexShader;
};
}
class Flow {
/**
* @param {Mesh} mesh The mesh to clone and modify to bend around the curve
* @param {number} numberOfCurves The amount of space that should preallocated for additional curves
*/
constructor(mesh, numberOfCurves = 1) {
__publicField(this, "curveArray");
__publicField(this, "curveLengthArray");
__publicField(this, "object3D");
__publicField(this, "splineTexure");
__publicField(this, "uniforms");
const obj3D = mesh.clone();
const splineTexure = initSplineTexture(numberOfCurves);
const uniforms = getUniforms(splineTexure);
obj3D.traverse((child) => {
if (child instanceof Mesh || child instanceof InstancedMesh) {
child.material = child.material.clone();
modifyShader(child.material, uniforms, numberOfCurves);
}
});
this.curveArray = new Array(numberOfCurves);
this.curveLengthArray = new Array(numberOfCurves);
this.object3D = obj3D;
this.splineTexure = splineTexure;
this.uniforms = uniforms;
}
updateCurve(index, curve) {
if (index >= this.curveArray.length)
throw Error("Index out of range for Flow");
const curveLength = curve.getLength();
this.uniforms.spineLength.value = curveLength;
this.curveLengthArray[index] = curveLength;
this.curveArray[index] = curve;
updateSplineTexture(this.splineTexure, curve, index);
}
moveAlongCurve(amount) {
this.uniforms.pathOffset.value += amount;
}
}
const matrix = /* @__PURE__ */ new Matrix4();
class InstancedFlow extends Flow {
/**
*
* @param {number} count The number of instanced elements
* @param {number} curveCount The number of curves to preallocate for
* @param {Geometry} geometry The geometry to use for the instanced mesh
* @param {Material} material The material to use for the instanced mesh
*/
constructor(count, curveCount, geometry, material) {
const mesh = new InstancedMesh(geometry, material, count);
mesh.instanceMatrix.setUsage(DynamicDrawUsage);
mesh.frustumCulled = false;
super(mesh, curveCount);
__publicField(this, "offsets");
__publicField(this, "whichCurve");
this.offsets = new Array(count).fill(0);
this.whichCurve = new Array(count).fill(0);
}
/**
* The extra information about which curve and curve position is stored in the translation components of the matrix for the instanced objects
* This writes that information to the matrix and marks it as needing update.
*
* @param {number} index of the instanced element to update
*/
writeChanges(index) {
matrix.makeTranslation(this.curveLengthArray[this.whichCurve[index]], this.whichCurve[index], this.offsets[index]);
this.object3D.setMatrixAt(index, matrix);
this.object3D.instanceMatrix.needsUpdate = true;
}
/**
* Move an individual element along the curve by a specific amount
*
* @param {number} index Which element to update
* @param {number} offset Move by how much
*/
moveIndividualAlongCurve(index, offset) {
this.offsets[index] += offset;
this.writeChanges(index);
}
/**
* Select which curve to use for an element
*
* @param {number} index the index of the instanced element to update
* @param {number} curveNo the index of the curve it should use
*/
setCurve(index, curveNo) {
if (isNaN(curveNo))
throw Error("curve index being set is Not a Number (NaN)");
this.whichCurve[index] = curveNo;
this.writeChanges(index);
}
}
export {
Flow,
InstancedFlow,
getUniforms,
initSplineTexture,
modifyShader,
updateSplineTexture
};
//# sourceMappingURL=CurveModifier.js.map
File diff suppressed because one or more lines are too long
+168
View File
@@ -0,0 +1,168 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const BufferGeometryUtils = require("../utils/BufferGeometryUtils.cjs");
class EdgeSplitModifier {
constructor() {
__publicField(this, "A", new THREE.Vector3());
__publicField(this, "B", new THREE.Vector3());
__publicField(this, "C", new THREE.Vector3());
__publicField(this, "positions", []);
__publicField(this, "normals", new Float32Array());
__publicField(this, "indexes", []);
__publicField(this, "pointToIndexMap", []);
__publicField(this, "splitIndexes", []);
__publicField(this, "oldNormals", []);
__publicField(this, "computeNormals", () => {
this.normals = new Float32Array(this.indexes.length * 3);
for (let i = 0; i < this.indexes.length; i += 3) {
let index = this.indexes[i];
this.A.set(this.positions[3 * index], this.positions[3 * index + 1], this.positions[3 * index + 2]);
index = this.indexes[i + 1];
this.B.set(this.positions[3 * index], this.positions[3 * index + 1], this.positions[3 * index + 2]);
index = this.indexes[i + 2];
this.C.set(this.positions[3 * index], this.positions[3 * index + 1], this.positions[3 * index + 2]);
this.C.sub(this.B);
this.A.sub(this.B);
const normal = this.C.cross(this.A).normalize();
for (let j = 0; j < 3; j++) {
this.normals[3 * (i + j)] = normal.x;
this.normals[3 * (i + j) + 1] = normal.y;
this.normals[3 * (i + j) + 2] = normal.z;
}
}
});
__publicField(this, "mapPositionsToIndexes", () => {
this.pointToIndexMap = Array(this.positions.length / 3);
for (let i = 0; i < this.indexes.length; i++) {
const index = this.indexes[i];
if (this.pointToIndexMap[index] == null) {
this.pointToIndexMap[index] = [];
}
this.pointToIndexMap[index].push(i);
}
});
__publicField(this, "edgeSplitToGroups", (indexes, cutOff, firstIndex) => {
this.A.set(
this.normals[3 * firstIndex],
this.normals[3 * firstIndex + 1],
this.normals[3 * firstIndex + 2]
).normalize();
const result = {
splitGroup: [],
currentGroup: [firstIndex]
};
for (let j of indexes) {
if (j !== firstIndex) {
this.B.set(this.normals[3 * j], this.normals[3 * j + 1], this.normals[3 * j + 2]).normalize();
if (this.B.dot(this.A) < cutOff) {
result.splitGroup.push(j);
} else {
result.currentGroup.push(j);
}
}
}
return result;
});
__publicField(this, "edgeSplit", (indexes, cutOff, original = null) => {
if (indexes.length === 0)
return;
const groupResults = [];
for (let index of indexes) {
groupResults.push(this.edgeSplitToGroups(indexes, cutOff, index));
}
let result = groupResults[0];
for (let groupResult of groupResults) {
if (groupResult.currentGroup.length > result.currentGroup.length) {
result = groupResult;
}
}
if (original != null) {
this.splitIndexes.push({
original,
indexes: result.currentGroup
});
}
if (result.splitGroup.length) {
this.edgeSplit(result.splitGroup, cutOff, original || result.currentGroup[0]);
}
});
__publicField(this, "modify", (geometry, cutOffAngle, tryKeepNormals = true) => {
let hadNormals = false;
if (geometry.attributes.normal) {
hadNormals = true;
geometry = geometry.clone();
if (tryKeepNormals === true && geometry.index !== null) {
this.oldNormals = geometry.attributes.normal.array;
}
geometry.deleteAttribute("normal");
}
if (geometry.index == null) {
if (BufferGeometryUtils === void 0) {
throw "THREE.EdgeSplitModifier relies on BufferGeometryUtils";
}
geometry = BufferGeometryUtils.mergeVertices(geometry);
}
this.indexes = geometry.index.array;
this.positions = geometry.getAttribute("position").array;
this.computeNormals();
this.mapPositionsToIndexes();
this.splitIndexes = [];
for (let vertexIndexes of this.pointToIndexMap) {
this.edgeSplit(vertexIndexes, Math.cos(cutOffAngle) - 1e-3);
}
const newAttributes = {};
for (let name of Object.keys(geometry.attributes)) {
const oldAttribute = geometry.attributes[name];
const newArray = new oldAttribute.array.constructor(
(this.indexes.length + this.splitIndexes.length) * oldAttribute.itemSize
);
newArray.set(oldAttribute.array);
newAttributes[name] = new THREE.BufferAttribute(newArray, oldAttribute.itemSize, oldAttribute.normalized);
}
const newIndexes = new Uint32Array(this.indexes.length);
newIndexes.set(this.indexes);
for (let i = 0; i < this.splitIndexes.length; i++) {
const split = this.splitIndexes[i];
const index = this.indexes[split.original];
for (let attribute of Object.values(newAttributes)) {
for (let j = 0; j < attribute.itemSize; j++) {
attribute.array[(this.indexes.length + i) * attribute.itemSize + j] = attribute.array[index * attribute.itemSize + j];
}
}
for (let j of split.indexes) {
newIndexes[j] = this.indexes.length + i;
}
}
geometry = new THREE.BufferGeometry();
geometry.setIndex(new THREE.BufferAttribute(newIndexes, 1));
for (let name of Object.keys(newAttributes)) {
geometry.setAttribute(name, newAttributes[name]);
}
if (hadNormals) {
geometry.computeVertexNormals();
if (this.oldNormals !== null) {
const changedNormals = new Array(this.oldNormals.length / 3).fill(false);
for (let splitData of this.splitIndexes)
changedNormals[splitData.original] = true;
for (let i = 0; i < changedNormals.length; i++) {
if (changedNormals[i] === false) {
for (let j = 0; j < 3; j++) {
geometry.attributes.normal.array[3 * i + j] = this.oldNormals[3 * i + j];
}
}
}
}
}
return geometry;
});
}
}
exports.EdgeSplitModifier = EdgeSplitModifier;
//# sourceMappingURL=EdgeSplitModifier.cjs.map
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
import { BufferGeometry } from 'three';
declare class EdgeSplitModifier {
private A;
private B;
private C;
private positions;
private normals;
private indexes;
private pointToIndexMap;
private splitIndexes;
private oldNormals;
constructor();
private computeNormals;
private mapPositionsToIndexes;
private edgeSplitToGroups;
private edgeSplit;
modify: (geometry: BufferGeometry, cutOffAngle: number, tryKeepNormals?: boolean) => BufferGeometry;
}
export { EdgeSplitModifier };
+169
View File
@@ -0,0 +1,169 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, BufferAttribute, BufferGeometry } from "three";
import * as BufferGeometryUtils from "../utils/BufferGeometryUtils.js";
import { mergeVertices } from "../utils/BufferGeometryUtils.js";
class EdgeSplitModifier {
constructor() {
__publicField(this, "A", new Vector3());
__publicField(this, "B", new Vector3());
__publicField(this, "C", new Vector3());
__publicField(this, "positions", []);
__publicField(this, "normals", new Float32Array());
__publicField(this, "indexes", []);
__publicField(this, "pointToIndexMap", []);
__publicField(this, "splitIndexes", []);
__publicField(this, "oldNormals", []);
__publicField(this, "computeNormals", () => {
this.normals = new Float32Array(this.indexes.length * 3);
for (let i = 0; i < this.indexes.length; i += 3) {
let index = this.indexes[i];
this.A.set(this.positions[3 * index], this.positions[3 * index + 1], this.positions[3 * index + 2]);
index = this.indexes[i + 1];
this.B.set(this.positions[3 * index], this.positions[3 * index + 1], this.positions[3 * index + 2]);
index = this.indexes[i + 2];
this.C.set(this.positions[3 * index], this.positions[3 * index + 1], this.positions[3 * index + 2]);
this.C.sub(this.B);
this.A.sub(this.B);
const normal = this.C.cross(this.A).normalize();
for (let j = 0; j < 3; j++) {
this.normals[3 * (i + j)] = normal.x;
this.normals[3 * (i + j) + 1] = normal.y;
this.normals[3 * (i + j) + 2] = normal.z;
}
}
});
__publicField(this, "mapPositionsToIndexes", () => {
this.pointToIndexMap = Array(this.positions.length / 3);
for (let i = 0; i < this.indexes.length; i++) {
const index = this.indexes[i];
if (this.pointToIndexMap[index] == null) {
this.pointToIndexMap[index] = [];
}
this.pointToIndexMap[index].push(i);
}
});
__publicField(this, "edgeSplitToGroups", (indexes, cutOff, firstIndex) => {
this.A.set(
this.normals[3 * firstIndex],
this.normals[3 * firstIndex + 1],
this.normals[3 * firstIndex + 2]
).normalize();
const result = {
splitGroup: [],
currentGroup: [firstIndex]
};
for (let j of indexes) {
if (j !== firstIndex) {
this.B.set(this.normals[3 * j], this.normals[3 * j + 1], this.normals[3 * j + 2]).normalize();
if (this.B.dot(this.A) < cutOff) {
result.splitGroup.push(j);
} else {
result.currentGroup.push(j);
}
}
}
return result;
});
__publicField(this, "edgeSplit", (indexes, cutOff, original = null) => {
if (indexes.length === 0)
return;
const groupResults = [];
for (let index of indexes) {
groupResults.push(this.edgeSplitToGroups(indexes, cutOff, index));
}
let result = groupResults[0];
for (let groupResult of groupResults) {
if (groupResult.currentGroup.length > result.currentGroup.length) {
result = groupResult;
}
}
if (original != null) {
this.splitIndexes.push({
original,
indexes: result.currentGroup
});
}
if (result.splitGroup.length) {
this.edgeSplit(result.splitGroup, cutOff, original || result.currentGroup[0]);
}
});
__publicField(this, "modify", (geometry, cutOffAngle, tryKeepNormals = true) => {
let hadNormals = false;
if (geometry.attributes.normal) {
hadNormals = true;
geometry = geometry.clone();
if (tryKeepNormals === true && geometry.index !== null) {
this.oldNormals = geometry.attributes.normal.array;
}
geometry.deleteAttribute("normal");
}
if (geometry.index == null) {
if (BufferGeometryUtils === void 0) {
throw "THREE.EdgeSplitModifier relies on BufferGeometryUtils";
}
geometry = mergeVertices(geometry);
}
this.indexes = geometry.index.array;
this.positions = geometry.getAttribute("position").array;
this.computeNormals();
this.mapPositionsToIndexes();
this.splitIndexes = [];
for (let vertexIndexes of this.pointToIndexMap) {
this.edgeSplit(vertexIndexes, Math.cos(cutOffAngle) - 1e-3);
}
const newAttributes = {};
for (let name of Object.keys(geometry.attributes)) {
const oldAttribute = geometry.attributes[name];
const newArray = new oldAttribute.array.constructor(
(this.indexes.length + this.splitIndexes.length) * oldAttribute.itemSize
);
newArray.set(oldAttribute.array);
newAttributes[name] = new BufferAttribute(newArray, oldAttribute.itemSize, oldAttribute.normalized);
}
const newIndexes = new Uint32Array(this.indexes.length);
newIndexes.set(this.indexes);
for (let i = 0; i < this.splitIndexes.length; i++) {
const split = this.splitIndexes[i];
const index = this.indexes[split.original];
for (let attribute of Object.values(newAttributes)) {
for (let j = 0; j < attribute.itemSize; j++) {
attribute.array[(this.indexes.length + i) * attribute.itemSize + j] = attribute.array[index * attribute.itemSize + j];
}
}
for (let j of split.indexes) {
newIndexes[j] = this.indexes.length + i;
}
}
geometry = new BufferGeometry();
geometry.setIndex(new BufferAttribute(newIndexes, 1));
for (let name of Object.keys(newAttributes)) {
geometry.setAttribute(name, newAttributes[name]);
}
if (hadNormals) {
geometry.computeVertexNormals();
if (this.oldNormals !== null) {
const changedNormals = new Array(this.oldNormals.length / 3).fill(false);
for (let splitData of this.splitIndexes)
changedNormals[splitData.original] = true;
for (let i = 0; i < changedNormals.length; i++) {
if (changedNormals[i] === false) {
for (let j = 0; j < 3; j++) {
geometry.attributes.normal.array[3 * i + j] = this.oldNormals[3 * i + j];
}
}
}
}
}
return geometry;
});
}
}
export {
EdgeSplitModifier
};
//# sourceMappingURL=EdgeSplitModifier.js.map
File diff suppressed because one or more lines are too long
+302
View File
@@ -0,0 +1,302 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const BufferGeometryUtils = require("../utils/BufferGeometryUtils.cjs");
const cb = /* @__PURE__ */ new THREE.Vector3();
const ab = /* @__PURE__ */ new THREE.Vector3();
function pushIfUnique(array, object) {
if (array.indexOf(object) === -1)
array.push(object);
}
function removeFromArray(array, object) {
const k = array.indexOf(object);
if (k > -1)
array.splice(k, 1);
}
class Vertex {
constructor(v, id) {
__publicField(this, "position");
__publicField(this, "id");
__publicField(this, "faces");
__publicField(this, "neighbors");
__publicField(this, "collapseCost");
__publicField(this, "collapseNeighbor");
__publicField(this, "minCost", 0);
__publicField(this, "totalCost", 0);
__publicField(this, "costCount", 0);
this.position = v;
this.id = id;
this.faces = [];
this.neighbors = [];
this.collapseCost = 0;
this.collapseNeighbor = null;
}
addUniqueNeighbor(vertex) {
pushIfUnique(this.neighbors, vertex);
}
removeIfNonNeighbor(n) {
const neighbors = this.neighbors;
const faces = this.faces;
const offset = neighbors.indexOf(n);
if (offset === -1)
return;
for (let i = 0; i < faces.length; i++) {
if (faces[i].hasVertex(n))
return;
}
neighbors.splice(offset, 1);
}
}
class Triangle {
constructor(v1, v2, v3, a, b, c) {
__publicField(this, "a");
__publicField(this, "b");
__publicField(this, "c");
__publicField(this, "v1");
__publicField(this, "v2");
__publicField(this, "v3");
__publicField(this, "normal", new THREE.Vector3());
this.a = a;
this.b = b;
this.c = c;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.computeNormal();
v1.faces.push(this);
v1.addUniqueNeighbor(v2);
v1.addUniqueNeighbor(v3);
v2.faces.push(this);
v2.addUniqueNeighbor(v1);
v2.addUniqueNeighbor(v3);
v3.faces.push(this);
v3.addUniqueNeighbor(v1);
v3.addUniqueNeighbor(v2);
}
computeNormal() {
const vA = this.v1.position;
const vB = this.v2.position;
const vC = this.v3.position;
cb.subVectors(vC, vB);
ab.subVectors(vA, vB);
cb.cross(ab).normalize();
this.normal.copy(cb);
}
hasVertex(v) {
return v === this.v1 || v === this.v2 || v === this.v3;
}
replaceVertex(oldv, newv) {
if (oldv === this.v1)
this.v1 = newv;
else if (oldv === this.v2)
this.v2 = newv;
else if (oldv === this.v3)
this.v3 = newv;
removeFromArray(oldv.faces, this);
newv.faces.push(this);
oldv.removeIfNonNeighbor(this.v1);
this.v1.removeIfNonNeighbor(oldv);
oldv.removeIfNonNeighbor(this.v2);
this.v2.removeIfNonNeighbor(oldv);
oldv.removeIfNonNeighbor(this.v3);
this.v3.removeIfNonNeighbor(oldv);
this.v1.addUniqueNeighbor(this.v2);
this.v1.addUniqueNeighbor(this.v3);
this.v2.addUniqueNeighbor(this.v1);
this.v2.addUniqueNeighbor(this.v3);
this.v3.addUniqueNeighbor(this.v1);
this.v3.addUniqueNeighbor(this.v2);
this.computeNormal();
}
}
class SimplifyModifier {
constructor() {
__publicField(this, "computeEdgeCollapseCost", (u, v) => {
const edgelength = v.position.distanceTo(u.position);
let curvature = 0;
const sideFaces = [];
let i, il = u.faces.length, face, sideFace;
for (i = 0; i < il; i++) {
face = u.faces[i];
if (face.hasVertex(v)) {
sideFaces.push(face);
}
}
for (i = 0; i < il; i++) {
let minCurvature = 1;
face = u.faces[i];
for (let j = 0; j < sideFaces.length; j++) {
sideFace = sideFaces[j];
const dotProd = face.normal.dot(sideFace.normal);
minCurvature = Math.min(minCurvature, (1.001 - dotProd) / 2);
}
curvature = Math.max(curvature, minCurvature);
}
const borders = 0;
if (sideFaces.length < 2) {
curvature = 1;
}
const amt = edgelength * curvature + borders;
return amt;
});
__publicField(this, "computeEdgeCostAtVertex", (v) => {
if (v.neighbors.length === 0) {
v.collapseNeighbor = null;
v.collapseCost = -0.01;
return;
}
v.collapseCost = 1e5;
v.collapseNeighbor = null;
for (let i = 0; i < v.neighbors.length; i++) {
const collapseCost = this.computeEdgeCollapseCost(v, v.neighbors[i]);
if (!v.collapseNeighbor) {
v.collapseNeighbor = v.neighbors[i];
v.collapseCost = collapseCost;
v.minCost = collapseCost;
v.totalCost = 0;
v.costCount = 0;
}
v.costCount++;
v.totalCost += collapseCost;
if (collapseCost < v.minCost) {
v.collapseNeighbor = v.neighbors[i];
v.minCost = collapseCost;
}
}
v.collapseCost = v.totalCost / v.costCount;
});
__publicField(this, "removeFace", (f, faces) => {
removeFromArray(faces, f);
if (f.v1)
removeFromArray(f.v1.faces, f);
if (f.v2)
removeFromArray(f.v2.faces, f);
if (f.v3)
removeFromArray(f.v3.faces, f);
const vs = [f.v1, f.v2, f.v3];
let v1, v2;
for (let i = 0; i < 3; i++) {
v1 = vs[i];
v2 = vs[(i + 1) % 3];
if (!v1 || !v2)
continue;
v1.removeIfNonNeighbor(v2);
v2.removeIfNonNeighbor(v1);
}
});
__publicField(this, "collapse", (vertices, faces, u, v) => {
if (!v) {
this.removeVertex(u, vertices);
return;
}
let i;
const tmpVertices = [];
for (i = 0; i < u.neighbors.length; i++) {
tmpVertices.push(u.neighbors[i]);
}
for (i = u.faces.length - 1; i >= 0; i--) {
if (u.faces[i].hasVertex(v)) {
this.removeFace(u.faces[i], faces);
}
}
for (i = u.faces.length - 1; i >= 0; i--) {
u.faces[i].replaceVertex(u, v);
}
this.removeVertex(u, vertices);
for (i = 0; i < tmpVertices.length; i++) {
this.computeEdgeCostAtVertex(tmpVertices[i]);
}
});
__publicField(this, "minimumCostEdge", (vertices) => {
let least = vertices[0];
for (let i = 0; i < vertices.length; i++) {
if (vertices[i].collapseCost < least.collapseCost) {
least = vertices[i];
}
}
return least;
});
__publicField(this, "modify", (geometry, count) => {
geometry = geometry.clone();
const attributes = geometry.attributes;
for (let name in attributes) {
if (name !== "position")
geometry.deleteAttribute(name);
}
geometry = BufferGeometryUtils.mergeVertices(geometry);
const vertices = [];
const faces = [];
const positionAttribute = geometry.getAttribute("position");
for (let i = 0; i < positionAttribute.count; i++) {
const v = new THREE.Vector3().fromBufferAttribute(positionAttribute, i);
const vertex = new Vertex(v, i);
vertices.push(vertex);
}
const geomIndex = geometry.getIndex();
if (geomIndex !== null) {
for (let i = 0; i < geomIndex.count; i += 3) {
const a = geomIndex.getX(i);
const b = geomIndex.getX(i + 1);
const c = geomIndex.getX(i + 2);
const triangle = new Triangle(vertices[a], vertices[b], vertices[c], a, b, c);
faces.push(triangle);
}
} else {
for (let i = 0; i < positionAttribute.count; i += 3) {
const a = i;
const b = i + 1;
const c = i + 2;
const triangle = new Triangle(vertices[a], vertices[b], vertices[c], a, b, c);
faces.push(triangle);
}
}
for (let i = 0, il = vertices.length; i < il; i++) {
this.computeEdgeCostAtVertex(vertices[i]);
}
let nextVertex;
let z = count;
while (z--) {
nextVertex = this.minimumCostEdge(vertices);
if (!nextVertex) {
console.log("THREE.SimplifyModifier: No next vertex");
break;
} else {
this.collapse(vertices, faces, nextVertex, nextVertex.collapseNeighbor);
}
}
const simplifiedGeometry = new THREE.BufferGeometry();
const position = [];
let index = [];
for (let i = 0; i < vertices.length; i++) {
const vertex = vertices[i].position;
position.push(vertex.x, vertex.y, vertex.z);
}
for (let i = 0; i < faces.length; i++) {
const face = faces[i];
const a = vertices.indexOf(face.v1);
const b = vertices.indexOf(face.v2);
const c = vertices.indexOf(face.v3);
index.push(a, b, c);
}
simplifiedGeometry.setAttribute("position", new THREE.Float32BufferAttribute(position, 3));
simplifiedGeometry.setIndex(index);
return simplifiedGeometry;
});
}
removeVertex(v, vertices) {
console.assert(v.faces.length === 0);
while (v.neighbors.length) {
const n = v.neighbors.pop();
removeFromArray(n.neighbors, v);
}
removeFromArray(vertices, v);
}
}
exports.SimplifyModifier = SimplifyModifier;
//# sourceMappingURL=SimplifyModifier.cjs.map
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
import { BufferGeometry } from 'three';
/**
* Simplification Geometry Modifier
* - based on code and technique
* - by Stan Melax in 1998
* - Progressive Mesh type Polygon Reduction Algorithm
* - http://www.melax.com/polychop/
*/
declare class SimplifyModifier {
constructor();
private computeEdgeCollapseCost;
private removeVertex;
private computeEdgeCostAtVertex;
private removeFace;
private collapse;
private minimumCostEdge;
modify: (geometry: BufferGeometry, count: number) => BufferGeometry;
}
export { SimplifyModifier };
+302
View File
@@ -0,0 +1,302 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, BufferGeometry, Float32BufferAttribute } from "three";
import { mergeVertices } from "../utils/BufferGeometryUtils.js";
const cb = /* @__PURE__ */ new Vector3();
const ab = /* @__PURE__ */ new Vector3();
function pushIfUnique(array, object) {
if (array.indexOf(object) === -1)
array.push(object);
}
function removeFromArray(array, object) {
const k = array.indexOf(object);
if (k > -1)
array.splice(k, 1);
}
class Vertex {
constructor(v, id) {
__publicField(this, "position");
__publicField(this, "id");
__publicField(this, "faces");
__publicField(this, "neighbors");
__publicField(this, "collapseCost");
__publicField(this, "collapseNeighbor");
__publicField(this, "minCost", 0);
__publicField(this, "totalCost", 0);
__publicField(this, "costCount", 0);
this.position = v;
this.id = id;
this.faces = [];
this.neighbors = [];
this.collapseCost = 0;
this.collapseNeighbor = null;
}
addUniqueNeighbor(vertex) {
pushIfUnique(this.neighbors, vertex);
}
removeIfNonNeighbor(n) {
const neighbors = this.neighbors;
const faces = this.faces;
const offset = neighbors.indexOf(n);
if (offset === -1)
return;
for (let i = 0; i < faces.length; i++) {
if (faces[i].hasVertex(n))
return;
}
neighbors.splice(offset, 1);
}
}
class Triangle {
constructor(v1, v2, v3, a, b, c) {
__publicField(this, "a");
__publicField(this, "b");
__publicField(this, "c");
__publicField(this, "v1");
__publicField(this, "v2");
__publicField(this, "v3");
__publicField(this, "normal", new Vector3());
this.a = a;
this.b = b;
this.c = c;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.computeNormal();
v1.faces.push(this);
v1.addUniqueNeighbor(v2);
v1.addUniqueNeighbor(v3);
v2.faces.push(this);
v2.addUniqueNeighbor(v1);
v2.addUniqueNeighbor(v3);
v3.faces.push(this);
v3.addUniqueNeighbor(v1);
v3.addUniqueNeighbor(v2);
}
computeNormal() {
const vA = this.v1.position;
const vB = this.v2.position;
const vC = this.v3.position;
cb.subVectors(vC, vB);
ab.subVectors(vA, vB);
cb.cross(ab).normalize();
this.normal.copy(cb);
}
hasVertex(v) {
return v === this.v1 || v === this.v2 || v === this.v3;
}
replaceVertex(oldv, newv) {
if (oldv === this.v1)
this.v1 = newv;
else if (oldv === this.v2)
this.v2 = newv;
else if (oldv === this.v3)
this.v3 = newv;
removeFromArray(oldv.faces, this);
newv.faces.push(this);
oldv.removeIfNonNeighbor(this.v1);
this.v1.removeIfNonNeighbor(oldv);
oldv.removeIfNonNeighbor(this.v2);
this.v2.removeIfNonNeighbor(oldv);
oldv.removeIfNonNeighbor(this.v3);
this.v3.removeIfNonNeighbor(oldv);
this.v1.addUniqueNeighbor(this.v2);
this.v1.addUniqueNeighbor(this.v3);
this.v2.addUniqueNeighbor(this.v1);
this.v2.addUniqueNeighbor(this.v3);
this.v3.addUniqueNeighbor(this.v1);
this.v3.addUniqueNeighbor(this.v2);
this.computeNormal();
}
}
class SimplifyModifier {
constructor() {
__publicField(this, "computeEdgeCollapseCost", (u, v) => {
const edgelength = v.position.distanceTo(u.position);
let curvature = 0;
const sideFaces = [];
let i, il = u.faces.length, face, sideFace;
for (i = 0; i < il; i++) {
face = u.faces[i];
if (face.hasVertex(v)) {
sideFaces.push(face);
}
}
for (i = 0; i < il; i++) {
let minCurvature = 1;
face = u.faces[i];
for (let j = 0; j < sideFaces.length; j++) {
sideFace = sideFaces[j];
const dotProd = face.normal.dot(sideFace.normal);
minCurvature = Math.min(minCurvature, (1.001 - dotProd) / 2);
}
curvature = Math.max(curvature, minCurvature);
}
const borders = 0;
if (sideFaces.length < 2) {
curvature = 1;
}
const amt = edgelength * curvature + borders;
return amt;
});
__publicField(this, "computeEdgeCostAtVertex", (v) => {
if (v.neighbors.length === 0) {
v.collapseNeighbor = null;
v.collapseCost = -0.01;
return;
}
v.collapseCost = 1e5;
v.collapseNeighbor = null;
for (let i = 0; i < v.neighbors.length; i++) {
const collapseCost = this.computeEdgeCollapseCost(v, v.neighbors[i]);
if (!v.collapseNeighbor) {
v.collapseNeighbor = v.neighbors[i];
v.collapseCost = collapseCost;
v.minCost = collapseCost;
v.totalCost = 0;
v.costCount = 0;
}
v.costCount++;
v.totalCost += collapseCost;
if (collapseCost < v.minCost) {
v.collapseNeighbor = v.neighbors[i];
v.minCost = collapseCost;
}
}
v.collapseCost = v.totalCost / v.costCount;
});
__publicField(this, "removeFace", (f, faces) => {
removeFromArray(faces, f);
if (f.v1)
removeFromArray(f.v1.faces, f);
if (f.v2)
removeFromArray(f.v2.faces, f);
if (f.v3)
removeFromArray(f.v3.faces, f);
const vs = [f.v1, f.v2, f.v3];
let v1, v2;
for (let i = 0; i < 3; i++) {
v1 = vs[i];
v2 = vs[(i + 1) % 3];
if (!v1 || !v2)
continue;
v1.removeIfNonNeighbor(v2);
v2.removeIfNonNeighbor(v1);
}
});
__publicField(this, "collapse", (vertices, faces, u, v) => {
if (!v) {
this.removeVertex(u, vertices);
return;
}
let i;
const tmpVertices = [];
for (i = 0; i < u.neighbors.length; i++) {
tmpVertices.push(u.neighbors[i]);
}
for (i = u.faces.length - 1; i >= 0; i--) {
if (u.faces[i].hasVertex(v)) {
this.removeFace(u.faces[i], faces);
}
}
for (i = u.faces.length - 1; i >= 0; i--) {
u.faces[i].replaceVertex(u, v);
}
this.removeVertex(u, vertices);
for (i = 0; i < tmpVertices.length; i++) {
this.computeEdgeCostAtVertex(tmpVertices[i]);
}
});
__publicField(this, "minimumCostEdge", (vertices) => {
let least = vertices[0];
for (let i = 0; i < vertices.length; i++) {
if (vertices[i].collapseCost < least.collapseCost) {
least = vertices[i];
}
}
return least;
});
__publicField(this, "modify", (geometry, count) => {
geometry = geometry.clone();
const attributes = geometry.attributes;
for (let name in attributes) {
if (name !== "position")
geometry.deleteAttribute(name);
}
geometry = mergeVertices(geometry);
const vertices = [];
const faces = [];
const positionAttribute = geometry.getAttribute("position");
for (let i = 0; i < positionAttribute.count; i++) {
const v = new Vector3().fromBufferAttribute(positionAttribute, i);
const vertex = new Vertex(v, i);
vertices.push(vertex);
}
const geomIndex = geometry.getIndex();
if (geomIndex !== null) {
for (let i = 0; i < geomIndex.count; i += 3) {
const a = geomIndex.getX(i);
const b = geomIndex.getX(i + 1);
const c = geomIndex.getX(i + 2);
const triangle = new Triangle(vertices[a], vertices[b], vertices[c], a, b, c);
faces.push(triangle);
}
} else {
for (let i = 0; i < positionAttribute.count; i += 3) {
const a = i;
const b = i + 1;
const c = i + 2;
const triangle = new Triangle(vertices[a], vertices[b], vertices[c], a, b, c);
faces.push(triangle);
}
}
for (let i = 0, il = vertices.length; i < il; i++) {
this.computeEdgeCostAtVertex(vertices[i]);
}
let nextVertex;
let z = count;
while (z--) {
nextVertex = this.minimumCostEdge(vertices);
if (!nextVertex) {
console.log("THREE.SimplifyModifier: No next vertex");
break;
} else {
this.collapse(vertices, faces, nextVertex, nextVertex.collapseNeighbor);
}
}
const simplifiedGeometry = new BufferGeometry();
const position = [];
let index = [];
for (let i = 0; i < vertices.length; i++) {
const vertex = vertices[i].position;
position.push(vertex.x, vertex.y, vertex.z);
}
for (let i = 0; i < faces.length; i++) {
const face = faces[i];
const a = vertices.indexOf(face.v1);
const b = vertices.indexOf(face.v2);
const c = vertices.indexOf(face.v3);
index.push(a, b, c);
}
simplifiedGeometry.setAttribute("position", new Float32BufferAttribute(position, 3));
simplifiedGeometry.setIndex(index);
return simplifiedGeometry;
});
}
removeVertex(v, vertices) {
console.assert(v.faces.length === 0);
while (v.neighbors.length) {
const n = v.neighbors.pop();
removeFromArray(n.neighbors, v);
}
removeFromArray(vertices, v);
}
}
export {
SimplifyModifier
};
//# sourceMappingURL=SimplifyModifier.js.map
File diff suppressed because one or more lines are too long
+216
View File
@@ -0,0 +1,216 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const uv1 = require("../_polyfill/uv1.cjs");
class TessellateModifier {
constructor(maxEdgeLength = 0.1, maxIterations = 6) {
__publicField(this, "maxEdgeLength");
__publicField(this, "maxIterations");
__publicField(this, "modify", (geometry) => {
if (geometry.index !== null) {
geometry = geometry.toNonIndexed();
}
const maxIterations = this.maxIterations;
const maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
const va = new THREE.Vector3();
const vb = new THREE.Vector3();
const vc = new THREE.Vector3();
const vm = new THREE.Vector3();
const vs = [va, vb, vc, vm];
const na = new THREE.Vector3();
const nb = new THREE.Vector3();
const nc = new THREE.Vector3();
const nm = new THREE.Vector3();
const ns = [na, nb, nc, nm];
const ca = new THREE.Color();
const cb = new THREE.Color();
const cc = new THREE.Color();
const cm = new THREE.Color();
const cs = [ca, cb, cc, cm];
const ua = new THREE.Vector2();
const ub = new THREE.Vector2();
const uc = new THREE.Vector2();
const um = new THREE.Vector2();
const us = [ua, ub, uc, um];
const u2a = new THREE.Vector2();
const u2b = new THREE.Vector2();
const u2c = new THREE.Vector2();
const u2m = new THREE.Vector2();
const u2s = [u2a, u2b, u2c, u2m];
const attributes = geometry.attributes;
const hasNormals = attributes.normal !== void 0;
const hasColors = attributes.color !== void 0;
const hasUVs = attributes.uv !== void 0;
const hasUV1s = attributes[uv1.UV1] !== void 0;
let positions = attributes.position.array;
let normals = hasNormals ? attributes.normal.array : null;
let colors = hasColors ? attributes.color.array : null;
let uvs = hasUVs ? attributes.uv.array : null;
let uv1s = hasUV1s ? attributes.uv1.array : null;
let positions2 = positions;
let normals2 = normals;
let colors2 = colors;
let uvs2 = uvs;
let uv1s2 = uv1s;
let iteration = 0;
let tessellating = true;
function addTriangle(a, b, c) {
const v1 = vs[a];
const v2 = vs[b];
const v3 = vs[c];
positions2.push(v1.x, v1.y, v1.z);
positions2.push(v2.x, v2.y, v2.z);
positions2.push(v3.x, v3.y, v3.z);
if (hasNormals) {
const n1 = ns[a];
const n2 = ns[b];
const n3 = ns[c];
normals2.push(n1.x, n1.y, n1.z);
normals2.push(n2.x, n2.y, n2.z);
normals2.push(n3.x, n3.y, n3.z);
}
if (hasColors) {
const c1 = cs[a];
const c2 = cs[b];
const c3 = cs[c];
colors2.push(c1.r, c1.g, c1.b);
colors2.push(c2.r, c2.g, c2.b);
colors2.push(c3.r, c3.g, c3.b);
}
if (hasUVs) {
const u1 = us[a];
const u2 = us[b];
const u3 = us[c];
uvs2.push(u1.x, u1.y);
uvs2.push(u2.x, u2.y);
uvs2.push(u3.x, u3.y);
}
if (hasUV1s) {
const u21 = u2s[a];
const u22 = u2s[b];
const u23 = u2s[c];
uv1s2.push(u21.x, u21.y);
uv1s2.push(u22.x, u22.y);
uv1s2.push(u23.x, u23.y);
}
}
while (tessellating && iteration < maxIterations) {
iteration++;
tessellating = false;
positions = positions2;
positions2 = [];
if (hasNormals) {
normals = normals2;
normals2 = [];
}
if (hasColors) {
colors = colors2;
colors2 = [];
}
if (hasUVs) {
uvs = uvs2;
uvs2 = [];
}
if (hasUV1s) {
uv1s = uv1s2;
uv1s2 = [];
}
for (let i = 0, i2 = 0, il = positions.length; i < il; i += 9, i2 += 6) {
va.fromArray(positions, i + 0);
vb.fromArray(positions, i + 3);
vc.fromArray(positions, i + 6);
if (hasNormals && normals) {
na.fromArray(normals, i + 0);
nb.fromArray(normals, i + 3);
nc.fromArray(normals, i + 6);
}
if (hasColors && colors) {
ca.fromArray(colors, i + 0);
cb.fromArray(colors, i + 3);
cc.fromArray(colors, i + 6);
}
if (hasUVs && uvs) {
ua.fromArray(uvs, i2 + 0);
ub.fromArray(uvs, i2 + 2);
uc.fromArray(uvs, i2 + 4);
}
if (hasUV1s && uv1s) {
u2a.fromArray(uv1s, i2 + 0);
u2b.fromArray(uv1s, i2 + 2);
u2c.fromArray(uv1s, i2 + 4);
}
const dab = va.distanceToSquared(vb);
const dbc = vb.distanceToSquared(vc);
const dac = va.distanceToSquared(vc);
if (dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared) {
tessellating = true;
if (dab >= dbc && dab >= dac) {
vm.lerpVectors(va, vb, 0.5);
if (hasNormals)
nm.lerpVectors(na, nb, 0.5);
if (hasColors)
cm.lerpColors(ca, cb, 0.5);
if (hasUVs)
um.lerpVectors(ua, ub, 0.5);
if (hasUV1s)
u2m.lerpVectors(u2a, u2b, 0.5);
addTriangle(0, 3, 2);
addTriangle(3, 1, 2);
} else if (dbc >= dab && dbc >= dac) {
vm.lerpVectors(vb, vc, 0.5);
if (hasNormals)
nm.lerpVectors(nb, nc, 0.5);
if (hasColors)
cm.lerpColors(cb, cc, 0.5);
if (hasUVs)
um.lerpVectors(ub, uc, 0.5);
if (hasUV1s)
u2m.lerpVectors(u2b, u2c, 0.5);
addTriangle(0, 1, 3);
addTriangle(3, 2, 0);
} else {
vm.lerpVectors(va, vc, 0.5);
if (hasNormals)
nm.lerpVectors(na, nc, 0.5);
if (hasColors)
cm.lerpColors(ca, cc, 0.5);
if (hasUVs)
um.lerpVectors(ua, uc, 0.5);
if (hasUV1s)
u2m.lerpVectors(u2a, u2c, 0.5);
addTriangle(0, 1, 3);
addTriangle(3, 1, 2);
}
} else {
addTriangle(0, 1, 2);
}
}
}
const geometry2 = new THREE.BufferGeometry();
geometry2.setAttribute("position", new THREE.Float32BufferAttribute(positions2, 3));
if (hasNormals) {
geometry2.setAttribute("normal", new THREE.Float32BufferAttribute(normals2, 3));
}
if (hasColors) {
geometry2.setAttribute("color", new THREE.Float32BufferAttribute(colors2, 3));
}
if (hasUVs) {
geometry2.setAttribute("uv", new THREE.Float32BufferAttribute(uvs2, 2));
}
if (hasUV1s) {
geometry2.setAttribute(uv1.UV1, new THREE.Float32BufferAttribute(uv1s2, 2));
}
return geometry2;
});
this.maxEdgeLength = maxEdgeLength;
this.maxIterations = maxIterations;
}
}
exports.TessellateModifier = TessellateModifier;
//# sourceMappingURL=TessellateModifier.cjs.map
File diff suppressed because one or more lines are too long
+11
View File
@@ -0,0 +1,11 @@
import { BufferGeometry } from 'three';
/**
* Break faces with edges longer than maxEdgeLength
*/
declare class TessellateModifier {
maxEdgeLength: number;
maxIterations: number;
constructor(maxEdgeLength?: number, maxIterations?: number);
modify: (geometry: BufferGeometry) => BufferGeometry;
}
export { TessellateModifier };
+216
View File
@@ -0,0 +1,216 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, Color, Vector2, BufferGeometry, Float32BufferAttribute } from "three";
import { UV1 } from "../_polyfill/uv1.js";
class TessellateModifier {
constructor(maxEdgeLength = 0.1, maxIterations = 6) {
__publicField(this, "maxEdgeLength");
__publicField(this, "maxIterations");
__publicField(this, "modify", (geometry) => {
if (geometry.index !== null) {
geometry = geometry.toNonIndexed();
}
const maxIterations = this.maxIterations;
const maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
const va = new Vector3();
const vb = new Vector3();
const vc = new Vector3();
const vm = new Vector3();
const vs = [va, vb, vc, vm];
const na = new Vector3();
const nb = new Vector3();
const nc = new Vector3();
const nm = new Vector3();
const ns = [na, nb, nc, nm];
const ca = new Color();
const cb = new Color();
const cc = new Color();
const cm = new Color();
const cs = [ca, cb, cc, cm];
const ua = new Vector2();
const ub = new Vector2();
const uc = new Vector2();
const um = new Vector2();
const us = [ua, ub, uc, um];
const u2a = new Vector2();
const u2b = new Vector2();
const u2c = new Vector2();
const u2m = new Vector2();
const u2s = [u2a, u2b, u2c, u2m];
const attributes = geometry.attributes;
const hasNormals = attributes.normal !== void 0;
const hasColors = attributes.color !== void 0;
const hasUVs = attributes.uv !== void 0;
const hasUV1s = attributes[UV1] !== void 0;
let positions = attributes.position.array;
let normals = hasNormals ? attributes.normal.array : null;
let colors = hasColors ? attributes.color.array : null;
let uvs = hasUVs ? attributes.uv.array : null;
let uv1s = hasUV1s ? attributes.uv1.array : null;
let positions2 = positions;
let normals2 = normals;
let colors2 = colors;
let uvs2 = uvs;
let uv1s2 = uv1s;
let iteration = 0;
let tessellating = true;
function addTriangle(a, b, c) {
const v1 = vs[a];
const v2 = vs[b];
const v3 = vs[c];
positions2.push(v1.x, v1.y, v1.z);
positions2.push(v2.x, v2.y, v2.z);
positions2.push(v3.x, v3.y, v3.z);
if (hasNormals) {
const n1 = ns[a];
const n2 = ns[b];
const n3 = ns[c];
normals2.push(n1.x, n1.y, n1.z);
normals2.push(n2.x, n2.y, n2.z);
normals2.push(n3.x, n3.y, n3.z);
}
if (hasColors) {
const c1 = cs[a];
const c2 = cs[b];
const c3 = cs[c];
colors2.push(c1.r, c1.g, c1.b);
colors2.push(c2.r, c2.g, c2.b);
colors2.push(c3.r, c3.g, c3.b);
}
if (hasUVs) {
const u1 = us[a];
const u2 = us[b];
const u3 = us[c];
uvs2.push(u1.x, u1.y);
uvs2.push(u2.x, u2.y);
uvs2.push(u3.x, u3.y);
}
if (hasUV1s) {
const u21 = u2s[a];
const u22 = u2s[b];
const u23 = u2s[c];
uv1s2.push(u21.x, u21.y);
uv1s2.push(u22.x, u22.y);
uv1s2.push(u23.x, u23.y);
}
}
while (tessellating && iteration < maxIterations) {
iteration++;
tessellating = false;
positions = positions2;
positions2 = [];
if (hasNormals) {
normals = normals2;
normals2 = [];
}
if (hasColors) {
colors = colors2;
colors2 = [];
}
if (hasUVs) {
uvs = uvs2;
uvs2 = [];
}
if (hasUV1s) {
uv1s = uv1s2;
uv1s2 = [];
}
for (let i = 0, i2 = 0, il = positions.length; i < il; i += 9, i2 += 6) {
va.fromArray(positions, i + 0);
vb.fromArray(positions, i + 3);
vc.fromArray(positions, i + 6);
if (hasNormals && normals) {
na.fromArray(normals, i + 0);
nb.fromArray(normals, i + 3);
nc.fromArray(normals, i + 6);
}
if (hasColors && colors) {
ca.fromArray(colors, i + 0);
cb.fromArray(colors, i + 3);
cc.fromArray(colors, i + 6);
}
if (hasUVs && uvs) {
ua.fromArray(uvs, i2 + 0);
ub.fromArray(uvs, i2 + 2);
uc.fromArray(uvs, i2 + 4);
}
if (hasUV1s && uv1s) {
u2a.fromArray(uv1s, i2 + 0);
u2b.fromArray(uv1s, i2 + 2);
u2c.fromArray(uv1s, i2 + 4);
}
const dab = va.distanceToSquared(vb);
const dbc = vb.distanceToSquared(vc);
const dac = va.distanceToSquared(vc);
if (dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared) {
tessellating = true;
if (dab >= dbc && dab >= dac) {
vm.lerpVectors(va, vb, 0.5);
if (hasNormals)
nm.lerpVectors(na, nb, 0.5);
if (hasColors)
cm.lerpColors(ca, cb, 0.5);
if (hasUVs)
um.lerpVectors(ua, ub, 0.5);
if (hasUV1s)
u2m.lerpVectors(u2a, u2b, 0.5);
addTriangle(0, 3, 2);
addTriangle(3, 1, 2);
} else if (dbc >= dab && dbc >= dac) {
vm.lerpVectors(vb, vc, 0.5);
if (hasNormals)
nm.lerpVectors(nb, nc, 0.5);
if (hasColors)
cm.lerpColors(cb, cc, 0.5);
if (hasUVs)
um.lerpVectors(ub, uc, 0.5);
if (hasUV1s)
u2m.lerpVectors(u2b, u2c, 0.5);
addTriangle(0, 1, 3);
addTriangle(3, 2, 0);
} else {
vm.lerpVectors(va, vc, 0.5);
if (hasNormals)
nm.lerpVectors(na, nc, 0.5);
if (hasColors)
cm.lerpColors(ca, cc, 0.5);
if (hasUVs)
um.lerpVectors(ua, uc, 0.5);
if (hasUV1s)
u2m.lerpVectors(u2a, u2c, 0.5);
addTriangle(0, 1, 3);
addTriangle(3, 1, 2);
}
} else {
addTriangle(0, 1, 2);
}
}
}
const geometry2 = new BufferGeometry();
geometry2.setAttribute("position", new Float32BufferAttribute(positions2, 3));
if (hasNormals) {
geometry2.setAttribute("normal", new Float32BufferAttribute(normals2, 3));
}
if (hasColors) {
geometry2.setAttribute("color", new Float32BufferAttribute(colors2, 3));
}
if (hasUVs) {
geometry2.setAttribute("uv", new Float32BufferAttribute(uvs2, 2));
}
if (hasUV1s) {
geometry2.setAttribute(UV1, new Float32BufferAttribute(uv1s2, 2));
}
return geometry2;
});
this.maxEdgeLength = maxEdgeLength;
this.maxIterations = maxIterations;
}
}
export {
TessellateModifier
};
//# sourceMappingURL=TessellateModifier.js.map
File diff suppressed because one or more lines are too long