ভার্চুয়াল আর্ট সেশন

আর্ট সেশনের বিস্তারিত

সারসংক্ষেপ

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

https://g.co/VirtualArtSessions

বেঁচে থাকার সময় কি! একটি ভোক্তা পণ্য হিসাবে ভার্চুয়াল বাস্তবতার প্রবর্তনের সাথে, নতুন এবং অনাবিষ্কৃত সম্ভাবনাগুলি আবিষ্কৃত হচ্ছে। Tilt Brush, HTC Vive-এ উপলব্ধ একটি Google পণ্য, যা আপনাকে ত্রিমাত্রিক স্থানে আঁকতে দেয়। যখন আমরা প্রথমবার টিল্ট ব্রাশ চেষ্টা করেছিলাম, তখন মোশন-ট্র্যাকড কন্ট্রোলারের সাথে আঁকার অনুভূতি এবং "সুপার-পাওয়ার সহ একটি ঘরে" থাকার উপস্থিতি আপনার সাথে থাকে; আপনার চারপাশের খালি জায়গায় আঁকতে সক্ষম হওয়ার মতো অভিজ্ঞতা সত্যিই নেই।

ভার্চুয়াল আর্ট পিস

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

ভার্চুয়াল বাস্তবতায় অঙ্কন রেকর্ড করা

ইউনিটিতে তৈরি, টিল্ট ব্রাশ সফ্টওয়্যার নিজেই একটি ডেস্কটপ অ্যাপ্লিকেশন যা আপনার মাথার অবস্থান (হেড মাউন্টেড ডিসপ্লে, বা HMD) এবং আপনার প্রতিটি হাতে কন্ট্রোলার ট্র্যাক করতে রুম-স্কেল VR ব্যবহার করে। টিল্ট ব্রাশে তৈরি আর্টওয়ার্ক ডিফল্টভাবে .tilt ফাইল হিসাবে রপ্তানি করা হয়। ওয়েবে এই অভিজ্ঞতা আনার জন্য, আমরা বুঝতে পেরেছি যে আমাদের শুধু আর্টওয়ার্ক ডেটার চেয়ে বেশি প্রয়োজন। আমরা টিল্ট ব্রাশ পরিবর্তন করতে টিল্ট ব্রাশ টিমের সাথে ঘনিষ্ঠভাবে কাজ করেছি যাতে এটি সেকেন্ডে 90 বার শিল্পীর মাথা এবং হাতের অবস্থানগুলি পূর্বাবস্থায় ফেরানো/মুছে ফেলার ক্রিয়াগুলি রপ্তানি করে৷

আঁকার সময়, টিল্ট ব্রাশ আপনার নিয়ামক অবস্থান এবং কোণ নেয় এবং সময়ের সাথে সাথে একাধিক পয়েন্টকে "স্ট্রোকে" রূপান্তর করে। আপনি এখানে একটি উদাহরণ দেখতে পারেন. আমরা এমন প্লাগইন লিখেছি যা এই স্ট্রোকগুলিকে বের করে এবং তাদের কাঁচা JSON হিসাবে আউটপুট করে।

    {
      "metadata": {
        "BrushIndex": [
          "d229d335-c334-495a-a801-660ac8a87360"
        ]
      },
      "actions": [
        {
          "type": "STROKE",
          "time": 12854,
          "data": {
            "id": 0,
            "brush": 0,
            "b_size": 0.081906750798225,
            "color": [
              0.69848710298538,
              0.39136275649071,
              0.211316883564
            ],
            "points": [
              [
                {
                  "t": 12854,
                  "p": 0.25791856646538,
                  "pos": [
                    [
                      1.9832634925842,
                      17.915264129639,
                      8.6014995574951
                    ],
                    [
                      -0.32014992833138,
                      0.82291424274445,
                      -0.41208130121231,
                      -0.22473378479481
                    ]
                  ]
                }, ...many more points
              ]
            ]
          }
        }, ... many more actions
      ]
    }

উপরের স্নিপেটটি স্কেচ JSON ফর্ম্যাটের ফর্ম্যাটকে রূপরেখা দেয়৷

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

প্রতিটি স্ট্রোকের প্রাথমিক তথ্য সংরক্ষণ করা হয়, তাই ব্রাশের ধরন, ব্রাশের আকার, রঙ আরজিবি সবই সংগ্রহ করা হয়।

অবশেষে, স্ট্রোকের প্রতিটি শিরোনাম সংরক্ষণ করা হয় এবং এতে অবস্থান, কোণ, সময় এবং সেইসাথে নিয়ন্ত্রকের ট্রিগার চাপ শক্তি (প্রতিটি বিন্দুর মধ্যে p হিসাবে উল্লেখ করা) অন্তর্ভুক্ত থাকে।

উল্লেখ্য যে ঘূর্ণন একটি 4-কম্পোনেন্ট কোয়াটারনিয়ন। এটি গুরুত্বপূর্ণ পরে যখন আমরা জিম্বাল লক এড়াতে স্ট্রোকগুলি রেন্ডার করি।

WebGL এর সাথে ব্যাক স্কেচ প্লে করা হচ্ছে

একটি ওয়েব ব্রাউজারে স্কেচগুলি দেখানোর জন্য, আমরা THREE.js ব্যবহার করেছি এবং জ্যামিতি প্রজন্মের কোড লিখেছি যা হুডের নীচে টিল্ট ব্রাশ কী করে তা অনুকরণ করেছে৷

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

ওয়েবজিএল স্কেচ

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

প্রতিটি স্ট্রোকের জন্য ত্রিভুজ স্ট্রিপ গণনা করার প্রক্রিয়া টিল্ট ব্রাশে ব্যবহৃত কোডের সাথে প্রায় অভিন্ন:

const V_UP = new THREE.Vector3( 0, 1, 0 );
const V_FORWARD = new THREE.Vector3( 0, 0, 1 );

function computeSurfaceFrame( previousRight, moveVector, orientation ){
    const pointerF = V_FORWARD.clone().applyQuaternion( orientation );

    const pointerU = V_UP.clone().applyQuaternion( orientation );

    const crossF = pointerF.clone().cross( moveVector );
    const crossU = pointerU.clone().cross( moveVector );

    const right1 = inDirectionOf( previousRight, crossF );
    const right2 = inDirectionOf( previousRight, crossU );

    right2.multiplyScalar( Math.abs( pointerF.dot( moveVector ) ) );

    const newRight = ( right1.clone().add( right2 ) ).normalize();
    const normal = moveVector.clone().cross( newRight );
    return { newRight, normal };
}

function inDirectionOf( desired, v ){
    return v.dot( desired ) >= 0 ? v.clone() : v.clone().multiplyScalar(-1);
}

স্ট্রোকের দিকনির্দেশ এবং অভিযোজন নিজেদের দ্বারা একত্রিত করা গাণিতিকভাবে অস্পষ্ট ফলাফল প্রদান করে; একাধিক স্বাভাবিক প্রাপ্ত হতে পারে এবং প্রায়শই জ্যামিতিতে একটি "মোচড়" প্রদান করে।

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

স্ট্রোক

প্রতিটি স্ট্রোকের কন্ট্রোল পয়েন্টের উপর ভিত্তি করে কোয়াড তৈরি করার পর, আমরা এক কোয়াড থেকে পরের দিকে তাদের কোণগুলিকে ইন্টারপোলেট করে কোয়াডগুলিকে ফিউজ করি

function fuseQuads( lastVerts, nextVerts) {
    const vTopPos = lastVerts[1].clone().add( nextVerts[0] ).multiplyScalar( 0.5
);
    const vBottomPos = lastVerts[5].clone().add( nextVerts[2] ).multiplyScalar(
0.5 );

    lastVerts[1].copy( vTopPos );
    lastVerts[4].copy( vTopPos );
    lastVerts[5].copy( vBottomPos );
    nextVerts[0].copy( vTopPos );
    nextVerts[2].copy( vBottomPos );
    nextVerts[3].copy( vBottomPos );
}
মিশ্রিত quads
মিশ্রিত quads.

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

function updateUVsForSegment( quadVerts, quadUVs, quadLengths, useAtlas,
atlasIndex ) {
    let fYStart = 0.0;
    let fYEnd = 1.0;

    if( useAtlas ){
    const fYWidth = 1.0 / TEXTURES_IN_ATLAS;
    fYStart = fYWidth * atlasIndex;
    fYEnd = fYWidth * (atlasIndex + 1.0);
    }

    //get length of current segment
    const totalLength = quadLengths.reduce( function( total, length ){
    return total + length;
    }, 0 );

    //then, run back through the last segment and update our UVs
    let currentLength = 0.0;
    quadUVs.forEach( function( uvs, index ){
    const segmentLength = quadLengths[ index ];
    const fXStart = currentLength / totalLength;
    const fXEnd = ( currentLength + segmentLength ) / totalLength;
    currentLength += segmentLength;

    uvs[ 0 ].set( fXStart, fYStart );
    uvs[ 1 ].set( fXEnd, fYStart );
    uvs[ 2 ].set( fXStart, fYEnd );
    uvs[ 3 ].set( fXStart, fYEnd );
    uvs[ 4 ].set( fXEnd, fYStart );
    uvs[ 5 ].set( fXEnd, fYEnd );

    });

}
তেল ব্রাশের জন্য একটি টেক্সচার এটলাসে চারটি টেক্সচার
তেল ব্রাশের জন্য একটি টেক্সচার এটলাসে চারটি টেক্সচার
টিল্ট ব্রাশে
টিল্ট ব্রাশে
ওয়েবজিএল-এ
ওয়েবজিএল-এ

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

উপরের পুরো স্কেচটি WebGL-এ একটি ড্র কলে সঞ্চালিত হয়
উপরের পুরো স্কেচটি WebGL-এ একটি ড্র কলে সঞ্চালিত হয়

সিস্টেমটি পরীক্ষা করার জন্য, আমরা একটি স্কেচ তৈরি করেছি যা 20 মিনিট সময় নিয়ে স্থানটি যতটা সম্ভব শীর্ষবিন্দু দিয়ে পূরণ করতে পারে। ফলস্বরূপ স্কেচ এখনও WebGL-এ 60fps-এ বাজছে৷

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

একটি চতুর্ভুজ লুকিয়ে রাখার অর্থ হল এর শীর্ষবিন্দুগুলিকে 0,0,0 বিন্দুতে ভেঙে ফেলা। যখন সময়টি সেই বিন্দুতে পৌঁছে যায় যেখানে চতুর্ভুজটি প্রকাশ করার কথা ছিল, আমরা শীর্ষবিন্দুগুলিকে আবার জায়গায় স্থাপন করি।

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

ভার্চুয়াল আর্ট পিস

শিল্পী রেকর্ডিং

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

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

যেহেতু শিল্পীর দেহটি এর পিছনে কী আছে তা দেখতে আমাদের বাধা দেবে, তাই আমরা একটি ডাবল কাইনেক্ট সিস্টেম ব্যবহার করেছি, উভয়ই ঘরের বিপরীত দিকে কেন্দ্রে নির্দেশ করে।

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

ফুটেজ রেকর্ড করার জন্য, আমরা HTC Vive, শিল্পী এবং ক্যামেরা রাখার জন্য একটি বিশেষ কক্ষ তৈরি করেছি। সমস্ত পৃষ্ঠতল এমন উপাদান দিয়ে আবৃত ছিল যা আমাদের একটি পরিষ্কার বিন্দু মেঘ (দেয়ালে ডুভেটাইন, মেঝেতে রাবার ম্যাটিং) দিতে ইনফ্রারেড আলো শোষণ করে। যদি উপাদানটি পয়েন্ট ক্লাউড ফুটেজে প্রদর্শিত হয়, আমরা কালো উপাদান বেছে নিয়েছি যাতে এটি সাদা কিছুর মতো বিভ্রান্তিকর না হয়।

রেকর্ডিং শিল্পী

ফলাফল ভিডিও রেকর্ডিং আমাদের একটি কণা সিস্টেম প্রজেক্ট করার জন্য যথেষ্ট তথ্য দিয়েছে। আমরা ফুটেজকে আরও পরিষ্কার করার জন্য ওপেনফ্রেমওয়ার্কগুলিতে কিছু অতিরিক্ত সরঞ্জাম লিখেছি, বিশেষ করে মেঝে, দেয়াল এবং ছাদ অপসারণ করা।

একটি রেকর্ড করা ভিডিও সেশনের চারটি চ্যানেল (উপরে দুটি রঙের চ্যানেল এবং নীচে দুটি গভীরতা)
একটি রেকর্ড করা ভিডিও সেশনের চারটি চ্যানেল (উপরে দুটি রঙের চ্যানেল এবং নীচে দুটি গভীরতা)

শিল্পীদের দেখানোর পাশাপাশি, আমরা HMD এবং কন্ট্রোলারকে 3D তেও রেন্ডার করতে চেয়েছিলাম। এটি শুধুমাত্র চূড়ান্ত আউটপুটে HMD-কে স্পষ্টভাবে দেখানোর জন্য গুরুত্বপূর্ণ ছিল না (HTC Vive-এর রিফ্লেক্টিভ লেন্সগুলি Kinect-এর IR রিডিং বন্ধ করে দিচ্ছিল), এটি আমাদের কণা আউটপুট ডিবাগ করার জন্য এবং স্কেচের সাথে ভিডিওগুলিকে লাইন আপ করার জন্য যোগাযোগের পয়েন্ট দিয়েছে৷

হেড মাউন্ট করা ডিসপ্লে, কন্ট্রোলার এবং কণা সারিবদ্ধ
হেড মাউন্ট করা ডিসপ্লে, কন্ট্রোলার এবং কণা সারিবদ্ধ

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

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

রেকর্ড শিল্পী

একবার ডেটা সারিবদ্ধ হয়ে গেলে, আমরা এটি সমস্ত প্রক্রিয়া করার জন্য NodeJS-এ লেখা কিছু স্ক্রিপ্ট ব্যবহার করি এবং একটি ভিডিও ফাইল এবং JSON ফাইলগুলির সিরিজ আউটপুট করি, সমস্ত ছাঁটা এবং সিঙ্ক্রোনাইজ করা হয়। ফাইলের আকার কমাতে, আমরা তিনটি জিনিস করেছি। প্রথমত, আমরা প্রতিটি ফ্লোটিং পয়েন্ট সংখ্যার যথার্থতা কমিয়েছি যাতে তারা সর্বোচ্চ 3 দশমিকের নির্ভুলতার মূল্যে থাকে। দ্বিতীয়ত, আমরা পয়েন্টের সংখ্যা এক তৃতীয়াংশ থেকে 30fps কমিয়েছি এবং ক্লায়েন্ট-সাইডের অবস্থানগুলিকে ইন্টারপোলেট করেছি। অবশেষে, আমরা ডেটা সিরিয়ালাইজ করেছি তাই কী/মান জোড়া সহ প্লেইন JSON ব্যবহার করার পরিবর্তে, HMD এবং কন্ট্রোলারের অবস্থান এবং ঘূর্ণনের জন্য মানগুলির একটি ক্রম তৈরি করা হয়। এটি ফাইলের আকারকে 3mb-এর লাজুক কমিয়ে দেয় যা তারের উপর বিতরণের জন্য গ্রহণযোগ্য ছিল।

রেকর্ডিং শিল্পীরা

যেহেতু ভিডিওটি নিজেই একটি HTML5 ভিডিও উপাদান হিসাবে পরিবেশন করা হয় যা একটি WebGL টেক্সচার দ্বারা কণা হয়ে পড়ার জন্য, তাই ভিডিওটি নিজেই ব্যাকগ্রাউন্ডে লুকিয়ে চালানোর প্রয়োজন হয়৷ একটি শেডার গভীরতার চিত্রের রঙগুলিকে 3D স্পেসে অবস্থানে রূপান্তর করে। জেমস জর্জ সরাসরি DepthKit থেকে ফুটেজ দিয়ে আপনি কীভাবে করতে পারেন তার একটি দুর্দান্ত উদাহরণ ভাগ করেছেন।

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

videoElement.addEventListener( 'timeupdate', function(){
    videoCanvas.paintFrame( videoElement );
});

function loopCanvas(){

    if( videoElement.readyState === videoElement.HAVE\_ENOUGH\_DATA ){

    const time = Date.now();
    const elapsed = ( time - lastTime ) / 1000;

    if( videoState.playing && elapsed >= ( 1 / 30 ) ){
        videoElement.currentTime = videoElement.currentTime + elapsed;
        lastTime = time;
    }

    }

}

frameLoop.add( loopCanvas );

ভিডিও থেকে ক্যানভাসে পিক্সেল বাফার অনুলিপি করা খুবই CPU-নিবিড় হওয়ায় iOS ফ্রেমরেট উল্লেখযোগ্যভাবে কমানোর দুর্ভাগ্যজনক পার্শ্ব-প্রতিক্রিয়া ছিল আমাদের পদ্ধতির। এটি প্রায় পেতে, আমরা একই ভিডিওগুলির ছোট আকারের সংস্করণগুলি পরিবেশন করেছি যা একটি iPhone 6 এ কমপক্ষে 30fps এর অনুমতি দেয়৷

উপসংহার

2016 সালের ভিআর সফ্টওয়্যার বিকাশের জন্য সাধারণ সম্মতি হল জ্যামিতি এবং শেডারগুলিকে সহজ রাখা যাতে আপনি একটি HMD-এ 90+ fps-এ চালাতে পারেন। এটি WebGL ডেমোগুলির জন্য সত্যিই একটি দুর্দান্ত লক্ষ্য হিসাবে পরিণত হয়েছে যেহেতু Tilt Brush ম্যাপে WebGL-এ খুব সুন্দরভাবে ব্যবহৃত কৌশলগুলি।

যদিও ওয়েব ব্রাউজারগুলি জটিল 3D মেশগুলি প্রদর্শন করে তা নিজের মধ্যেই উত্তেজনাপূর্ণ নয়, এটি ধারণার প্রমাণ যে VR কাজ এবং ওয়েবের ক্রস পরাগায়ন সম্পূর্ণভাবে সম্ভব।