اعمال کردن نماهای دوربین و فرافکنی

در محیط OpenGL ES، نماهای دوربین و فرافکنی به شما امکان می‌دهند اشیای ترسیم‌شده را به‌گونه‌ای نمایش دهید که بیشتر شبیه به نحوه دیدن اشیای فیزیکی با چشمانتان باشد. این شبیه‌سازی مشاهده فیزیکی با تبدیل‌های ریاضی مختصات شیء ترسیم‌شده انجام می‌شود:

  • طرح‌افکنی - این تبدیل، مختصات اشیای ترسیم‌شده را براساس عرض و ارتفاع GLSurfaceView که در آن نمایش داده می‌شوند تنظیم می‌کند. بدون این محاسبه، اشیای ترسیم‌شده توسط OpenGL ES به‌دلیل نسبت‌های نابرابر پنجره نما کج می‌شوند. تبدیل تصویر معمولاً فقط زمانی باید محاسبه شود که نسبت‌های نمای OpenGL در روش onSurfaceChanged() رندرکننده شما ایجاد یا تغییر کرده باشد. برای اطلاعات بیشتر درباره طرح‌افکنی‌های OpenGL ES و نگاشت مختصات، به نگاشت مختصات برای اشیاء ترسیم‌شده مراجعه کنید.
  • نمای دوربین - این تبدیل مختصات اشیای ترسیم‌شده را براساس موقعیت دوربین مجازی تنظیم می‌کند. توجه به این نکته مهم است که OpenGL ES شیء دوربین واقعی را تعریف نمی‌کند، بلکه درعوض روش‌های کاربردی‌ای ارائه می‌دهد که با تبدیل نمایش اشیای ترسیم‌شده، دوربین را شبیه‌سازی می‌کند. تبدیل نمای دوربین ممکن است فقط یک‌بار هنگام ایجاد GLSurfaceView محاسبه شود، یا ممکن است به‌طور پویا براساس کنش‌های کاربر یا عملکرد برنامه شما تغییر کند.

این درس نحوه ایجاد نمای دوربین و تصویر و اعمال آن بر شکل‌های ترسیم‌شده در GLSurfaceView را شرح می‌دهد.

تعریف کردن تصویرسازی

داده‌های تبدیل فرافکنی در روش onSurfaceChanged() کلاس GLSurfaceView.Renderer شما محاسبه می‌شود. کد نمونه زیر ارتفاع و عرض GLSurfaceView را می‌گیرد و از آن برای پر کردن تبدیل تصویر Matrix بااستفاده از روش Matrix.frustumM() استفاده می‌کند:

کاتلین

// vPMatrix is an abbreviation for "Model View Projection Matrix"
private val vPMatrix = FloatArray(16)
private val projectionMatrix = FloatArray(16)
private val viewMatrix = FloatArray(16)

override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
    GLES20.glViewport(0, 0, width, height)

    val ratio: Float = width.toFloat() / height.toFloat()

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
}

جاوا

// vPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] vPMatrix = new float[16];
private final float[] projectionMatrix = new float[16];
private final float[] viewMatrix = new float[16];

@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}

این کد یک ماتریس تصویرسازی را پر می‌کند، mProjectionMatrix که سپس می‌توانید آن را با یک تبدیل نمای دوربین در روش onDrawFrame() ترکیب کنید، که در بخش بعدی نشان داده شده است.

توجه: فقط اعمال تبدیل فرافکنی به اشیاء طراحی معمولاً منجر به نمایش بسیار خالی می‌شود. به‌طور کلی، باید تبدیل نمای دوربین را نیز اعمال کنید تا هر چیزی روی صفحه‌نمایش نشان داده شود.

تعریف کردن نمای دوربین

فرایند تبدیل اشیای ترسیم‌شده را با افزودن تبدیل نمای دوربین به‌عنوان بخشی از فرایند ترسیم در پردازنده گرافیکی‌تان تکمیل کنید. در کد نمونه زیر، تبدیل نمای دوربین بااستفاده از روش Matrix.setLookAtM() محاسبه می‌شود و سپس با ماتریس تصویر محاسبه‌شده قبلی ترکیب می‌شود. سپس ماتریس‌های تبدیل ترکیبی به شکل ترسیم‌شده منتقل می‌شوند.

کاتلین

override fun onDrawFrame(unused: GL10) {
    ...
    // Set the camera position (View matrix)
    Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)

    // Calculate the projection and view transformation
    Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0)

    // Draw shape
    triangle.draw(vPMatrix)

جاوا

@Override
public void onDrawFrame(GL10 unused) {
    ...
    // Set the camera position (View matrix)
    Matrix.setLookAtM(viewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    // Calculate the projection and view transformation
    Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);

    // Draw shape
    triangle.draw(vPMatrix);
}

اعمال تبدیل‌های دوربین و فرافکنی

برای استفاده از ماتریس تبدیل نمای دوربین و تصویر ترکیبی نشان‌داده‌شده در بخش‌های پیش‌نمایش، ابتدا متغیر ماتریس را به سایه‌زن رأس که قبلاً در کلاس Triangle تعریف شده است اضافه کنید:

کاتلین

class Triangle {

    private val vertexShaderCode =
            // This matrix member variable provides a hook to manipulate
            // the coordinates of the objects that use this vertex shader
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            // the matrix must be included as a modifier of gl_Position
            // Note that the uMVPMatrix factor *must be first* in order
            // for the matrix multiplication product to be correct.
            "  gl_Position = uMVPMatrix * vPosition;" +
            "}"

    // Use to access and set the view transformation
    private var vPMatrixHandle: Int = 0

    ...
}

جاوا

public class Triangle {

    private final String vertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +
        "attribute vec4 vPosition;" +
        "void main() {" +
        // the matrix must be included as a modifier of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        "  gl_Position = uMVPMatrix * vPosition;" +
        "}";

    // Use to access and set the view transformation
    private int vPMatrixHandle;

    ...
}

سپس، روش draw() اشیای گرافیکی‌تان را اصلاح کنید تا ماتریس تبدیل ترکیبی را بپذیرد و آن را روی شکل اعمال کند:

کاتلین

fun draw(mvpMatrix: FloatArray) { // pass in the calculated transformation matrix
    ...

    // get handle to shape's transformation matrix
    vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix")

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0)

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

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(positionHandle)
}

جاوا

public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix
    ...

    // get handle to shape's transformation matrix
    vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0);

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

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

وقتی تبدیل‌های نمای دوربین و تصویر را به‌درستی محاسبه و اعمال کردید، اشیاء گرافیکی شما با نسبت‌های صحیح ترسیم می‌شوند و باید شبیه به این باشند:

شکل ۱. مثلثی که با اعمال نمای دوربین و تصویرسازی کشیده شده است.

اکنون که برنامه‌ای دارید که شکل‌هایتان را با نسبت‌های صحیح نمایش می‌دهد، وقت آن است که به شکل‌هایتان حرکت اضافه کنید.