スキル一覧に戻る
MasatoMakino

fastedgesgeometry-architecture

by MasatoMakino

Mesh and Edge lines in three.js that can change color after geometry is merged

0🍴 0📅 2026年1月22日
GitHubで見るManusで実行

SKILL.md


name: fastedgesgeometry-architecture description: Architecture and implementation details of FastEdgesGeometry. Use when modifying FastEdgesGeometry, understanding its optimization techniques, or debugging edge generation issues.

FastEdgesGeometry Architecture

Background

FastEdgesGeometry is a performance-optimized fork of Three.js EdgesGeometry. The original EdgesGeometry had performance issues with complex geometries, leading to the creation of this optimized version.

File: src/FastEdgesGeometry.ts

Evolution History

Stage 1: Three.js EdgesGeometry (Original)

Standard Three.js EdgesGeometry implementation:

AspectImplementation
Edge hashString concatenation: "x,y,z" format (4 decimal precision)
Edge storageObject with string keys: "hash0_hash1"
Normal calculationTriangle.getNormal() method
Vertex accumulationArray.push()

Problem: String hash generation and object key lookup are slow

Stage 2: FastEdgesGeometry (v0.7.3, 2024-11)

Replaced string hash with numeric hash:

AspectImplementation
Edge hashNumeric hash via hybridtaus() (Tausworthe algorithm)
Edge storageMap<number, {index0, index1, normal}>
Normal calculationTriangle.getNormal() method (unchanged)
Vertex accumulationArray.push() (unchanged)

Improvement: Numeric hash speeds up edge lookup (~3-4x faster) Remaining issues: Function call overhead, object allocation, dynamic arrays

Stage 3: FastEdgesGeometry (v0.7.4+, 2026-01)

Applied further optimizations:

AspectImplementation
Edge hashInline computeHash() with pre-transformed seed
Edge storageParallel Typed Arrays (Uint32Array, Float32Array)
Normal calculationDirect cross product calculation
Vertex accumulationPre-allocated Float32Array with index tracking

Improvement: Function inlining, Typed Arrays, object allocation avoidance (~30% faster)

Optimization Mapping

Stage 2 → Stage 3 Optimization Details

Stage 2 (v0.7.3)Stage 3 (v0.7.4+)Rationale
Triangle class with getNormal()Direct cross product calculationAvoid method call overhead and object property access
Map<hash, {index0, index1, normal}>Parallel Typed Arrays (Uint32Array, Float32Array)Reduce object allocation and GC pressure
vertices.push() dynamic arrayPre-allocated Float32Array with final slice()Avoid array resize operations
hybridtaus() function callsInline hash computationEliminate function call stack overhead
options?.seed access in loopPre-transformed seed constantAvoid repeated optional chaining
Triangle object for vertex accessDirect Vector3 variables (_a, _b, _c)Eliminate object property lookup

Code Structure Mapping

OperationThree.js EdgesGeometryFastEdges (v0.7.3)FastEdges (v0.7.4+)
Hash generation"x,y,z" stringhybridtaus(x,y,z)computeHash(x,y,z) inline
Normal calculationtriangle.getNormal(normal)triangle.getNormal(normal)direct cross product
Edge storageedgeData["hash"] = objedgeData.set(hash, obj)typed arrays[slot]
Vertex accumulationvertices.push(...)vertices.push(...)vertexBuffer[writeIndex++]

Inline Hash Function

The computeHash() function (lines 94-100) is an inline expansion of hybridtaus():

// hybridtaus() static method (preserved for public API):
static hybridtaus(x, y, z, seed = 255) {
  x = FastEdgesGeometry.taus(x, 13, 19, 12, 0xfffffffe);
  y = FastEdgesGeometry.taus(y, 2, 25, 4, 0xfffffff8);
  z = FastEdgesGeometry.taus(z, 3, 11, 17, 0xfffffff0);
  seed = u32(seed * 1664525 + 1013904223);
  return u32(x ^ y ^ z ^ seed);
}

// Inlined as computeHash() with pre-transformed seed:
const transformedSeed = (seed * 1664525 + 1013904223) >>> 0;
const computeHash = (x, y, z) => {
  x = (((x & 0xfffffffe) << 13) ^ (((x << 19) ^ x) >>> 12)) >>> 0;
  y = (((y & 0xfffffff8) << 2) ^ (((y << 25) ^ y) >>> 4)) >>> 0;
  z = (((z & 0xfffffff0) << 3) ^ (((z << 11) ^ z) >>> 17)) >>> 0;
  return (x ^ y ^ z ^ transformedSeed) >>> 0;
};

The magic numbers (0xfffffffe, 0xfffffff8, 0xfffffff0) and bit shifts come from the Tausworthe random number generator algorithm (GPU Gems 3, Chapter 37).

Performance Results

Benchmark comparison (Chrome, macOS):

GeometryTrianglesEdgesGeometryFastEdges (old)FastEdges (new)Speedup
SphereGeometry(32,32)1,9844.40ms1.20ms0.90ms4.9x vs original
TorusKnot(200,32)12,80028.40ms6.50ms5.00ms5.7x vs original
TorusKnot(400,64)51,200134.40ms28.70ms21.80ms6.2x vs original

Optimization Principles Applied

  1. Inline function calls - Eliminate call stack overhead in hot loops
  2. Pre-allocate fixed arrays - Replace dynamic push() with typed array indexing
  3. Avoid high-level abstractions - Use primitives instead of objects/classes
  4. Pre-compute constants - Move invariant calculations outside loops

Trade-offs

  • Readability: Code is more complex and harder to understand
  • Maintainability: Changes require understanding the optimization mapping
  • Justification: Edge geometry generation directly impacts user experience (frame drops during scene initialization)

Future Optimization Considerations

If further optimization is needed:

  • WebGPU Compute Shader (parallel processing on GPU)
  • Web Workers (limited benefit due to data transfer overhead)
  • Only practical for geometries with 100k+ triangles

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です