WebVR-এ ডান্স টোনাইট

WebVR দ্বারা প্রবর্তিত সম্ভাবনাগুলি অন্বেষণ করার জন্য একসাথে কাজ করার বিষয়ে Google Data Arts টিম যখন Moniker এবং আমার সাথে যোগাযোগ করেছিল তখন আমি উত্তেজিত হয়েছিলাম৷ আমি বছরের পর বছর ধরে তাদের দলের কাছ থেকে আসা কাজ দেখেছি এবং তাদের প্রকল্পগুলি সর্বদা আমার সাথে একটি ছন্দে লেগেছে। আমাদের সহযোগিতার ফলে ডান্স টোনাইট , এলসিডি সাউন্ডসিস্টেম এবং তাদের অনুরাগীদের সাথে একটি চির-পরিবর্তিত ভিআর নাচের অভিজ্ঞতা। এখানে আমরা এটা কিভাবে করেছি.

ধারণাটি

আমরা WebVR ব্যবহার করে প্রোটোটাইপগুলির একটি সিরিজ বিকাশের সাথে শুরু করেছি, একটি উন্মুক্ত মান যা আপনার ব্রাউজার ব্যবহার করে একটি ওয়েবসাইট পরিদর্শন করে VR এ প্রবেশ করা সম্ভব করে। লক্ষ্য হল আপনার যে ডিভাইসই থাকুক না কেন, প্রত্যেকের জন্য VR অভিজ্ঞতায় যাওয়া সহজ করা।

আমরা এটা হৃদয়ে নিয়েছি। আমরা যা নিয়ে এসেছি তা সব ধরনের VR-এ কাজ করা উচিত, VR হেডসেট যা মোবাইল ফোনের সাথে কাজ করে যেমন Google এর Daydream View, Cardboard এবং Samsung এর Gear VR থেকে HTC VIVE এবং Oculus Rift এর মতো রুম-স্কেল সিস্টেম যা আপনার শারীরিক প্রতিফলন ঘটায়। আপনার ভার্চুয়াল পরিবেশে আন্দোলন। সম্ভবত সবচেয়ে গুরুত্বপূর্ণ, আমরা অনুভব করেছি যে ওয়েবের আত্মার মধ্যে এমন কিছু তৈরি করা হবে যা VR ডিভাইসের মালিক নয় এমন প্রত্যেকের জন্যও কাজ করে।

1. DIY মোশন ক্যাপচার

যেহেতু আমরা ব্যবহারকারীদের সৃজনশীলভাবে জড়িত করতে চেয়েছিলাম, তাই আমরা VR ব্যবহার করে অংশগ্রহণ এবং আত্মপ্রকাশের সম্ভাবনাগুলি খতিয়ে দেখতে শুরু করেছি৷ VR-এ আপনি কতটা সূক্ষ্মভাবে চলাফেরা করতে এবং চারপাশে দেখতে পারেন এবং কতটা বিশ্বস্ততা ছিল তা দেখে আমরা মুগ্ধ হয়েছি। এটি আমাদের একটি ধারণা দিয়েছে। ব্যবহারকারীদের কিছু দেখার বা তৈরি করার পরিবর্তে, তাদের গতিবিধি রেকর্ড করার বিষয়ে কীভাবে?

কেউ ডান্স টোনাইটে নিজেদের রেকর্ড করছে। তাদের পিছনের পর্দা দেখায় যে তারা তাদের হেডসেটে কী দেখছে

আমরা একটি প্রোটোটাইপ তৈরি করেছি যেখানে আমরা নাচের সময় আমাদের ভিআর গগলস এবং কন্ট্রোলারের অবস্থান রেকর্ড করেছি। আমরা রেকর্ড করা অবস্থানগুলিকে বিমূর্ত আকার দিয়ে প্রতিস্থাপন করেছি এবং ফলাফল দেখে অবাক হয়েছি। ফলাফল এত মানবিক এবং এত ব্যক্তিত্ব ছিল! আমরা দ্রুত বুঝতে পেরেছি যে আমরা ঘরে বসে সস্তা মোশন ক্যাপচার করতে WebVR ব্যবহার করতে পারি।

WebVR-এর মাধ্যমে, বিকাশকারী VRPose অবজেক্টের মাধ্যমে ব্যবহারকারীর মাথার অবস্থান এবং ওরিয়েন্টেশনে অ্যাক্সেস করতে পারে। এই মান VR হার্ডওয়্যার দ্বারা প্রতিটি ফ্রেম আপডেট করা হয় যাতে আপনার কোড সঠিক দৃষ্টিকোণ থেকে নতুন ফ্রেম রেন্ডার করতে পারে। WebVR-এর সাথে GamePad API- এর মাধ্যমে, আমরা GamepadPose অবজেক্টের মাধ্যমে ব্যবহারকারী নিয়ন্ত্রকদের অবস্থান/ওরিয়েন্টেশন অ্যাক্সেস করতে পারি। আমরা কেবল এই সমস্ত অবস্থান এবং অভিযোজন মান প্রতিটি ফ্রেমে সংরক্ষণ করি, এইভাবে ব্যবহারকারীর গতিবিধির একটি "রেকর্ডিং" তৈরি করে৷

2. মিনিমালিজম এবং পোশাক

আজকের রুম স্কেল VR সরঞ্জামের সাহায্যে, আমরা ব্যবহারকারীর শরীরের তিনটি পয়েন্ট ট্র্যাক করতে পারি: তাদের মাথা এবং দুটি হাত। ডান্স টোনাইটে, আমরা মহাকাশে এই 3 পয়েন্টের গতিবিধিতে মানবতার উপর ফোকাস রাখতে চেয়েছিলাম। এটি অর্জন করার জন্য, আমরা আন্দোলনের উপর ফোকাস করার জন্য নান্দনিকতাকে যতটা সম্ভব কম ঠেলে দিয়েছি। মানুষের মস্তিষ্ককে কাজে লাগানোর ধারণাটি আমরা পছন্দ করেছি।

এই ভিডিওটি সুইডিশ মনোবিজ্ঞানী গুনার জোহানসনের কাজ প্রদর্শন করে এমন উদাহরণগুলির মধ্যে একটি ছিল যেগুলিকে আমরা যতটা সম্ভব কমিয়ে দেওয়ার কথা বিবেচনা করার সময় উল্লেখ করেছি৷ এটি দেখায় যে কীভাবে ভাসমান সাদা বিন্দুগুলি গতিতে দেখা যায় তা দেহ হিসাবে তাত্ক্ষণিকভাবে স্বীকৃত হয়।

দৃশ্যত, আমরা মার্গারেট হেস্টিংসের 1970 সালের অস্কার শ্লেমারের ট্রায়াডিক ব্যালে রিস্টেজিংয়ের এই রেকর্ডিংয়ের রঙিন ঘর এবং জ্যামিতিক পোশাক দ্বারা অনুপ্রাণিত হয়েছি।

যেখানে শ্লেমারের বিমূর্ত জ্যামিতিক পোশাক বেছে নেওয়ার কারণ ছিল তার নর্তকদের নড়াচড়াকে পুতুল এবং ম্যারিওনেটের মধ্যে সীমাবদ্ধ করা, আমাদের ডান্স টোনাইটের বিপরীত লক্ষ্য ছিল।

তারা ঘূর্ণনের মাধ্যমে কতটা তথ্য পৌঁছেছে তার উপর আমরা আমাদের আকারের পছন্দের ভিত্তিতে শেষ করেছি। একটি অর্ব যেভাবেই ঘোরানো হোক না কেন একই রকম দেখায়, কিন্তু একটি শঙ্কু সত্যিই যে দিকে তাকাচ্ছে সেদিকে নির্দেশ করে এবং পিছনের থেকে সামনের দিক থেকে ভিন্ন দেখায়।

3. আন্দোলনের জন্য লুপ প্যাডেল

আমরা রেকর্ড করা লোকদের একটি বড় দল দেখাতে চেয়েছিলাম যে একে অপরের সাথে নাচছে এবং চলাফেরা করছে। এটি করা লাইভ সম্ভব হবে না, যেহেতু ভিআর ডিভাইসগুলি যথেষ্ট পরিমাণে নেই। কিন্তু আমরা এখনও আন্দোলনের মাধ্যমে একে অপরের প্রতি প্রতিক্রিয়া জানাতে চেয়েছিলাম। আমাদের মন চলে গেছে নরম্যান ম্যাকক্লারেনের 1964 সালের ভিডিও টুকরো "ক্যানন"-এ পুনরাবৃত্তিমূলক পারফরম্যান্সে।

ম্যাকক্লারেনের পারফরম্যান্সে অত্যন্ত কোরিওগ্রাফিত আন্দোলনের একটি সিরিজ রয়েছে যা প্রতিটি লুপের পরে একে অপরের সাথে যোগাযোগ করতে শুরু করে। অনেকটা মিউজিকের লুপ প্যাডেলের মতো, যেখানে মিউজিশিয়ানরা লাইভ মিউজিকের বিভিন্ন অংশ লেয়ারিং করে নিজেদের সাথে জ্যাম করে, আমরা দেখতে আগ্রহী ছিলাম যে আমরা এমন একটি পরিবেশ তৈরি করতে পারি যেখানে ব্যবহারকারীরা অবাধে পারফরম্যান্সের হালকা সংস্করণ তৈরি করতে পারে।

4. আন্তঃসংযুক্ত কক্ষ

আন্তঃসংযুক্ত কক্ষ

অনেক মিউজিকের মতো, এলসিডি সাউন্ড সিস্টেমের ট্র্যাকগুলি সুনির্দিষ্টভাবে সময়োপযোগী ব্যবস্থা ব্যবহার করে তৈরি করা হয়। তাদের ট্র্যাক, টোনাইট, যা আমাদের প্রকল্পে বৈশিষ্ট্যযুক্ত, পরিমাপগুলি বৈশিষ্ট্যযুক্ত যা ঠিক 8 সেকেন্ড দীর্ঘ। আমরা ব্যবহারকারীদের ট্র্যাকের প্রতিটি 8-সেকেন্ড লুপের জন্য একটি পারফরম্যান্স করতে চেয়েছিলাম। যদিও এই ব্যবস্থাগুলির ছন্দ পরিবর্তন হয় না, তবে তাদের সঙ্গীত বিষয়বস্তু পরিবর্তন করে। গানটি অগ্রসর হওয়ার সাথে সাথে বিভিন্ন যন্ত্র এবং কণ্ঠের সাথে এমন কিছু মুহূর্ত রয়েছে যেখানে অভিনয়কারীরা বিভিন্ন উপায়ে প্রতিক্রিয়া জানাতে পারে। এই ব্যবস্থাগুলির প্রতিটি একটি ঘর হিসাবে প্রকাশ করা হয়, যেখানে লোকেরা এটির সাথে মানানসই একটি পারফরম্যান্স করতে পারে।

কর্মক্ষমতা জন্য অপ্টিমাইজেশান: ফ্রেম ড্রপ করবেন না

একটি মাল্টি-প্ল্যাটফর্ম VR অভিজ্ঞতা তৈরি করা যা প্রতিটি ডিভাইস বা প্ল্যাটফর্মের জন্য সর্বোত্তম কর্মক্ষমতা সহ একটি একক কোডবেসে চলে।

VR-এ থাকাকালীন, ফ্রেম রেট আপনার চলাফেরার সাথে তাল মিলিয়ে না থাকার কারণে আপনি সবচেয়ে বমি বমি ভাব অনুভব করতে পারেন। আপনি যদি মাথা ঘুরান কিন্তু আপনার চোখ যে ভিজ্যুয়ালগুলি দেখেন আপনার ভেতরের কানের গতির সাথে মেলে না, তাহলে তা তাৎক্ষণিক পেট মন্থন করে। এই কারণে, আমাদের কোন বড় ফ্রেম রেট বিলম্ব এড়াতে হবে। এখানে কিছু অপ্টিমাইজেশান রয়েছে যা আমরা বাস্তবায়ন করেছি।

1. ইনস্ট্যান্সড বাফার জ্যামিতি

যেহেতু আমাদের সম্পূর্ণ প্রজেক্ট মাত্র কয়েকটি 3d অবজেক্ট ব্যবহার করে, আমরা ইনস্ট্যান্সড বাফার জ্যামিতি ব্যবহার করে একটি বিশাল কর্মক্ষমতা বুস্ট করতে সক্ষম হয়েছি। মূলত, এটি আপনাকে একবার জিপিইউতে আপনার অবজেক্ট আপলোড করতে এবং একটি সিঙ্গেল ড্র কলে সেই অবজেক্টের যতগুলি "দৃষ্টান্ত" আঁকতে দেয় তা আপনাকে অনুমতি দেয়। ডান্স টোনাইট-এ, আমাদের কাছে শুধুমাত্র 3টি ভিন্ন বস্তু রয়েছে (একটি শঙ্কু, একটি সিলিন্ডার এবং একটি গর্ত সহ ঘর), কিন্তু সেই বস্তুগুলির সম্ভাব্য শত শত কপি। ইনস্ট্যান্স বাফার জ্যামিতি হল ThreeJS-এর একটি অংশ , কিন্তু আমরা Dusan Bosnjak-এর পরীক্ষামূলক এবং ইন-প্রোগ্রেস ফর্ক ব্যবহার করেছি যা THREE.InstanceMesh প্রয়োগ করে, যা ইন্সট্যান্সড বাফার জ্যামিতির সাথে কাজ করা আরও সহজ করে তোলে।

2. আবর্জনা সংগ্রহকারী এড়িয়ে চলা

অন্যান্য অনেক স্ক্রিপ্টিং ভাষার মতো, জাভাস্ক্রিপ্ট স্বয়ংক্রিয়ভাবে মেমরি মুক্ত করে যেগুলি বরাদ্দ করা বস্তুগুলি আর ব্যবহার করা হয় না। এই প্রক্রিয়াটিকে আবর্জনা সংগ্রহ বলা হয়।

এটি কখন ঘটে তার উপর বিকাশকারীদের কোন নিয়ন্ত্রণ নেই। আবর্জনা সংগ্রহকারী যে কোনো মুহূর্তে আমাদের দরজায় উপস্থিত হতে পারে এবং আবর্জনা খালি করা শুরু করতে পারে, ফলে তারা তাদের মিষ্টি সময় নেয় বলে ফ্রেমগুলি ফেলে দেয়।

এর সমাধান হল আমাদের বস্তুর পুনর্ব্যবহার করে যতটা সম্ভব কম আবর্জনা তৈরি করা। প্রতিটি গণনার জন্য একটি নতুন ভেক্টর অবজেক্ট তৈরি করার পরিবর্তে, আমরা পুনঃব্যবহারের জন্য স্ক্র্যাচ বস্তু চিহ্নিত করেছি। যেহেতু আমরা আমাদের রেফারেন্সকে আমাদের সুযোগের বাইরে সরিয়ে দিয়ে তাদের ধরে রাখি, সেগুলিকে অপসারণের জন্য চিহ্নিত করা হয়নি৷

উদাহরণস্বরূপ, ব্যবহারকারীর মাথা এবং হাতের অবস্থান ম্যাট্রিক্সকে আমরা প্রতিটি ফ্রেমের অবস্থান/ঘূর্ণন মানগুলির অ্যারেতে রূপান্তর করার জন্য আমাদের কোড এখানে রয়েছে। SERIALIZE_POSITION , SERIALIZE_ROTATION , এবং SERIALIZE_SCALE পুনঃব্যবহারের মাধ্যমে, আমরা প্রতিবার ফাংশন কল করার সময় নতুন বস্তু তৈরি করলে যে মেমরি বরাদ্দ এবং আবর্জনা সংগ্রহ করা হবে তা এড়িয়ে যাই।

const SERIALIZE_POSITION = new THREE.Vector3();
const SERIALIZE_ROTATION = new THREE.Quaternion();
const SERIALIZE_SCALE = new THREE.Vector3();
export const serializeMatrix = (matrix) => {
    matrix.decompose(SERIALIZE_POSITION, SERIALIZE_ROTATION, SERIALIZE_SCALE);
    return SERIALIZE_POSITION.toArray()
    .concat(SERIALIZE_ROTATION.toArray())
    .map(compressNumber);
};

3. সিরিয়ালাইজিং মোশন এবং প্রগতিশীল প্লেব্যাক

VR-এ ব্যবহারকারীদের গতিবিধি ক্যাপচার করার জন্য, আমাদের তাদের হেডসেট এবং কন্ট্রোলারের অবস্থান এবং ঘূর্ণনকে সিরিয়ালাইজ করতে হবে এবং আমাদের সার্ভারে এই ডেটা আপলোড করতে হবে। আমরা প্রতিটি ফ্রেমের জন্য সম্পূর্ণ রূপান্তর ম্যাট্রিক্স ক্যাপচার করা শুরু করেছি। এটি ভাল পারফর্ম করেছে, কিন্তু 16টি সংখ্যা প্রতি সেকেন্ডে 90 ফ্রেমে 3টি অবস্থান দ্বারা গুণিত হয়েছে, এটি খুব বড় ফাইলের দিকে পরিচালিত করে এবং তাই ডেটা আপলোড এবং ডাউনলোড করার সময় দীর্ঘ অপেক্ষা করে। রূপান্তর ম্যাট্রিক্স থেকে অবস্থানগত এবং ঘূর্ণনগত ডেটা বের করে আমরা এই মানগুলি 16 থেকে 7 এ নামিয়ে আনতে সক্ষম হয়েছি।

যেহেতু ওয়েবে দর্শকরা প্রায়শই ঠিক কী আশা করবেন তা না জেনেই একটি লিঙ্কে ক্লিক করে, তাই আমাদের দ্রুত ভিজ্যুয়াল সামগ্রী দেখাতে হবে বা তারা কয়েক সেকেন্ডের মধ্যে চলে যাবে।

এই কারণে, আমরা নিশ্চিত করতে চেয়েছিলাম যে আমাদের প্রকল্প যত তাড়াতাড়ি সম্ভব খেলা শুরু করতে পারে। প্রাথমিকভাবে, আমরা আমাদের আন্দোলনের ডেটা লোড করার জন্য একটি বিন্যাস হিসাবে JSON ব্যবহার করছিলাম। সমস্যা হল যে আমরা এটি পার্স করতে সক্ষম হওয়ার আগে আমাদের সম্পূর্ণ JSON ফাইলটি লোড করতে হবে। খুব প্রগতিশীল নয়।

ড্যান্স টোনাইটের মতো একটি প্রজেক্টকে সর্বোচ্চ সম্ভাব্য ফ্রেম হারে প্রদর্শন করার জন্য, ব্রাউজারে জাভাস্ক্রিপ্ট গণনার জন্য প্রতিটি ফ্রেমে অল্প সময় থাকে। আপনি যদি খুব বেশি সময় নেন, অ্যানিমেশনগুলি তোতলাতে শুরু করে। প্রথমে, আমরা তোতলামি অনুভব করছিলাম কারণ এই বিশাল JSON ফাইলগুলি ব্রাউজার দ্বারা ডিকোড করা হয়েছিল৷

আমরা NDJSON বা Newline delimited JSON নামে একটি সুবিধাজনক স্ট্রিমিং ডেটা ফর্ম্যাট জুড়ে এসেছি। এখানে কৌশলটি হল বৈধ JSON স্ট্রিংগুলির একটি সিরিজ দিয়ে একটি ফাইল তৈরি করা, প্রতিটি তাদের নিজস্ব লাইনে। এটি আপনাকে ফাইলটি লোড করার সময় পার্স করার অনুমতি দেয়, এটি সম্পূর্ণরূপে লোড হওয়ার আগে আমাদের পারফরম্যান্স প্রদর্শন করতে দেয়।

আমাদের রেকর্ডিংগুলির একটির একটি অংশ দেখতে কেমন তা এখানে রয়েছে:

{"fps":15,"count":1,"loopIndex":"1","hideHead":false}
[-464,17111,-6568,-235,-315,-44,9992,-3509,7823,-7074, ... ]
[-583,17146,-6574,-215,-361,-38,9991,-3743,7821,-7092, ... ]
[-693,17158,-6580,-117,-341,64,9993,-3977,7874,-7171, ... ]
[-772,17134,-6591,-93,-273,205,9994,-4125,7889,-7319, ... ]
[-814,17135,-6620,-123,-248,408,9988,-4196,7882,-7376, ... ]
[-840,17125,-6644,-173,-227,530,9982,-4174,7815,-7356, ... ]
[-868,17120,-6670,-148,-183,564,9981,-4069,7732,-7366, ... ]
...

NDJSON ব্যবহার করে আমরা পারফরম্যান্সের পৃথক ফ্রেমের ডেটা উপস্থাপনাকে স্ট্রিং হিসাবে রাখি। আমরা প্রয়োজনীয় সময়ে পৌঁছানো পর্যন্ত অপেক্ষা করতে পারি, তাদের অবস্থানগত ডেটাতে ডিকোড করার আগে, এইভাবে সময়ের সাথে প্রয়োজনীয় প্রক্রিয়াকরণ ছড়িয়ে পড়ে।

4. ইন্টারপোলেটিং আন্দোলন

যেহেতু আমরা একই সময়ে চলমান 30 থেকে 60টি পারফরম্যান্স প্রদর্শন করার আশা করছিলাম, তাই আমাদের ডেটা রেট আমাদের ইতিমধ্যেই ছিল তার চেয়ে আরও কমিয়ে আনা দরকার। ডেটা আর্টস টিম তাদের ভার্চুয়াল আর্ট সেশন প্রকল্পে একই সমস্যা মোকাবেলা করেছে, যেখানে তারা টিল্ট ব্রাশ ব্যবহার করে ভিআর-এ চিত্রশিল্পীদের রেকর্ডিং প্লে ব্যাক করে। তারা কম ফ্রেম রেট সহ ব্যবহারকারীর ডেটার মধ্যবর্তী সংস্করণ তৈরি করে এবং সেগুলিকে প্লে করার সময় ফ্রেমের মধ্যে ইন্টারপোলেট করে এটি সমাধান করেছিল। আমরা অবাক হয়েছি যে আমরা 15 এফপিএস বনাম আসল 90 এফপিএস রেকর্ডিংয়ের মধ্যে একটি ইন্টারপোলেটেড রেকর্ডিংয়ের মধ্যে পার্থক্য খুঁজে পেতে পারিনি।

নিজের জন্য দেখতে, আপনি Dance Tonite কে ?dataRate= ক্যোয়ারী স্ট্রিং ব্যবহার করে বিভিন্ন হারে ডেটা প্লে ব্যাক করতে বাধ্য করতে পারেন। আপনি 90 ফ্রেমে সেকেন্ডে , 45 ফ্রেমে সেকেন্ডে , বা 15 ফ্রেমে সেকেন্ডে রেকর্ড করা গতির তুলনা করতে এটি ব্যবহার করতে পারেন।

অবস্থানের জন্য, আমরা পূর্ববর্তী কীফ্রেম এবং পরবর্তী কীফ্রেমের মধ্যে একটি রৈখিক ইন্টারপোলেশন করি, আমরা কীফ্রেমের মধ্যে সময়ের মধ্যে কতটা কাছাকাছি আছি তার ভিত্তিতে (অনুপাত):

const { x: x1, y: y1, z: z1 } = getPosition(previous, performanceIndex, limbIndex);
const { x: x2, y: y2, z: z2 } = getPosition(next, performanceIndex, limbIndex);
interpolatedPosition = new THREE.Vector3();
interpolatedPosition.set(
    x1 + (x2 - x1) * ratio,
    y1 + (y2 - y1) * ratio,
    z1 + (z2 - z1) * ratio
    );

ওরিয়েন্টেশনের জন্য, আমরা কীফ্রেমের মধ্যে একটি গোলাকার লিনিয়ার ইন্টারপোলেশন (slerp) করি। ওরিয়েন্টেশন কোয়াটারনিয়ন হিসাবে সংরক্ষণ করা হয়।

const quaternion = getQuaternion(previous, performanceIndex, limbIndex);
quaternion.slerp(
    getQuaternion(next, performanceIndex, limbIndex),
    ratio
    );

5. সঙ্গীতের গতিবিধি সিঙ্ক করা হচ্ছে

রেকর্ড করা অ্যানিমেশনগুলির কোন ফ্রেমে প্লেব্যাক করতে হবে তা জানার জন্য, আমাদের মিলিসেকেন্ডে মিউজিকের বর্তমান সময় জানতে হবে। দেখা যাচ্ছে যে যদিও এইচটিএমএল অডিও উপাদানটি ক্রমান্বয়ে লোডিং এবং ব্যাক সাউন্ড প্লে করার জন্য নিখুঁত, এটি যে সময় বৈশিষ্ট্য প্রদান করে তা ব্রাউজারের ফ্রেম লুপের সাথে সিঙ্কে পরিবর্তিত হয় না। এটা সবসময় একটু বন্ধ. কখনও কখনও একটি ms এর ভগ্নাংশ খুব তাড়াতাড়ি, কখনও কখনও একটি ভগ্নাংশ খুব দেরিতে।

এটি আমাদের সুন্দর নাচের রেকর্ডিংগুলিতে তোতলামির দিকে নিয়ে যায়, যা আমরা যে কোনও মূল্যে এড়াতে চাই৷ এর প্রতিকারের জন্য, আমরা জাভাস্ক্রিপ্টে আমাদের নিজস্ব টাইমার প্রয়োগ করেছি। এইভাবে আমরা নিশ্চিত হতে পারি যে ফ্রেমের মধ্যে যে পরিমাণ সময় পরিবর্তিত হয়েছে তা শেষ ফ্রেমের পর থেকে যে সময় অতিবাহিত হয়েছে। যখনই আমাদের টাইমার মিউজিকের সাথে 10 ms-এর বেশি সিঙ্কের বাইরে চলে যায়, আমরা এটি আবার সিঙ্ক্রোনাইজ করি।

6. কলিং এবং কুয়াশা

প্রতিটি গল্পের একটি ভাল সমাপ্তি প্রয়োজন এবং আমরা আমাদের অভিজ্ঞতার শেষ পর্যন্ত ব্যবহারকারীদের জন্য আশ্চর্যজনক কিছু করতে চেয়েছিলাম। আপনি শেষ ঘর থেকে বেরিয়ে যাওয়ার সাথে সাথে আপনি শঙ্কু এবং সিলিন্ডারের শান্ত প্রাকৃতিক দৃশ্যের মতো অনুভূত হয়ে প্রবেশ করবেন। "এটাই কি শেষ?", আপনি ভাবছেন। আপনি যখন মাঠে আরও এগিয়ে যান, হঠাৎ সঙ্গীতের সুর বিভিন্ন শঙ্কু এবং সিলিন্ডারের দলকে নর্তকীতে পরিণত করে। আপনি একটি বিশাল পার্টি মাঝখানে নিজেকে খুঁজে! তারপর হঠাৎ গান বন্ধ হয়ে গেলে সবকিছু মাটিতে পড়ে যায়।

যদিও এটি একজন দর্শক হিসাবে দুর্দান্ত অনুভূত হয়েছিল, এটি সমাধানের জন্য কিছু পারফরম্যান্স প্রতিবন্ধকতার পরিচয় দিয়েছে। আমাদের নতুন সমাপ্তির জন্য প্রয়োজনীয় 40টি অদ্ভুত অতিরিক্ত পারফরম্যান্সের সাথে রুম স্কেল VR ডিভাইস এবং তাদের হাই-এন্ড গেমিং রিগগুলি নিখুঁতভাবে পারফর্ম করেছে। কিন্তু নির্দিষ্ট কিছু মোবাইল ডিভাইসে ফ্রেম রেট অর্ধেক হয়ে গেছে।

এটি প্রতিহত করার জন্য, আমরা কুয়াশা চালু করেছি। একটা নির্দিষ্ট দূরত্বের পর ধীরে ধীরে সবকিছু কালো হয়ে যায়। যেহেতু দৃশ্যমান নয় এমনটি আমাদের গণনা বা আঁকার দরকার নেই, তাই আমরা দৃশ্যমান নয় এমন কক্ষগুলিতে পারফরম্যান্স বন্ধ করি এবং এটি আমাদের CPU এবং GPU উভয়ের জন্য কাজ সংরক্ষণ করতে দেয়। কিন্তু কিভাবে সঠিক দূরত্ব সিদ্ধান্ত নিতে?

কিছু ডিভাইস আপনি তাদের উপর নিক্ষেপ করা সবকিছু পরিচালনা করতে পারে এবং অন্যগুলি আরও সংকীর্ণ। আমরা একটি স্লাইডিং স্কেল বাস্তবায়ন করতে বেছে নিয়েছি। ক্রমাগত প্রতি সেকেন্ডে ফ্রেমের পরিমাণ পরিমাপ করে, আমরা সেই অনুযায়ী আমাদের কুয়াশার দূরত্ব সামঞ্জস্য করতে পারি। যতক্ষণ না আমাদের ফ্রেম রেট মসৃণভাবে চলছে, ততক্ষণ আমরা কুয়াশা দূর করে আরও রেন্ডার কাজ করার চেষ্টা করি। যদি ফ্রেমরেট যথেষ্ট মসৃণ না হয়, তাহলে আমরা কুয়াশাকে কাছাকাছি নিয়ে আসি যা আমাদের অন্ধকারে রেন্ডারিং পারফরম্যান্স এড়িয়ে যেতে দেয়।

// this is called every frame
// the FPS calculation is based on stats.js by @mrdoob
tick: (interval = 3000) => {
    frames++;
    const time = (performance || Date).now();
    if (prevTime == null) prevTime = time;
    if (time > prevTime + interval) {
    fps = Math.round((frames * 1000) / (time - prevTime));
    frames = 0;
    prevTime = time;
    const lastCullDistance = settings.cullDistance;

    // if the fps is lower than 52 reduce the cull distance
    if (fps <= 52) {
        settings.cullDistance = Math.max(
        settings.minCullDistance,
        settings.cullDistance - settings.roomDepth
        );
    }
    // if the FPS is higher than 56, increase the cull distance
    else if (fps > 56) {
        settings.cullDistance = Math.min(
        settings.maxCullDistance,
        settings.cullDistance + settings.roomDepth
        );
    }
    }

    // gradually increase the cull distance to the new setting
    cullDistance = cullDistance * 0.95 + settings.cullDistance * 0.05;

    // mask the edge of the cull distance with fog
    viewer.fog.near = cullDistance - settings.roomDepth;
    viewer.fog.far = cullDistance;
}

প্রত্যেকের জন্য কিছু: ওয়েবের জন্য VR তৈরি করা

মাল্টি-প্ল্যাটফর্ম ডিজাইন এবং ডেভেলপ করা, অ্যাসিমেট্রিক এক্সপেরিয়েন্স মানে প্রতিটি ব্যবহারকারীর প্রয়োজনের জন্য তাদের ডিভাইসের উপর নির্ভর করে হিসাব করা। এবং প্রতিটি ডিজাইনের সিদ্ধান্তের সাথে, আমাদের দেখতে হবে যে এটি কীভাবে অন্যান্য ব্যবহারকারীদের প্রভাবিত করতে পারে। আপনি কীভাবে নিশ্চিত করবেন যে আপনি VR-এ যা দেখছেন তা VR ছাড়াই সমানভাবে উত্তেজনাপূর্ণ এবং ভিসা বিপরীতে?

1. হলুদ কক্ষ

সুতরাং আমাদের রুম-স্কেল ভিআর ব্যবহারকারীরা পারফরম্যান্স তৈরি করবে, তবে মোবাইল ভিআর ডিভাইসের ব্যবহারকারীরা (যেমন কার্ডবোর্ড, ডেড্রিম ভিউ বা স্যামসাং গিয়ার) প্রকল্পটি কীভাবে অনুভব করবে? এর জন্য, আমরা আমাদের পরিবেশে একটি নতুন উপাদান চালু করেছি: হলুদ কক্ষ।

হলুদ কক্ষ
হলুদ কক্ষ

আপনি যখন ভিআর-এ প্রকল্পটি দেখেন, তখন আপনি হলুদ কক্ষের দৃষ্টিকোণ থেকে তা করছেন। আপনি যখন ঘরে ঘরে ভাসছেন, নর্তকীরা আপনার উপস্থিতিতে প্রতিক্রিয়া জানায়। তারা আপনাকে অঙ্গভঙ্গি করে, আপনার চারপাশে নাচ করে, আপনার পিছনে মজার গতি তৈরি করে এবং দ্রুত আপনার পথ থেকে সরে যায় যাতে তারা আপনার সাথে ধাক্কা না খায়। হলুদ কক্ষ সবসময় মনোযোগ কেন্দ্র।

এর কারণ হ'ল একটি পারফরম্যান্স রেকর্ড করার সময়, হলুদ কক্ষটি সংগীতের সাথে সিঙ্ক করে ঘরের মাঝখানে চলে যায় এবং চারপাশে লুপ করে। অরবের অবস্থান পারফর্মারকে একটি ধারণা দেয় যে তারা সময় কোথায় আছে এবং তাদের লুপে কতটা সময় বাকি আছে। এটি তাদের চারপাশে একটি পারফরম্যান্স তৈরি করার জন্য একটি স্বাভাবিক ফোকাস প্রদান করে।

2. আরেকটি দৃষ্টিকোণ

আমরা ভিআর ছাড়া ব্যবহারকারীদের ছেড়ে যেতে চাইনি, বিশেষত কারণ তারা সম্ভবত আমাদের সবচেয়ে বড় দর্শক হতে পারে। একটি ভুল VR অভিজ্ঞতা তৈরি করার পরিবর্তে, আমরা স্ক্রিন-ভিত্তিক ডিভাইসগুলিকে তাদের নিজস্ব অভিজ্ঞতা দিতে চেয়েছিলাম। আমাদের আইসোমেট্রিক দৃষ্টিকোণ থেকে উপরে থেকে পারফরম্যান্স দেখানোর ধারণা ছিল। এই দৃষ্টিকোণটি কম্পিউটার গেমগুলির একটি সমৃদ্ধ ইতিহাস রয়েছে। এটি 1982 সাল থেকে একটি স্পেস শ্যুটার গেম জ্যাক্সন-এ প্রথম ব্যবহার করা হয়েছিল। যেখানে ভিআর ব্যবহারকারীরা এটির ঘনত্বের মধ্যে রয়েছে, আইসোমেট্রিক দৃষ্টিকোণ ক্রিয়াটির উপর ঈশ্বরের মতো দৃষ্টিভঙ্গি দেয়। আমরা পুতুল-হাউসের নান্দনিকতার ছোঁয়া দিয়ে মডেলগুলিকে কিছুটা বাড়িয়ে তোলার বেছে নিয়েছি।

3. ছায়া: আপনি এটি তৈরি না হওয়া পর্যন্ত এটি জাল

আমরা দেখতে পেয়েছি যে আমাদের কিছু ব্যবহারকারী আমাদের আইসোমেট্রিক দৃষ্টিকোণটির গভীরতা দেখতে খুব কঠিন সময় পার করছেন। আমি নিশ্চিত যে এই কারণেই Zaxxon ছিল ইতিহাসের প্রথম কম্পিউটার গেমগুলির মধ্যে একটি যা তার উড়ন্ত বস্তুর নীচে একটি গতিশীল ছায়া প্রজেক্ট করেছে।

ছায়া

দেখা যাচ্ছে যে 3D তে ছায়া তৈরি করা কঠিন। বিশেষ করে মোবাইল ফোনের মতো সংকুচিত ডিভাইসের জন্য। প্রাথমিকভাবে আমাদেরকে তাদের সমীকরণ থেকে বের করে দেওয়ার কঠিন সিদ্ধান্ত নিতে হয়েছিল, কিন্তু Three.js-এর লেখক এবং অভিজ্ঞ ডেমো হ্যাকার মিস্টার ডুব- এর কাছে পরামর্শ চাওয়ার পর, তিনি তাদের জালিয়াতি করার অভিনব ধারণা নিয়ে আসেন।

আমাদের প্রতিটি ভাসমান বস্তু কীভাবে আমাদের আলোকে অস্পষ্ট করছে এবং তাই বিভিন্ন আকারের ছায়া নিক্ষেপ করছে তা গণনা করার পরিবর্তে, আমরা তাদের প্রতিটির নীচে একই বৃত্তাকার অস্পষ্ট টেক্সচার চিত্র আঁকি। যেহেতু আমাদের ভিজ্যুয়ালগুলি প্রথমে বাস্তবতাকে অনুকরণ করার চেষ্টা করছে না, তাই আমরা দেখতে পেলাম যে আমরা মাত্র কয়েকটি পরিবর্তনের মাধ্যমে এটি থেকে খুব সহজেই মুক্তি পেতে পারি। যখন বস্তুগুলি মাটির কাছাকাছি আসে, তখন আমাদের টেক্সচারগুলি গাঢ় এবং ছোট হয়। যখন তারা উপরে যায়, আমরা টেক্সচারগুলিকে আরও স্বচ্ছ এবং বড় করে তুলি।

এগুলি তৈরি করতে, আমরা এই টেক্সচারটি একটি নরম সাদা থেকে কালো গ্রেডিয়েন্টের সাথে ব্যবহার করেছি (কোনও আলফা স্বচ্ছতা ছাড়াই)। আমরা উপাদানটিকে স্বচ্ছ হিসাবে সেট করি এবং বিয়োগমূলক মিশ্রণ ব্যবহার করি। যখন তারা ওভারল্যাপ করে তখন এটি তাদের সুন্দরভাবে মিশ্রিত করতে সহায়তা করে:

function createShadow() {
    const texture = new THREE.TextureLoader().load(shadowTextureUrl);
    const material = new THREE.MeshLambertMaterial({
        map: texture,
        transparent: true,
        side: THREE.BackSide,
        depthWrite: false,
        blending: THREE.SubtractiveBlending,
    });
    const geometry = new THREE.PlaneBufferGeometry(0.5, 0.5, 1, 1);
    const plane = new THREE.Mesh(geometry, material);
    return plane;
    }

4. সেখানে থাকা

একজন পারফর্মারের মাথায় ক্লিক করার মাধ্যমে, ভিআর ছাড়া দর্শকরা নর্তকীর দৃষ্টিকোণ থেকে জিনিসগুলি দেখতে সক্ষম হয়। এই কোণ থেকে, অনেক ছোট বিবরণ স্পষ্ট হয়ে ওঠে. ধাপে ধাপে তাদের পারফরম্যান্স রাখার চেষ্টা করে, নর্তকীরা দ্রুত একে অপরের দিকে তাকায়। কক্ষটি ঘরে প্রবেশ করার সাথে সাথে আপনি তাদের ঘাবড়ে গিয়ে তার দিকে তাকিয়ে থাকতে দেখেন। একজন দর্শক হিসাবে, আপনি এই আন্দোলনগুলিকে প্রভাবিত করতে পারবেন না, এটি আশ্চর্যজনকভাবে নিমজ্জনের অনুভূতি প্রকাশ করে। আবার, আমরা আমাদের ব্যবহারকারীদের একটি নম্র মাউস-নিয়ন্ত্রিত ভুল VR সংস্করণের সাথে উপস্থাপন করার চেয়ে এটি করা পছন্দ করি।

5. শেয়ারিং রেকর্ডিং

আমরা জানি আপনি কতটা গর্বিত হতে পারেন যখন 20টি স্তরের পারফর্মার একে অপরের প্রতি প্রতিক্রিয়া জানাতে একটি জটিল কোরিওগ্রাফ করা রেকর্ডিং বন্ধ করে। আমরা জানতাম আমাদের ব্যবহারকারীরা সম্ভবত এটি তাদের বন্ধুদের দেখাতে চাইবে৷ কিন্তু এই কৃতিত্বের একটি স্থির চিত্র যথেষ্ট যোগাযোগ করে না। পরিবর্তে, আমরা আমাদের ব্যবহারকারীদের তাদের পারফরম্যান্সের ভিডিও শেয়ার করার অনুমতি দিতে চেয়েছিলাম। আসলে, কেন একটি GIF নয়? আমাদের অ্যানিমেশনগুলি ফ্ল্যাট ছায়াযুক্ত, ফর্ম্যাটের সীমিত রঙের প্যালেটগুলির জন্য উপযুক্ত৷

রেকর্ডিং শেয়ার করা

আমরা GIF.js- এ ফিরে এসেছি, একটি জাভাস্ক্রিপ্ট লাইব্রেরি যা আপনাকে ব্রাউজারের মধ্যে থেকে অ্যানিমেটেড gif এনকোড করতে দেয়। এটি ওয়েব কর্মীদের কাছে ফ্রেমের এনকোডিং অফলোড করে যা ব্যাকগ্রাউন্ডে আলাদা প্রসেস হিসাবে চালাতে সক্ষম হয়, এইভাবে পাশাপাশি কাজ করে একাধিক প্রসেসরের সুবিধা নিতে সক্ষম হয়।

দুঃখের বিষয়, অ্যানিমেশনের জন্য আমাদের যে পরিমাণ ফ্রেমের প্রয়োজন ছিল, এনকোডিং প্রক্রিয়া তখনও খুব ধীর ছিল। GIF একটি সীমিত রঙের প্যালেট ব্যবহার করে ছোট ফাইল তৈরি করতে সক্ষম। আমরা দেখেছি যে প্রতিটি পিক্সেলের জন্য সবচেয়ে কাছের রঙ খুঁজে পেতে বেশিরভাগ সময় ব্যয় করা হচ্ছে। আমরা একটি ছোট শর্ট কাট হ্যাক করে এই প্রক্রিয়াটিকে দশগুণ অপ্টিমাইজ করতে সক্ষম হয়েছি: যদি পিক্সেলের রঙ শেষের মতো একই হয়, তাহলে প্যালেট থেকে আগের মতো একই রঙ ব্যবহার করুন।

এখন আমাদের দ্রুত এনকোড ছিল, কিন্তু ফলস্বরূপ GIF ফাইলগুলি আকারে খুব বড় ছিল। GIF বিন্যাস আপনাকে নির্দেশ করতে দেয় যে কীভাবে প্রতিটি ফ্রেম তার নিষ্পত্তি পদ্ধতি সংজ্ঞায়িত করে শেষের উপরে প্রদর্শিত হবে। ছোট ফাইল পেতে, প্রতিটি পিক্সেল প্রতিটি ফ্রেম আপডেট করার পরিবর্তে, আমরা শুধুমাত্র পরিবর্তিত পিক্সেলগুলি আপডেট করি। এনকোডিং প্রক্রিয়াকে আবার ধীর করার সময়, এটি আমাদের ফাইলের আকারকে সুন্দরভাবে কমিয়ে এনেছে।

6. সলিড গ্রাউন্ড: গুগল ক্লাউড এবং ফায়ারবেস

একটি "ব্যবহারকারী-উত্পাদিত সামগ্রী" সাইটের ব্যাকএন্ড প্রায়শই জটিল এবং ভঙ্গুর হতে পারে, তবে আমরা এমন একটি সিস্টেম নিয়ে এসেছি যা গুগল ক্লাউড এবং ফায়ারবেসের জন্য সহজ এবং শক্তিশালী ধন্যবাদ৷ যখন একজন পারফর্মার সিস্টেমে একটি নতুন নাচ আপলোড করে, তখন সেগুলি ফায়ারবেস প্রমাণীকরণ দ্বারা বেনামে প্রমাণীকৃত হয়। ফায়ারবেসের জন্য ক্লাউড স্টোরেজ ব্যবহার করে একটি অস্থায়ী জায়গায় তাদের রেকর্ডিং আপলোড করার অনুমতি দেওয়া হয়েছে। আপলোড সম্পূর্ণ হলে, ক্লায়েন্ট মেশিন তাদের Firebase টোকেন ব্যবহার করে Firebase HTTP ট্রিগারের জন্য একটি ক্লাউড ফাংশন কল করে। এটি একটি সার্ভার প্রক্রিয়াকে ট্রিগার করে যা জমাটি যাচাই করে, একটি ডাটাবেস রেকর্ড তৈরি করে এবং রেকর্ডিংটিকে Google ক্লাউড স্টোরেজের একটি সর্বজনীন ডিরেক্টরিতে নিয়ে যায়।

শক্ত মাটি

আমাদের সমস্ত পাবলিক সামগ্রী একটি ক্লাউড স্টোরেজ বালতিতে ফ্ল্যাট ফাইলগুলির একটি সিরিজে সংরক্ষণ করা হয়। এর মানে হল আমাদের ডেটা সারা বিশ্বে দ্রুত অ্যাক্সেসযোগ্য এবং আমাদের কোনও ভাবেই ডেটা প্রাপ্যতাকে প্রভাবিত করে উচ্চ ট্রাফিক লোড নিয়ে চিন্তা করার দরকার নেই৷

আমরা একটি সাধারণ মডারেশন/কিউরেশন টুল তৈরি করতে একটি ফায়ারবেস রিয়েলটাইম ডেটাবেস এবং ক্লাউড ফাংশন এন্ডপয়েন্ট ব্যবহার করেছি যা আমাদের VR-এ প্রতিটি নতুন জমা দেখতে এবং যেকোনো ডিভাইস থেকে নতুন প্লেলিস্ট প্রকাশ করতে দেয়।

7. সেবা কর্মী

পরিষেবা কর্মীরা একটি মোটামুটি সাম্প্রতিক উদ্ভাবন যা ওয়েবসাইট সম্পদের ক্যাশিং পরিচালনা করতে সহায়তা করে। আমাদের ক্ষেত্রে, পরিষেবা কর্মীরা আমাদের কন্টেন্ট দ্রুত লোড করে রিটার্ন ভিজিটরদের জন্য এবং এমনকি সাইটটিকে অফলাইনে কাজ করার অনুমতি দেয়। এইগুলি গুরুত্বপূর্ণ বৈশিষ্ট্য কারণ আমাদের অনেক দর্শক বিভিন্ন মানের মোবাইল সংযোগে থাকবে।

প্রকল্পে একজন পরিষেবা কর্মীদের যোগ করা সহজ ছিল একটি সহজ ওয়েবপ্যাক প্লাগইনের জন্য ধন্যবাদ যা আপনার জন্য বেশিরভাগ ভারী উত্তোলন পরিচালনা করে। নীচের কনফিগারেশনে, আমরা একটি পরিষেবা কর্মী তৈরি করি যা স্বয়ংক্রিয়ভাবে আমাদের সমস্ত স্ট্যাটিক ফাইল ক্যাশে করবে। এটি নেটওয়ার্ক থেকে সর্বশেষ প্লেলিস্ট ফাইলটি টেনে আনবে, যদি উপলব্ধ থাকে, যেহেতু প্লেলিস্টটি সব সময় আপডেট হবে। সমস্ত রেকর্ডিং json ফাইল উপলব্ধ থাকলে ক্যাশে থেকে টানতে হবে, কারণ এগুলি কখনই পরিবর্তন হবে না।

const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
config.plugins.push(
    new SWPrecacheWebpackPlugin({
    dontCacheBustUrlsMatching: /\.\w{8}\./,
    filename: 'service-worker.js',
    minify: true,
    navigateFallback: 'index.html',
    staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
    runtimeCaching: [{
        urlPattern: /playlist\.json$/,
        handler: 'networkFirst',
    }, {
        urlPattern: /\/recordings\//,
        handler: 'cacheFirst',
        options: {
        cache: {
            maxEntries: 120,
            name: 'recordings',
        },
        },
    }],
    })
);

বর্তমানে, প্লাগইনটি আমাদের মিউজিক ফাইলের মতো ক্রমান্বয়ে লোড হওয়া মিডিয়া সম্পদগুলি পরিচালনা করে না, তাই আমরা এই ফাইলগুলিতে ক্লাউড স্টোরেজ Cache-Control হেডারটি public, max-age=31536000 সেট করে কাজ করেছি যাতে ব্রাউজার ফাইলটি ক্যাশে করে। এক বছর পর্যন্ত।

উপসংহার

পারফর্মাররা কীভাবে এই অভিজ্ঞতা যোগ করবে এবং গতি ব্যবহার করে সৃজনশীল অভিব্যক্তির জন্য এটিকে একটি হাতিয়ার হিসেবে ব্যবহার করবে তা দেখে আমরা উত্তেজিত। আমরা সমস্ত কোড ওপেন সোর্স প্রকাশ করেছি, যা আপনি https://github.com/puckey/dance-tonite- এ খুঁজে পেতে পারেন। VR এবং বিশেষ করে WebVR-এর এই প্রাথমিক দিনগুলিতে, এই নতুন মাধ্যমটি কী নতুন সৃজনশীল এবং অপ্রত্যাশিত দিকনির্দেশনা নেবে তা দেখার জন্য আমরা উন্মুখ। উপর নাচ .