pixiv হল একটি অনলাইন কমিউনিটি পরিষেবা যা ইলাস্ট্রেটর এবং ইলাস্ট্রেশন উত্সাহীদের তাদের বিষয়বস্তুর মাধ্যমে একে অপরের সাথে যোগাযোগ করার জন্য। এটি লোকেদের তাদের নিজস্ব চিত্রগুলি পোস্ট করতে দেয়৷ সারা বিশ্বে তাদের 84 মিলিয়নেরও বেশি ব্যবহারকারী রয়েছে এবং 2023 সালের মে পর্যন্ত 120 মিলিয়নেরও বেশি শিল্পকর্ম পোস্ট করা হয়েছে।
pixiv স্কেচ pixiv দ্বারা প্রদত্ত পরিষেবাগুলির মধ্যে একটি। এটি আঙুল বা স্টাইল ব্যবহার করে ওয়েবসাইটে শিল্পকর্ম আঁকতে ব্যবহৃত হয়। এটি অসংখ্য ধরণের ব্রাশ, স্তর এবং বালতি পেইন্টিং সহ আশ্চর্যজনক চিত্র আঁকার জন্য বিভিন্ন বৈশিষ্ট্য সমর্থন করে এবং মানুষকে তাদের অঙ্কন প্রক্রিয়া লাইভস্ট্রিম করার অনুমতি দেয়।
এই কেস স্টাডিতে, আমরা দেখব কিভাবে pixiv Sketch WebGL, WebAssembly, এবং WebRTC এর মত কিছু নতুন ওয়েব প্ল্যাটফর্ম বৈশিষ্ট্য ব্যবহার করে তাদের ওয়েব অ্যাপের কর্মক্ষমতা এবং গুণমান উন্নত করেছে।
কেন ওয়েবে একটি স্কেচিং অ্যাপ তৈরি করবেন?
pixiv Sketch প্রথম 2015 সালে ওয়েবে এবং iOS-এ প্রকাশিত হয়েছিল। ওয়েব সংস্করণের জন্য তাদের লক্ষ্য শ্রোতা ছিল প্রাথমিকভাবে ডেস্কটপ, যা এখনও চিত্র সম্প্রদায়ের দ্বারা ব্যবহৃত সবচেয়ে বড় প্ল্যাটফর্ম।
এখানে একটি ডেস্কটপ অ্যাপের পরিবর্তে একটি ওয়েব সংস্করণ বিকাশ করার জন্য পিক্সিভের শীর্ষ দুটি কারণ রয়েছে:
- উইন্ডোজ, ম্যাক, লিনাক্স এবং আরও অনেক কিছুর জন্য অ্যাপ তৈরি করা খুবই ব্যয়বহুল। ওয়েব ডেস্কটপের যেকোনো ব্রাউজারে পৌঁছায়।
- প্ল্যাটফর্ম জুড়ে ওয়েবের সর্বোত্তম নাগাল রয়েছে। ওয়েব ডেস্কটপ এবং মোবাইলে এবং প্রতিটি অপারেটিং সিস্টেমে উপলব্ধ।
প্রযুক্তি
pixiv স্কেচ ব্যবহারকারীদের থেকে বেছে নেওয়ার জন্য বিভিন্ন ব্রাশ রয়েছে। WebGL গ্রহণ করার আগে, শুধুমাত্র এক ধরনের ব্রাশ ছিল যেহেতু 2D ক্যানভাস বিভিন্ন ব্রাশের জটিল টেক্সচারকে চিত্রিত করার জন্য খুব সীমিত ছিল, যেমন একটি পেন্সিলের মোটা প্রান্ত এবং ভিন্ন প্রস্থ এবং রঙের তীব্রতা যা স্কেচের চাপে পরিবর্তিত হয়।
WebGL ব্যবহার করে সৃজনশীল ধরনের ব্রাশ
যাইহোক, WebGL গ্রহণের সাথে সাথে, তারা ব্রাশের বিবরণে আরও বৈচিত্র্য যোগ করতে এবং উপলব্ধ ব্রাশের সংখ্যা সাতটিতে উন্নীত করতে সক্ষম হয়েছিল।
2D ক্যানভাস প্রসঙ্গ ব্যবহার করে, নিম্নলিখিত স্ক্রিনশটের মতো সমানভাবে বিতরণ করা প্রস্থের সাথে একটি সাধারণ টেক্সচার আছে এমন লাইনগুলি আঁকতে পেরেছিল:
এই লাইনগুলি পাথ তৈরি করে এবং স্ট্রোক আঁকার মাধ্যমে আঁকা হয়েছিল, কিন্তু WebGL পয়েন্ট স্প্রাইট এবং শেডার ব্যবহার করে এটি পুনরুত্পাদন করে, নিম্নলিখিত কোড নমুনায় দেখানো হয়েছে
নিম্নলিখিত উদাহরণটি একটি শীর্ষবিন্দু শেডার প্রদর্শন করে।
precision highp float;
attribute vec2 pos;
attribute float thicknessFactor;
attribute float opacityFactor;
uniform float pointSize;
varying float varyingOpacityFactor;
varying float hardness;
// Calculate hardness from actual point size
float calcHardness(float s) {
float h0 = .1 * (s - 1.);
float h1 = .01 * (s - 10.) + .6;
float h2 = .005 * (s - 30.) + .8;
float h3 = .001 * (s - 50.) + .9;
float h4 = .0002 * (s - 100.) + .95;
return min(h0, min(h1, min(h2, min(h3, h4))));
}
void main() {
float actualPointSize = pointSize * thicknessFactor;
varyingOpacityFactor = opacityFactor;
hardness = calcHardness(actualPointSize);
gl_Position = vec4(pos, 0., 1.);
gl_PointSize = actualPointSize;
}
নিম্নলিখিত উদাহরণটি একটি খণ্ড শেডারের জন্য নমুনা কোড দেখায়।
precision highp float;
const float strength = .8;
const float exponent = 5.;
uniform vec4 color;
varying float hardness;
varying float varyingOpacityFactor;
float fallOff(const float r) {
// w is for width
float w = 1. - hardness;
if (w < 0.01) {
return 1.;
} else {
return min(1., pow(1. - (r - hardness) / w, exponent));
}
}
void main() {
vec2 texCoord = (gl_PointCoord - .5) * 2.;
float r = length(texCoord);
if (r > 1.) {
discard;
}
float brushAlpha = fallOff(r) * varyingOpacityFactor * strength * color.a;
gl_FragColor = vec4(color.rgb, brushAlpha);
}
পয়েন্ট স্প্রাইটের ব্যবহার অঙ্কন চাপের প্রতিক্রিয়ায় বেধ এবং ছায়ায় তারতম্য করা সহজ করে তোলে, নিম্নলিখিত শক্তিশালী এবং দুর্বল লাইনগুলিকে প্রকাশ করার অনুমতি দেয়, যেমন:
উপরন্তু, পয়েন্ট স্প্রাইট ব্যবহার করে বাস্তবায়ন এখন একটি পৃথক শেডার ব্যবহার করে টেক্সচার সংযুক্ত করতে পারে, যা পেন্সিল এবং অনুভূত-টিপ পেনের মতো টেক্সচার সহ ব্রাশের দক্ষ উপস্থাপনের অনুমতি দেয়।
ব্রাউজারে স্টাইলাস সমর্থন
একটি ডিজিটাল স্টাইলাস ব্যবহার করা ডিজিটাল শিল্পীদের জন্য অত্যন্ত জনপ্রিয় হয়ে উঠেছে। আধুনিক ব্রাউজারগুলি PointerEvent API সমর্থন করে যা ব্যবহারকারীদের তাদের ডিভাইসে একটি স্টাইলাস ব্যবহার করতে সক্ষম করে: কলমের চাপ পরিমাপ করতে PointerEvent.pressure
ব্যবহার করুন এবং ডিভাইসে কলমের কোণ পরিমাপ করতে PointerEvent.tiltX
, PointerEvent.tiltY
ব্যবহার করুন৷
পয়েন্ট স্প্রাইট দিয়ে ব্রাশ স্ট্রোক করার জন্য, PointerEvent
অবশ্যই ইন্টারপোলেট করতে হবে এবং আরও সূক্ষ্ম-দানাযুক্ত ইভেন্ট সিকোয়েন্সে রূপান্তর করতে হবে। পয়েন্টার ইভেন্টে, লেখনীর অভিযোজন পোলার স্থানাঙ্কের আকারে প্রাপ্ত করা যেতে পারে, কিন্তু পিক্সিভ স্কেচ তাদের ব্যবহার করার আগে স্টাইলাসের অভিযোজন প্রতিনিধিত্বকারী ভেক্টরে রূপান্তরিত করে।
function getTiltAsVector(event: PointerEvent): [number, number, number] {
const u = Math.tan((event.tiltX / 180) * Math.PI);
const v = Math.tan((event.tiltY / 180) * Math.PI);
const z = Math.sqrt(1 / (u * u + v * v + 1));
const x = z * u;
const y = z * v;
return [x, y, z];
}
function handlePointerDown(event: PointerEvent) {
const position = [event.clientX, event.clientY];
const pressure = event.pressure;
const tilt = getTiltAsVector(event);
interpolateAndRender(position, pressure, tilt);
}
একাধিক অঙ্কন স্তর
স্তরগুলি ডিজিটাল অঙ্কনের সবচেয়ে অনন্য ধারণাগুলির মধ্যে একটি। তারা ব্যবহারকারীদের একে অপরের উপরে চিত্রের বিভিন্ন অংশ আঁকতে দেয় এবং স্তর দ্বারা স্তর সম্পাদনা করার অনুমতি দেয়। pixiv স্কেচ অন্যান্য ডিজিটাল ড্রয়িং অ্যাপের মতো লেয়ার ফাংশন প্রদান করে।
প্রচলিতভাবে, drawImage()
এবং কম্পোজিটিং অপারেশন সহ একাধিক <canvas>
উপাদান ব্যবহার করে স্তরগুলি বাস্তবায়ন করা সম্ভব। যাইহোক এটি সমস্যাযুক্ত কারণ 2D ক্যানভাস প্রসঙ্গে, CanvasRenderingContext2D.globalCompositeOperation
কম্পোজিশন মোড ব্যবহার করা ছাড়া অন্য কোন বিকল্প নেই, যা পূর্বনির্ধারিত এবং মূলত স্কেলেবিলিটি সীমাবদ্ধ করে। WebGL ব্যবহার করে এবং শেডার লিখে, এটি বিকাশকারীদের কম্পোজিশন মোড ব্যবহার করতে দেয় যা API দ্বারা পূর্বনির্ধারিত নয়। ভবিষ্যতে, পিক্সিভ স্কেচ বৃহত্তর পরিমাপযোগ্যতা এবং নমনীয়তার জন্য WebGL ব্যবহার করে স্তর বৈশিষ্ট্যটি বাস্তবায়ন করবে।
স্তর রচনার জন্য নমুনা কোড এখানে:
precision highp float;
uniform sampler2D baseTexture;
uniform sampler2D blendTexture;
uniform mediump float opacity;
varying highp vec2 uv;
// for normal mode
vec3 blend(const vec4 baseColor, const vec4 blendColor) {
return blendColor.rgb;
}
// for multiply mode
vec3 blend(const vec4 baseColor, const vec4 blendColor) {
return blendColor.rgb * blendColor.rgb;
}
void main()
{
vec4 blendColor = texture2D(blendTexture, uv);
vec4 baseColor = texture2D(baseTexture, uv);
blendColor.a *= opacity;
float a1 = baseColor.a * blendColor.a;
float a2 = baseColor.a * (1. - blendColor.a);
float a3 = (1. - baseColor.a) * blendColor.a;
float resultAlpha = a1 + a2 + a3;
const float epsilon = 0.001;
if (resultAlpha > epsilon) {
vec3 noAlphaResult = blend(baseColor, blendColor);
vec3 resultColor =
noAlphaResult * a1 + baseColor.rgb * a2 + blendColor.rgb * a3;
gl_FragColor = vec4(resultColor / resultAlpha, resultAlpha);
} else {
gl_FragColor = vec4(0);
}
}
বালতি ফাংশন সঙ্গে বড় এলাকা পেইন্টিং
পিক্সিভ স্কেচ আইওএস এবং অ্যান্ড্রয়েড অ্যাপগুলি ইতিমধ্যে বালতি বৈশিষ্ট্য সরবরাহ করেছে, তবে ওয়েব সংস্করণটি দেয়নি। বালতি ফাংশনের অ্যাপ সংস্করণ C++ এ প্রয়োগ করা হয়েছিল।
C++ এ ইতিমধ্যেই উপলব্ধ কোডবেস সহ, pixiv Sketch ওয়েব সংস্করণে বালতি ফাংশন বাস্তবায়নের জন্য Emscripten এবং asm.js ব্যবহার করেছে।
bfsQueue.push(startPoint);
while (!bfsQueue.empty()) {
Point point = bfsQueue.front();
bfsQueue.pop();
/* ... */
bfsQueue.push(anotherPoint);
}
asm.js ব্যবহার করে একটি পারফরম্যান্ট সমাধান সক্রিয় করা হয়েছে। বিশুদ্ধ জাভাস্ক্রিপ্ট বনাম asm.js এর এক্সিকিউশন টাইম তুলনা করে, asm.js ব্যবহার করে এক্সিকিউশন টাইম 67% ছোট করা হয়েছে। WASM ব্যবহার করার সময় এটি আরও ভাল হবে বলে আশা করা হচ্ছে।
পরীক্ষার বিবরণ:
- কিভাবে: বালতি ফাংশন সহ 1180x800px এলাকা পেইন্ট করুন
- টেস্ট ডিভাইস: MacBook Pro (M1 Max)
কার্যকর করার সময়:
- বিশুদ্ধ জাভাস্ক্রিপ্ট: 213.8ms
- asm.js: 70.3ms
Emscripten এবং asm.js ব্যবহার করে, pixiv স্কেচ প্ল্যাটফর্ম-নির্দিষ্ট অ্যাপ সংস্করণ থেকে কোডবেস পুনঃব্যবহার করে সফলভাবে বালতি বৈশিষ্ট্যটি প্রকাশ করতে সক্ষম হয়েছে।
আঁকার সময় লাইভ-স্ট্রিমিং
pixiv Sketch লাইভ ওয়েব অ্যাপের মাধ্যমে আঁকার সময় লাইভ-স্ট্রিম করার বৈশিষ্ট্যটি অফার করে। এটি getUserMedia()
থেকে প্রাপ্ত মাইক্রোফোন অডিও ট্র্যাক এবং <canvas>
উপাদান থেকে পুনরুদ্ধার করা MediaStream
ভিডিও ট্র্যাককে একত্রিত করে WebRTC API ব্যবহার করে।
const canvasElement = document.querySelector('#DrawCanvas');
const framerate = 24;
const canvasStream = canvasElement.captureStream(framerate);
const videoStreamTrack = canvasStream.getVideoTracks()[0];
const audioStream = await navigator.mediaDevices.getUserMedia({
video: false,
audio: {},
});
const audioStreamTrack = audioStream.getAudioTracks()[0];
const stream = new MediaStream();
stream.addTrack(audioStreamTrack.clone());
stream.addTrack(videoStreamTrack.clone());
উপসংহার
WebGL, WebAssembly এবং WebRTC-এর মতো নতুন API-এর শক্তির সাহায্যে আপনি ওয়েব প্ল্যাটফর্মে একটি জটিল অ্যাপ তৈরি করতে পারেন এবং যেকোনো ডিভাইস জুড়ে এটিকে স্কেল করতে পারেন। আপনি নিম্নলিখিত লিঙ্কগুলিতে এই কেস স্টাডিতে প্রবর্তিত প্রযুক্তিগুলি সম্পর্কে আরও জানতে পারেন:
- ওয়েবজিএল
- এছাড়াও WebGPU , WebGL-এর উত্তরসূরী পরীক্ষা করে দেখুন
- ওয়েব অ্যাসেম্বলি
- ওয়েবআরটিসি
- জাপানি ভাষায় মূল নিবন্ধ