বাংলায় অ্যান্ড্রয়েড সহায়িকা - Bangla Android Guide

শেপ অংকন/ ড্র করা

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

  • Vertex Shader – একটি শেপের শীর্ষবিন্দুগুলো (vertices) রেন্ডারিং করার জন্য OpenGL ES গ্রাফিক্স কোড

  • Fragment Shader – কালার এবং টেক্সচার দিয়ে একটি শেপের ফেস রেন্ডারিং করার জন্য OpenGL ES গ্রাফিক্স কোড

  • Program – একটি OpenGL ES অবজেক্ট যা শেডার ধারন করে যা আপনি এক বা একাধীক শেপ ড্র করার জন্য ব্যবহার করতে চান

আপনার একটি শেপ ড্র করার জন্য কমপক্ষে একটি ভারটেক্স শেডার লাগবে এবং ঐ শেপ রঙ করতে একটি ফ্রাগমেন্ট শেডার লাগবে। এই শেডগুলো অবশ্যই সংকলিত হতে হবে এবং তারপর একটি OpenGL ES program এ যুক্ত হতে হবে, তারপর এটাকে শেপ ড্র করার কাজে ব্যবহার করা হবে। এখানে একটি উদাহরণ আছে, কীভাবে একটি মৌলিক শেডার নির্ধারন করতে হয় যা আপনি একটি শেপ ড্র করার কাজে ব্যবহার করতে পারেন:

private final String vertexShaderCode =
    "attribute vec4 vPosition;" +
    "void main() {" +
    "  gl_Position = vPosition;" +
    "}";

private final String fragmentShaderCode =
    "precision mediump float;" +
    "uniform vec4 vColor;" +
    "void main() {" +
    "  gl_FragColor = vColor;" +
    "}";

শেডার OpenGL Shading Language (GLSL) কোড ধারন করে যা OpenGL ES পরিবেশে ব্যবহারের পূর্বে অবশ্যই সংকলিত হতে হবে। এই কোড সংকলন করতে আপনার রেন্ডারার ক্লাসে একটি ইউটিলিটি পদ্ধতি তৈরী করুন:

public static int loadShader(int type, String shaderCode){

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}

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

নোট: সংকলিত OpenGL ES শেডার এবং লিংক করা প্রোগ্রাম সিপিইউ সাইকেল এবং প্রসেসকরা সময়ের শর্তে ব্যয়বহুল, তাই আপনাকে এটা একবারের বেশী করাটা পরিহার করতে হবে। আপনি যদি রান টাইমে আপনার শেডারের কনটেন্ট সম্পর্কে না জানেন, আপনার উচিত আপনার কোড তৈরী করা যেমনভাবে তারা শুধু তৈরী করা জিনিসটা পেয়ে থাকে এবং পরবর্তী ব্যবহারের জন্য জমিয়ে রাখে। public class Triangle() { ...

    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables
}

এই মুহুর্তে, আপনি যথার্থ কল যুক্ত করতে প্রস্তুত হয়েছেন যা আপনার শেপ ড্র করে। OpenGL ES দিয়ে শেপ অংকন চায় রেন্ডারিং পাইপলাইনকে বলতে পান যে আপনি কি ড্র করতে চান এবং কীভাবে এটা ড্র করতে চান সেই জন্য আপনি কিছু প্যারামিটার নির্দিষ্ট করুন। যেহেতু ড্রয়িং অপশন শেপ দ্বারা ভিন্ন ভিন্ন হতে পারে, তাই এটা একটা ভালো চিন্তা যে আপনার শেপ ক্লাস তাদেও নিজস্ব ড্রয়িং লজিক (যুক্তি) ধারন করে।

শেপ ড্র করার জন্য একটি draw()পদ্ধতি তৈরী করুন। এই কোড শেপের ভারটেক্স শেডার এবং ফ্রাগমেন্ট শেডারে অবস্থান (পজিশন) এবং কালার ভ্যালু সেট করে, এবং তারপর ড্র করার কাজ সম্পাদন করে।

public void draw() {
    // Add program to OpenGL ES environment
    GLES20.glUseProgram(mProgram);

    // get handle to vertex shader's vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                                 GLES20.GL_FLOAT, false,
                                 vertexStride, vertexBuffer);

    // get handle to fragment shader's vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}

যখনই আপনার এই সকল কোড যথাস্থানে থাকবে, এই অবজেক্ট অংকন করতে শুধু আপনার রেন্ডারারের onDrawFrame()পদ্ধতির মধ্যে থেকে পদ্ধতিতে একটি কল করা প্রয়োজন। যযখন আপনি অ্যাপলিকেশনটি রান করবেন, এটা দেখতে অনেকটা এরকম দেখাবে:

ফিগার ১. একটি প্রজেকশন বা ক্যামেরা ভিউ ছাড়া অংকিত ত্রিভুজ

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

সর্বশেষটা হচ্ছে ত্রিভুজটি, অনড়, ডেটা একটু বিরক্তিকর। Adding Motion অনুশীলনীতে আপনি এই শেপকে রোটেট করতে পারবেন এবং OpenGL ES গ্রাফিক্স পাইপলাইন এর ব্যবহার আরও আকর্ষনীয় করবে।