three-zoo
v0.13.0
Published
Some reusable bits for building things with Three.js
Maintainers
Readme
Installation
npm install three-zooContents
- IK -
TwoBoneIK,AimChainIK - Instanced Mesh Pool -
InstancedMeshPool,InstancedMeshInstance,InstancedMeshGroup - Lighting -
Sun,SkyLight - Material Converters - Standard to Basic / Lambert / Phong / Toon / Physical, Basic to Physical
- Miscellaneous -
DualFovCamera,SceneTraversal,SceneSorter,SkinnedMeshBaker
IK
TwoBoneIK
Analytical two-bone IK solver. Chain: root -> middle -> end. Pole controls bend direction. Writes local quaternions to root and middle.
const twoBoneIK = new TwoBoneIK(upperArm, foreArm, hand, poleObject, targetObject);
// call after AnimationMixer.update() each frame
twoBoneIK.solve();
// tune pole twist per bone
twoBoneIK.rootPoleAxis.set(0, 1, 0);
twoBoneIK.middlePoleTwist = false;AimChainIK
Distributes aim rotation across a bone chain according to per-bone weights.
const aimChainIK = new AimChainIK([spine1, spine2, spine3, head]);
aimChainIK.curve = [0.2, 0.5, 0.8, 1.0]; // root gets least, tip gets most
aimChainIK.weight = 0.8; // global blend
// sample directions before calling - mutates bone quaternions
aimChainIK.solve(currentForward, targetDirection);Instanced Mesh Pool
Manages InstancedMesh instances keyed by geometry+material. Grows capacity automatically.
const pool = new InstancedMeshPool(scene, { initialCapacity: 32, capacityStep: 16 });
// allocate / update / release individual instances
const instance = new InstancedMeshInstance(pool, geometry, material);
instance.setPosition3f(1, 0, 0).setScale3f(2, 2, 2).flushTransform();
instance.destroy();
// group multiple instances under a shared Object3D transform
const group = new InstancedMeshGroup([instanceA, instanceB]);
scene.add(group);
group.position.set(10, 0, 0);
group.flushTransform(); // propagates group world matrix to all instances
group.destroy();Lighting
Sun
DirectionalLight with spherical positioning and shadow auto-configuration.
const sun = new Sun();
sun.elevation = Math.PI / 4;
sun.azimuth = Math.PI / 2;
sun.distance = 100;
sun.configureShadowsForBoundingBox(sceneBounds);
sun.setDirectionFromHDRTexture(hdrTexture, 50);SkyLight
HemisphereLight that extracts sky and ground colors from an HDR environment map.
const skyLight = new SkyLight();
skyLight.setColorsFromHDRTexture(hdrTexture, {
skySampleCount: 100,
groundSampleCount: 100,
});Material Converters
All converters expose a single static convert(material, options?). Common options:
| Option | Default | Description |
|------------------|---------|--------------------------------------|
| preserveName | true | Copy .name to the new material |
| copyUserData | true | Copy .userData |
| disposeOriginal| false | Dispose source material after conversion |
// Standard -> unlit
const basicMaterial = StandardToBasicConverter.convert(standardMaterial, { brightnessFactor: 1.3, combineEmissive: true });
// Standard -> diffuse-only lit
const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);
const phongMaterial = StandardToPhongConverter.convert(standardMaterial);
const toonMaterial = StandardToToonConverter.convert(standardMaterial);
// Standard <-> Physical
const physicalMaterial = StandardToPhysicalConverter.convert(standardMaterial);
const standardMaterial2 = BasicToPhysicalConverter.convert(basicMaterial);Miscellaneous
DualFovCamera
PerspectiveCamera with independent horizontal and vertical FOV.
const camera = new DualFovCamera(90, 60);
camera.horizontalFov = 100;
camera.verticalFov = 70;
camera.fitVerticalFovToPoints(vertices);
camera.fitVerticalFovToBox(boundingBox);
camera.fitVerticalFovToMesh(skinnedMesh);
camera.lookAtMeshCenterOfMass(skinnedMesh);SceneTraversal
Static helpers for depth-first scene graph traversal.
// find by name
const playerObject = SceneTraversal.getObjectByName(scene, 'Player');
const metalMaterial = SceneTraversal.getMaterialByName(scene, 'Metal');
// filter by regex or predicate
const enemies = SceneTraversal.filterObjects(scene, /^enemy_/);
const glassMaterials = SceneTraversal.filterMaterials(scene, /glass/i);
// enumerate with callback
SceneTraversal.enumerateMaterials(scene, (material) => {
material.needsUpdate = true;
});
// find meshes that use specific materials
const glassMeshes = SceneTraversal.findMaterialUsers(scene, glassMaterials);SceneSorter
Assigns sequential renderOrder values sorted by distance to a point. Useful for transparent meshes.
// front-to-back
SceneSorter.sortByDistanceToPoint(object, cameraPosition, 0);
// back-to-front (transparent objects)
SceneSorter.sortByDistanceToPoint(object, cameraPosition, 0, true);SkinnedMeshBaker
Bakes a SkinnedMesh to static geometry.
// current pose
const staticMesh = SkinnedMeshBaker.bakePose(skinnedMesh);
// specific animation frame
const frameMesh = SkinnedMeshBaker.bakeAnimationFrame(armature, skinnedMesh, 1.5, animationClip);Requirements
three>=0.157.0 <0.180.0 (peer dependency)
License
MIT © jango
