
three.js Procedural Animals là gì?
three.js Procedural Animals là thư viện chứa 24 loài động vật được tạo trong thời gian chạy cho three.js. Thay vì tải xuống mô hình, texture, rig hoặc đoạn hoạt ảnh, bạn gọi createAnimal() và thư viện sẽ dựng một động vật hoàn chỉnh có hoạt ảnh bằng mã.
Mỗi loài động vật được tạo hình từ các trường khoảng cách có dấu, chuyển thành lưới, dựng rig, gắn skin, phủ lông, lông vũ hoặc vảy, rồi được tạo hoạt ảnh bằng dáng đi và hành động dựa trên động học ngược. Các kiểu cơ thể hiện có gồm động vật chân có đệm thịt, động vật móng guốc, chim, động vật bơi, rắn, nhện và động vật bật nhảy.
Bạn có thể khám phá mọi loài, biến thể, hành động và chế độ gỡ lỗi trong bản trình diễn trực tiếp, hoặc xem mã nguồn trong kho GitHub.
Tính năng chính
- 24 loài: Các lựa chọn trải dài từ sói, mèo, ngựa và thỏ đến chim, cá, rắn và nhện.
- Cá thể theo seed: Một seed tạo ra kích thước, tỷ lệ cơ thể, bộ lông, giới tính, độ tuổi và lựa chọn biến thể có thể lặp lại, trừ khi bạn ghi đè chúng.
- Hoạt ảnh trong thời gian chạy: Động vật tự động chọn dáng đi phù hợp và cung cấp các hành động như ngồi, ngủ, ăn, tấn công và nhảy.
- Năm mức chất lượng: Chọn từ
hero,high,medium,lowvàcrowd. - Dựng bằng Worker: Theo mặc định, quá trình dựng chạy trong Web Worker dạng module, với cơ chế dự phòng sang luồng gọi.
- Đóng gói ngoại tuyến: Dựng sẵn một cá thể thành tệp
.animalđể tải trong khoảng 20 mili giây. - Điều khiển hướng đến game: Điều khiển động vật, di chuyển đến đích, bám theo vật thể vật lý, theo dõi mục tiêu, phát hành động và nhận sự kiện gameplay.
- Hỗ trợ TypeScript: Gói sử dụng ES module và bao gồm các khai báo TypeScript.
Cài đặt
Thư viện yêu cầu three.js r160 trở lên làm dependency ngang hàng duy nhất. Cài đặt gói và three.js bằng npm:
npm install procedural-animals threeNếu gói chưa có trên npm, hãy cài đặt trực tiếp từ GitHub:
npm install github:majidmanzarpour/threejs-procedural-animals threeTạo động vật đầu tiên
Bắt đầu bằng cách import three.js và createAnimal. Hàm này là bất đồng bộ vì việc dựng lưới, rig, lớp phủ và dữ liệu liên quan cần thời gian.
import * as THREE from 'three';
import { createAnimal } from 'procedural-animals';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xa9c1e0);
const camera = new THREE.PerspectiveCamera(
40,
innerWidth / innerHeight,
0.1,
500
);
camera.position.set(6, 3, 8);
const sun = new THREE.DirectionalLight(0xfff3e4, 2.7);
sun.position.set(6, 10, 4);
sun.castShadow = true;
scene.add(
sun,
new THREE.HemisphereLight(0xdde6f2, 0x5f5a52, 1.15)
);
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(200, 200).rotateX(-Math.PI / 2),
new THREE.MeshStandardMaterial({ color: 0x77736a })
);
floor.receiveShadow = true;
scene.add(floor);
async function main() {
const wolf = await createAnimal('wolf', {
seed: 3,
quality: 'high'
});
scene.add(wolf.object);
let last = performance.now();
renderer.setAnimationLoop((now) => {
const dt = (now - last) / 1000;
last = now;
wolf.move({
speed: wolf.gears.walk,
heading: now / 1000 * 0.3
});
wolf.update(dt);
camera.lookAt(wolf.position);
renderer.render(scene, camera);
});
}
main();Ví dụ này có một số quy tắc quan trọng:
- Tạo động vật bên trong một hàm
asyncvà await kết quả. - Thêm
animal.objectvào scene, nhưng giữ transform của object đó ở trạng thái identity. Động vật tự quản lý việc di chuyển. - Sử dụng các phương thức như
move(),moveTo()hoặcfollow()để điều khiển hướng di chuyển. - Gọi
update(dt)chính xác một lần mỗi frame, vớidtđược đo bằng giây. - Sử dụng tốc độ từ
animal.gearsvì tên gear khả dụng có thể khác nhau tùy loài.
Tránh dùng
awaitở cấp cao nhất trong module entry. Theo tài liệu dự án, điều này có thể khiến bản build production của Vite bị deadlock.
Di chuyển và điều hướng
Điều khiển trực tiếp
Phương thức move() nhận tốc độ tính bằng mét trên giây và hướng tính bằng radian. Hướng 0 quay về trục Z dương.
wolf.move({
speed: wolf.gears.walk,
heading: Math.PI / 2
});Gọi stop() khi muốn động vật dừng di chuyển:
wolf.stop();Di chuyển đến đích
Sử dụng moveTo() để đưa động vật đến một điểm trong không gian thế giới. Phương thức này phát sự kiện arrive sau khi đến đích.
wolf.moveTo(
new THREE.Vector3(10, 0, 4),
{ speed: 3 }
);
wolf.on('arrive', () => {
console.log('The wolf arrived.');
});Bám theo vật thể vật lý
Nếu một hệ thống khác điều khiển một vật thể, hãy truyền vị trí và vận tốc hiện tại của vật thể đó vào follow() mỗi frame:
wolf.follow(body.position, body.velocity);Theo dõi mục tiêu
Yêu cầu động vật quay đầu về phía mục tiêu bằng lookAt(). Truyền null để dừng theo dõi.
wolf.lookAt(player.position);
// Later:
wolf.lookAt(null);Các hành động chơi
Mọi loài đều hỗ trợ các hành động chung jump, sit, lie, sleep, eat, drink, attack, hit, death và stand. Các loài cũng có thể cung cấp những hành động chuyên biệt. Ví dụ, rắn có thể cuộn mình và tấn công, chim có thể cất cánh và hạ cánh, còn thỏ có thể nhảy và dậm chân.
Phương thức play() trả về một Promise với kết quả có thể là done, interrupted, stopped hoặc refused.
const result = await wolf.play('attack');
console.log(result);Hãy kiểm tra animal.actions thay vì giả định rằng một loài hỗ trợ hành động chuyên biệt nào đó. Bạn có thể dừng một hành động được chỉ định tên bằng stopAction():
wolf.stopAction('attack');Phản hồi các sự kiện của động vật
API sự kiện cho phép các hệ thống trò chơi phản hồi animation và chuyển động. Các sự kiện khả dụng gồm footstep, attackHit, actionStart, actionEnd, arrive, takeoff, land, death, vocalize và wingbeat.
const onFootstep = (event) => {
sfx.play('step', event.position, event.strength);
};
wolf.on('footstep', onFootstep);
wolf.on('attackHit', (event) => {
damage(event.position, event.direction);
});
// Remove a listener when it is no longer needed.
wolf.off('footstep', onFootstep);Cấu hình địa hình và nước
Tùy chọn ground là một hàm trả về độ cao địa hình tại tọa độ X và Z. Tọa độ của hàm phải nằm trong không gian của animal.object.parent, và độ cao trả về phải khớp với địa hình được hiển thị trong cảnh.
const deer = await createAnimal('deer', {
ground: (x, z) => terrainHeightAt(x, z),
position: new THREE.Vector3(4, 0, 8),
heading: Math.PI
});Động vật bơi cần một hàm water và vị trí khởi đầu bên dưới mặt nước. Hàm này trả về độ cao mặt nước hoặc null tại nơi không có nước.
const fish = await createAnimal('fish', {
water: (x, z) => 2,
position: new THREE.Vector3(0, 1, 0)
});
scene.add(fish.object);Động vật trên cạn cũng có thể sử dụng định nghĩa nước để uống và lội nước. Chim có thể nhận một mảng perches chứa các điểm THREE.Vector3 mà chúng có thể bay tới.
Chọn loài, biến thể và cá thể
Thư viện bao gồm chó sói, chó, cáo, mèo, sư tử, báo săn, gấu, chuột, thỏ, ngựa, hươu, bò, lợn, cừu, dê, lợn rừng, ếch, gà, quạ, đại bàng, cá, cá mập, rắn và nhện.
Dùng seed để tạo một cá thể có thể tái lập. Bạn cũng có thể chọn rõ biến thể, giới tính hoặc độ tuổi:
const cat = await createAnimal('cat', {
seed: 12,
quality: 'high',
variant: 'tuxedo',
sex: 'female',
age: 'adult'
});Các mã định danh loài dạng chuỗi được tải theo yêu cầu. Nếu ứng dụng chỉ cần một loài, hãy import trực tiếp loài đó để giữ bundle gọn hơn:
import wolfSpecies from 'procedural-animals/species/wolf';
import { createAnimal } from 'procedural-animals';
const wolf = await createAnimal(wolfSpecies, {
seed: 3
});Chọn cấp chất lượng phù hợp
- hero: Khoảng 110.000 đến 130.000 đỉnh cho các cảnh cận điện ảnh.
- high: Khoảng 65.000 đến 80.000 đỉnh cho động vật của người chơi. Đây là mặc định.
- medium: Khoảng 25.000 đến 32.000 đỉnh cho góc nhìn trung và điện thoại.
- low: Khoảng 11.000 đến 15.000 đỉnh cho đàn khoảng 10 đến 20 con.
- crowd: Khoảng 5.000 đến 8.000 đỉnh cho đám đông khoảng 100 con, với một lệnh vẽ.
Bạn có thể thay đổi độ chi tiết bộ lông trên mesh hiện có bằng setQuality(). Với các đám đông lớn, hãy kết hợp cấp crowd với setLod(2) để giảm độ chi tiết chuyển động:
const sheep = await createAnimal('sheep', {
seed: 5,
quality: 'crowd'
});
sheep.setLod(2);Kết quả build được lưu vào bộ nhớ đệm theo loài, seed, chất lượng và biến thể. Vì vậy, một đàn 100 con sử dụng sáu seed chỉ cần sáu bản build riêng biệt. Chi phí CPU được ghi nhận là khoảng 0,1 mili giây cho mỗi con mỗi khung hình.
Cấu hình Web Worker
Quá trình build động vật mất khoảng 0,4 đến 6 giây. Theo mặc định, việc khởi tạo chạy trong các Web Worker dạng module. Nếu Worker không khả dụng, thư viện sẽ chuyển sang luồng gọi.
Cấu hình Vite
// vite.config.js
export default {
worker: { format: 'es' },
build: { target: 'es2022' },
optimizeDeps: {
exclude: ['procedural-animals']
}
};webpack 5 và Parcel 2 không yêu cầu cấu hình worker bổ sung.
Các bundler khác
Với bundler khác, hãy tự bundle worker:
npx esbuild node_modules/procedural-animals/src/worker.js --bundle --format=iife --minify --outfile=public/animal-worker.jsSau đó đăng ký một factory tạo worker:
import { setWorkerFactory } from 'procedural-animals';
setWorkerFactory(
() => new Worker('/animal-worker.js')
);Bạn có thể tắt việc build bằng worker cho một động vật cụ thể, nhưng thao tác này sẽ chặn luồng gọi trong suốt thời gian build:
const wolf = await createAnimal('wolf', {
worker: false
});Đóng gói sẵn động vật để tải nhanh
Đối với một cá thể đã biết, hãy dựng sẵn nó thành tệp .animal. Việc này thay thế độ trễ dựng lúc chạy bằng thao tác tải tệp, được README ước tính mất khoảng 20 mili giây.
npx procedural-animals-bake wolf --seed 3 --quality high -o public/wolf-3.animalTải tệp đã tạo dưới dạng ArrayBuffer và truyền tệp đó qua tùy chọn baked:
const wolf = await createAnimal('wolf', {
baked: fetch('/wolf-3.animal')
.then((response) => response.arrayBuffer())
});Cá thể đã dựng sẵn phải tương ứng với loài và cấu hình được chuẩn bị bởi lệnh.
Mẹo nâng cao
Sử dụng trạng thái chuyển động chỉ đọc
Đọc position, heading, speed, velocity và state để điều phối camera, gameplay hoặc giao diện. Không thao tác với đối tượng gốc của động vật để tạo chuyển động.
Gắn đối tượng phụ vào các điểm được đặt tên
Tập hợp attachments cung cấp các điểm như mouth, head và back. Chim cũng cung cấp các điểm gắn ở chân, còn ngựa có các điểm liên quan đến cưỡi, bao gồm seat, bàn đạp và hàm thiếc. Hãy gắn các đối tượng phụ vào những đối tượng điểm gắn này thay vì tự ước tính vị trí đang chuyển động của chúng.
Sử dụng các tùy chọn gỡ lỗi và lớp phủ
API động vật bao gồm setDebug(mode, on) với các chế độ albedo, weights, material và bare. Sử dụng setCoverings(on) để bật hoặc tắt các lớp lông.
wolf.setDebug('weights', true);
wolf.setCoverings(false);Tính hướng về một điểm
Vì hướng bằng 0 quay về Z dương, hãy sử dụng Math.atan2(dx, dz) khi tính hướng tới mục tiêu:
const dx = target.x - wolf.position.x;
const dz = target.z - wolf.position.z;
const heading = Math.atan2(dx, dz);
wolf.move({
speed: wolf.gears.walk,
heading
});Dọn dẹp tài nguyên
Gọi dispose() khi một động vật bị xóa vĩnh viễn. Thao tác này giải phóng tài nguyên GPU của nó và xóa nó khỏi cảnh.
wolf.dispose();Các export và tài liệu hữu ích
Gói chính cũng export listSpecies, loadSpecies, setWorkerFactory, clearBuildCache và QUALITY:
import {
createAnimal,
listSpecies,
loadSpecies,
setWorkerFactory,
clearBuildCache,
QUALITY
} from 'procedural-animals';Để biết mọi tùy chọn, payload sự kiện, trường trạng thái và công thức, hãy tham khảo tài liệu tham khảo đầy đủ và khai báo TypeScript của kho lưu trữ.
Kết luận
three.js Procedural Animals cung cấp cách tiếp cận ưu tiên mã nguồn để thêm các loài động vật hoang dã đa dạng, có khung xương và hoạt ảnh vào ứng dụng three.js. Hãy bắt đầu với createAnimal(), thêm đối tượng được trả về vào cảnh, điều khiển nó thông qua API động vật và cập nhật một lần mỗi khung hình. Worker, tính năng dựng sẵn, bộ nhớ đệm theo seed và nhiều cấp chất lượng cho phép cùng một quy trình hỗ trợ cả cận cảnh chi tiết lẫn đám đông quy mô lớn.
