
three.js Procedural Animals কী?
three.js Procedural Animals হলো three.js-এর জন্য রানটাইমে তৈরি করা ২৪টি প্রাণীসমৃদ্ধ একটি লাইব্রেরি। মডেল, টেক্সচার, রিগ বা অ্যানিমেশন ক্লিপ ডাউনলোড করার বদলে আপনি createAnimal() কল করেন, আর লাইব্রেরি কোডের মাধ্যমে একটি সম্পূর্ণ অ্যানিমেটেড প্রাণী তৈরি করে।
প্রতিটি প্রাণী signed distance field থেকে তৈরি, মেশ করা, রিগ করা, স্কিন করা এবং লোম, পালক বা আঁশে আবৃত। এরপর inverse-kinematics গেইট ও অ্যাকশনের মাধ্যমে অ্যানিমেট করা হয়। এতে থাবাযুক্ত প্রাণী, খুরওয়ালা প্রাণী, পাখি, জলজ প্রাণী, সাপ, মাকড়সা ও লাফানো প্রাণীসহ বিভিন্ন ধরনের দেহগঠন রয়েছে।
আপনি লাইভ শোকেসে প্রতিটি প্রজাতি, ভ্যারিয়েন্ট, অ্যাকশন ও ডিবাগ ভিউ দেখতে পারেন, অথবা GitHub রিপোজিটরিতে সোর্স পরিদর্শন করতে পারেন।
প্রধান বৈশিষ্ট্য
- ২৪টি প্রজাতি: নেকড়ে, বিড়াল, ঘোড়া ও খরগোশ থেকে শুরু করে পাখি, মাছ, সাপ ও মাকড়সা পর্যন্ত বিভিন্ন বিকল্প রয়েছে।
- সিড-নির্ভর পৃথক প্রাণী: আপনি আলাদাভাবে পরিবর্তন না করলে একটি সিড থেকে পুনরাবৃত্তিযোগ্য আকার, অনুপাত, আবরণ, লিঙ্গ, বয়স ও ভ্যারিয়েন্ট তৈরি হয়।
- রানটাইম অ্যানিমেশন: প্রাণীরা স্বয়ংক্রিয়ভাবে উপযুক্ত গেইট বেছে নেয় এবং বসা, ঘুমানো, খাওয়া, আক্রমণ ও লাফানোর মতো অ্যাকশন প্রকাশ করে।
- পাঁচটি গুণমান স্তর:
hero,high,medium,lowওcrowdথেকে বেছে নিন। - ওয়ার্কার-ভিত্তিক নির্মাণ: ডিফল্টভাবে মডিউল Web Worker-এ নির্মাণ সম্পন্ন হয়, তবে প্রয়োজনে কলকারী থ্রেডে fallback থাকে।
- অফলাইন বেকিং: প্রায় ২০ মিলিসেকেন্ডে লোড করার জন্য একটি প্রাণীকে
.animalফাইল হিসেবে আগে থেকেই তৈরি করুন। - গেম-কেন্দ্রিক নিয়ন্ত্রণ: প্রাণী চালান, গন্তব্যে পাঠান, ফিজিক্স বডি অনুসরণ করান, লক্ষ্য ট্র্যাক করুন, অ্যাকশন চালান এবং গেমপ্লে ইভেন্ট গ্রহণ করুন।
- TypeScript সমর্থন: প্যাকেজটি ES মডিউল ব্যবহার করে এবং TypeScript declaration অন্তর্ভুক্ত করে।
ইনস্টলেশন
লাইব্রেরিটির একমাত্র peer dependency হিসেবে three.js r160 বা পরবর্তী সংস্করণ প্রয়োজন। npm দিয়ে প্যাকেজ ও three.js ইনস্টল করুন:
npm install procedural-animals threeপ্যাকেজটি npm-এ এখনও উপলভ্য না হলে সরাসরি GitHub থেকে ইনস্টল করুন:
npm install github:majidmanzarpour/threejs-procedural-animals threeআপনার প্রথম প্রাণী তৈরি করুন
প্রথমে three.js এবং createAnimal ইমপোর্ট করুন। মেশ, রিগ, আবরণ ও সংশ্লিষ্ট ডেটা তৈরি করতে সময় লাগে বলে ফাংশনটি asynchronous।
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();এই উদাহরণে কয়েকটি গুরুত্বপূর্ণ নিয়ম রয়েছে:
- একটি
asyncফাংশনের ভেতরে প্রাণী তৈরি করুন এবং ফলাফলের জন্য await করুন। animal.object-কে scene-এ যোগ করুন, তবে ওই অবজেক্টের transform identity অবস্থায় রাখুন। প্রাণীটি নিজেই তার চলাচল নিয়ন্ত্রণ করে।- এটি পরিচালনা করতে
move(),moveTo()বাfollow()-এর মতো মেথড ব্যবহার করুন। - প্রতি ফ্রেমে ঠিক একবার
update(dt)কল করুন, যেখানেdtসেকেন্ডে মাপা হবে। animal.gearsথেকে গতি ব্যবহার করুন, কারণ প্রজাতিভেদে উপলভ্য gear-এর নাম ভিন্ন হতে পারে।
Entry module-এ top-level
awaitব্যবহার এড়িয়ে চলুন। প্রকল্পের ডকুমেন্টেশন অনুযায়ী, এটি Vite production build-এ deadlock তৈরি করতে পারে।
চলাচল ও নেভিগেশন
সরাসরি নিয়ন্ত্রণ
move() মেথডটি প্রতি সেকেন্ডে মিটারে গতি এবং রেডিয়ানে heading গ্রহণ করে। 0 heading হলে প্রাণীটি ধনাত্মক Z অক্ষের দিকে মুখ করে।
wolf.move({
speed: wolf.gears.walk,
heading: Math.PI / 2
});প্রাণীকে থামাতে stop() কল করুন:
wolf.stop();গন্তব্যে যাওয়া
কোনো প্রাণীকে world-space বিন্দুর দিকে পাঠাতে moveTo() ব্যবহার করুন। গন্তব্যে পৌঁছানোর পর এটি একটি arrive ইভেন্ট পাঠায়।
wolf.moveTo(
new THREE.Vector3(10, 0, 4),
{ speed: 3 }
);
wolf.on('arrive', () => {
console.log('The wolf arrived.');
});ফিজিক্স বডি অনুসরণ
অন্য কোনো সিস্টেম যদি একটি বডি নিয়ন্ত্রণ করে, প্রতি ফ্রেমে তার বর্তমান অবস্থান ও velocity follow()-এ পাঠান:
wolf.follow(body.position, body.velocity);লক্ষ্য ট্র্যাক করা
lookAt() দিয়ে প্রাণীটির মাথা কোনো লক্ষ্যের দিকে ঘোরান। ট্র্যাকিং বন্ধ করতে null পাঠান।
wolf.lookAt(player.position);
// পরে:
wolf.lookAt(null);প্লে অ্যাকশন
প্রতিটি প্রজাতি সাধারণ jump, sit, lie, sleep, eat, drink, attack, hit, death এবং stand অ্যাকশন সমর্থন করে। প্রজাতিগুলো বিশেষায়িত অ্যাকশনও প্রদান করতে পারে। উদাহরণস্বরূপ, সাপ কুণ্ডলী পাকিয়ে আঘাত করতে পারে, পাখি উড়তে ও অবতরণ করতে পারে এবং খরগোশ লাফিয়ে পা ঠুকতে পারে।
play() মেথড একটি Promise রিটার্ন করে, যার ফলাফল done, interrupted, stopped অথবা refused হতে পারে।
const result = await wolf.play('attack');
console.log(result);কোনো প্রজাতি বিশেষায়িত অ্যাকশন সমর্থন করে ধরে নেওয়ার বদলে animal.actions পরিদর্শন করুন। stopAction() ব্যবহার করে নামযুক্ত কোনো অ্যাকশন থামাতে পারেন:
wolf.stopAction('attack');প্রাণীর ইভেন্টে প্রতিক্রিয়া
ইভেন্ট API অ্যানিমেশন ও চলাচলে গেম সিস্টেমকে প্রতিক্রিয়া জানাতে দেয়। উপলভ্য ইভেন্টগুলোর মধ্যে রয়েছে footstep, attackHit, actionStart, actionEnd, arrive, takeoff, land, death, vocalize এবং wingbeat।
const onFootstep = (event) => {
sfx.play('step', event.position, event.strength);
};
wolf.on('footstep', onFootstep);
wolf.on('attackHit', (event) => {
damage(event.position, event.direction);
});
// আর প্রয়োজন না থাকলে একটি লিসেনার সরান।
wolf.off('footstep', onFootstep);ভূখণ্ড ও পানি কনফিগার করুন
ground অপশনটি এমন একটি ফাংশন, যা X ও Z কোঅর্ডিনেটের জন্য ভূখণ্ডের উচ্চতা রিটার্ন করে। এর কোঅর্ডিনেট অবশ্যই animal.object.parent-এর স্পেসে হতে হবে এবং রিটার্ন করা উচ্চতা অবশ্যই দৃশ্যে রেন্ডার করা ভূখণ্ডের সঙ্গে সামঞ্জস্যপূর্ণ হতে হবে।
const deer = await createAnimal('deer', {
ground: (x, z) => terrainHeightAt(x, z),
position: new THREE.Vector3(4, 0, 8),
heading: Math.PI
});সাঁতার কাটে এমন প্রাণীর জন্য water ফাংশন এবং পানির পৃষ্ঠের নিচে একটি শুরুর অবস্থান প্রয়োজন। পানি থাকলে ফাংশনটি পানির পৃষ্ঠের উচ্চতা রিটার্ন করে, আর পানি না থাকলে null রিটার্ন করে।
const fish = await createAnimal('fish', {
water: (x, z) => 2,
position: new THREE.Vector3(0, 1, 0)
});
scene.add(fish.object);স্থলচর প্রাণীরাও পান করার ও পানিতে হাঁটার জন্য পানির সংজ্ঞা ব্যবহার করতে পারে। পাখিদের perches অ্যারে দেওয়া যেতে পারে, যাতে তারা উড়ে যেতে পারে এমন THREE.Vector3 পয়েন্ট থাকে।
প্রজাতি, ভ্যারিয়েন্ট ও স্বতন্ত্র প্রাণী নির্বাচন
লাইব্রেরিতে নেকড়ে, কুকুর, শিয়াল, বিড়াল, সিংহ, চিতা, ভালুক, ইঁদুর, খরগোশ, ঘোড়া, হরিণ, গরু, শূকর, ভেড়া, ছাগল, বুনো শূকর, ব্যাঙ, মুরগি, কাক, ঈগল, মাছ, হাঙর, সাপ এবং মাকড়সা অন্তর্ভুক্ত রয়েছে।
পুনরাবৃত্তিযোগ্য স্বতন্ত্র প্রাণী তৈরি করতে seed ব্যবহার করুন। এর ভ্যারিয়েন্ট, লিঙ্গ বা বয়সও স্পষ্টভাবে নির্বাচন করতে পারেন:
const cat = await createAnimal('cat', {
seed: 12,
quality: 'high',
variant: 'tuxedo',
sex: 'female',
age: 'adult'
});স্ট্রিং প্রজাতি আইডেন্টিফায়ার প্রয়োজনের সময় লোড করা হয়। কোনো অ্যাপ্লিকেশনের যদি কেবল একটি প্রজাতি প্রয়োজন হয়, তাহলে বান্ডেলকে কেন্দ্রীভূত রাখতে সেই প্রজাতিটি সরাসরি ইমপোর্ট করুন:
import wolfSpecies from 'procedural-animals/species/wolf';
import { createAnimal } from 'procedural-animals';
const wolf = await createAnimal(wolfSpecies, {
seed: 3
});সঠিক কোয়ালিটি স্তর নির্বাচন
- hero: সিনেমাটিক ক্লোজ-আপের জন্য প্রায় 110,000 থেকে 130,000টি ভার্টেক্স।
- high: প্লেয়ারের প্রাণীর জন্য প্রায় 65,000 থেকে 80,000টি ভার্টেক্স। এটিই ডিফল্ট।
- medium: মাঝারি দূরত্বের দৃশ্য ও ফোনের জন্য প্রায় 25,000 থেকে 32,000টি ভার্টেক্স।
- low: প্রায় 10 থেকে 20টি প্রাণীর পাল বা দলের জন্য প্রায় 11,000 থেকে 15,000টি ভার্টেক্স।
- crowd: প্রায় 100টি প্রাণীর ভিড়ের জন্য প্রায় 5,000 থেকে 8,000টি ভার্টেক্স, একটি ড্র কলসহ।
setQuality() ব্যবহার করে বিদ্যমান মেশে কোটের ডিটেইল পরিবর্তন করতে পারেন। বড় ভিড়ের ক্ষেত্রে crowd স্তরের সঙ্গে setLod(2) ব্যবহার করে চলনের ডিটেইল কমান:
const sheep = await createAnimal('sheep', {
seed: 5,
quality: 'crowd'
});
sheep.setLod(2);বিল্ডের ফলাফল প্রজাতি, seed, কোয়ালিটি ও ভ্যারিয়েন্ট অনুযায়ী ক্যাশ করা হয়। তাই ছয়টি seed ব্যবহার করা 100টি প্রাণীর একটি পালের জন্য মাত্র ছয়টি স্বতন্ত্র বিল্ড প্রয়োজন। নথিভুক্ত CPU খরচ প্রতি ফ্রেমে প্রতি প্রাণীর জন্য প্রায় 0.1 মিলিসেকেন্ড।
Web Worker কনফিগার করুন
প্রাণীর বিল্ডে প্রায় 0.4 থেকে 6 সেকেন্ড সময় লাগে। ডিফল্টভাবে, নির্মাণ মডিউল Web Worker-এ চলে। Worker উপলভ্য না হলে লাইব্রেরি কলিং থ্রেডে ফিরে যায়।
Vite কনফিগারেশন
// vite.config.js
export default {
worker: { format: 'es' },
build: { target: 'es2022' },
optimizeDeps: {
exclude: ['procedural-animals']
}
};webpack 5 ও Parcel 2-এর জন্য অতিরিক্ত worker কনফিগারেশনের প্রয়োজন নেই।
অন্যান্য বান্ডলার
অন্য কোনো বান্ডলারের জন্য worker-টি ম্যানুয়ালি বান্ডেল করুন:
npx esbuild node_modules/procedural-animals/src/worker.js --bundle --format=iife --minify --outfile=public/animal-worker.jsতারপর worker তৈরি করে এমন একটি factory রেজিস্টার করুন:
import { setWorkerFactory } from 'procedural-animals';
setWorkerFactory(
() => new Worker('/animal-worker.js')
);নির্দিষ্ট কোনো প্রাণীর জন্য worker নির্মাণ নিষ্ক্রিয় করতে পারেন, তবে এতে বিল্ড চলাকালীন কলিং থ্রেডটি আটকে থাকবে:
const wolf = await createAnimal('wolf', {
worker: false
});দ্রুত লোডিংয়ের জন্য প্রাণী প্রি-বিল্ড করুন
কোনো নির্দিষ্ট ব্যক্তির জন্য সেটিকে আগে থেকেই একটি .animal ফাইলে বেক করে রাখুন। এতে রানটাইম বিল্ডের বিলম্বের পরিবর্তে ফাইল লোড হবে, যা README অনুযায়ী প্রায় 20 মিলিসেকেন্ড সময় নেয়।
npx procedural-animals-bake wolf --seed 3 --quality high -o public/wolf-3.animalতৈরি করা ফাইলটি ArrayBuffer হিসেবে আনুন এবং baked অপশনের মাধ্যমে পাঠান:
const wolf = await createAnimal('wolf', {
baked: fetch('/wolf-3.animal')
.then((response) => response.arrayBuffer())
});বেক করা ব্যক্তিটির প্রজাতি এবং কমান্ডের মাধ্যমে প্রস্তুত করা কনফিগারেশনের সঙ্গে সামঞ্জস্য থাকা উচিত।
উন্নত টিপস
শুধু-পাঠযোগ্য গতির অবস্থা ব্যবহার করুন
ক্যামেরা, গেমপ্লে বা ইন্টারফেস সমন্বয় করতে position, heading, speed, velocity এবং state পড়ুন। চলন তৈরি করতে প্রাণীটির রুট অবজেক্ট পরিবর্তন করবেন না।
নামযুক্ত পয়েন্টে প্রপস সংযুক্ত করুন
attachments সংগ্রহে mouth, head এবং back-এর মতো পয়েন্ট রয়েছে। পাখিদের ক্ষেত্রে পায়ের অ্যাটাচমেন্টও থাকে, আর ঘোড়ার ক্ষেত্রে seat, stirrups এবং bits-সহ চড়ার জন্য প্রয়োজনীয় পয়েন্ট থাকে। অ্যানিমেশনের সময়কার অবস্থান হাতে আনুমানিক হিসাব না করে এই অ্যাটাচমেন্ট অবজেক্টগুলোর সঙ্গে প্রপসকে প্যারেন্ট করুন।
ডিবাগ ও কভারিং নিয়ন্ত্রণ ব্যবহার করুন
প্রাণী API-তে albedo, weights, material এবং bare মোডসহ setDebug(mode, on) রয়েছে। পশমের স্তর চালু বা বন্ধ করতে setCoverings(on) ব্যবহার করুন।
wolf.setDebug('weights', true);
wolf.setCoverings(false);একটি পয়েন্টের দিকে হেডিং হিসাব করুন
হেডিং শূন্য ধনাত্মক Z অক্ষের দিকে মুখ করে, তাই কোনো লক্ষ্যের দিকে দিক হিসাব করার সময় Math.atan2(dx, dz) ব্যবহার করুন:
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
});রিসোর্স পরিষ্কার করুন
কোনো প্রাণী স্থায়ীভাবে সরিয়ে ফেললে dispose() কল করুন। এটি প্রাণীটির GPU রিসোর্স মুক্ত করে এবং দৃশ্য থেকে সেটিকে সরিয়ে দেয়।
wolf.dispose();উপযোগী এক্সপোর্ট ও ডকুমেন্টেশন
প্রধান প্যাকেজটি listSpecies, loadSpecies, setWorkerFactory, clearBuildCache এবং QUALITY-ও এক্সপোর্ট করে:
import {
createAnimal,
listSpecies,
loadSpecies,
setWorkerFactory,
clearBuildCache,
QUALITY
} from 'procedural-animals';প্রতিটি অপশন, ইভেন্ট পেলোড, স্টেট ফিল্ড এবং রেসিপির জন্য রিপোজিটরির সম্পূর্ণ রেফারেন্স এবং TypeScript ডিক্লারেশন দেখুন।
উপসংহার
three.js Procedural Animals three.js অ্যাপ্লিকেশনে বৈচিত্র্যময়, রিগ করা এবং অ্যানিমেটেড বন্যপ্রাণী যোগ করার জন্য কোড-ভিত্তিক একটি উপায় প্রদান করে। createAnimal() দিয়ে শুরু করুন, ফেরত পাওয়া অবজেক্টটি দৃশ্যে যোগ করুন, প্রাণী API-এর মাধ্যমে সেটিকে নিয়ন্ত্রণ করুন এবং প্রতি ফ্রেমে একবার আপডেট করুন। Workers, baking, seeded caching এবং একাধিক quality tier একই ওয়ার্কফ্লোকে বিস্তারিত ক্লোজ-আপ এবং বড় crowd—উভয় ক্ষেত্রেই উপযোগী করে।
