Şekil çiz

OpenGL ile çizilecek şekilleri tanımladıktan sonra, muhtemelen bu şekilleri çizmek istersiniz. OpenGL ES 2.0 ile şekil çizmek tahmin edebileceğinizden biraz daha fazla kod gerektirir çünkü API, grafik oluşturma ardışık düzeni üzerinde çok daha fazla kontrol sağlar.

Bu derste, önceki derste tanımladığınız şekillerin OpenGL ES 2.0 API'si kullanılarak nasıl çizileceği açıklanmaktadır.

Şekilleri başlat

Herhangi bir çizim yapmadan önce, çizmeyi planladığınız şekilleri başlatmalı ve yüklemelisiniz. Programınızda kullandığınız şekillerin yapısı (orijinal koordinatlar) yürütme sırasında değişmediği sürece bellek ve işleme verimliliği için bunları oluşturucunuzun onSurfaceCreated() yönteminde başlatmanız gerekir.

Kotlin

class MyGLRenderer : GLSurfaceView.Renderer {
    ...
    private lateinit var mTriangle: Triangle
    private lateinit var mSquare: Square

    override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
        ...
        // initialize a triangle
        mTriangle = Triangle()
        // initialize a square
        mSquare = Square()
    }
    ...
}

Java

public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...
    private Triangle mTriangle;
    private Square   mSquare;

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        // initialize a triangle
        mTriangle = new Triangle();
        // initialize a square
        mSquare = new Square();
    }
    ...
}

Şekil çizme

Grafik oluşturma hattına çok fazla ayrıntı sağlamanız gerektiğinden OpenGL ES 2.0 kullanarak tanımlanmış bir şekil çizmek için önemli miktarda kod gerekir. Özellikle aşağıdakileri tanımlamanız gerekir:

  • Vertex Gölgelendirici - Bir şeklin köşelerini oluşturmak için OpenGL ES grafik kodu.
  • Parça Gölgelendirici - Bir şeklin yüzünü renkler veya dokularla oluşturmak için OpenGL ES kodu.
  • Program - Bir veya daha fazla şekil çizmek için kullanmak istediğiniz gölgelendiricileri içeren bir OpenGL ES nesnesidir.

Bir şekil çizmek için en az bir köşe gölgelendiriciye, bu şekli renklendirmek için de bir parça gölgelendiriciye ihtiyacınız vardır. Bu gölgelendiriciler derlenmeli ve ardından, şekli çizmek için kullanılacak bir OpenGL ES programına eklenmelidir. Triangle sınıfında şekil çizmek için kullanabileceğiniz temel gölgelendiricileri nasıl tanımlayacağınızı gösteren bir örneği burada bulabilirsiniz:

Kotlin

class Triangle {

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

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

    ...
}

Java

public class Triangle {

    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;" +
        "}";

    ...
}

Gölgelendiriciler, OpenGL ES ortamında kullanılmadan önce derlenmesi gereken OpenGL Gölgeleme Dili (GLSL) kodu içerir. Bu kodu derlemek için oluşturucu sınıfınızda bir yardımcı program yöntemi oluşturun:

Kotlin

fun loadShader(type: Int, shaderCode: String): Int {

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    return GLES20.glCreateShader(type).also { shader ->

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

Java

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;
}

Şeklinizi çizmek için gölgelendirici kodunu derlemeniz, bunları bir OpenGL ES program nesnesine eklemeniz ve ardından programı bağlamanız gerekir. Bu işlemi, çizdiğiniz nesnenin oluşturucuda yapın, böylece sadece bir defa yapılır.

Not: OpenGL ES gölgelendiricilerini ve bağlantı programlarını derlemek, CPU döngüleri ve işleme süresi açısından pahalıdır. Bu nedenle, bunu bir kereden fazla yapmamanız gerekir. Çalışma zamanında gölgelendiricilerinizin içeriğini bilmiyorsanız kodunuzu yalnızca bir kez oluşturulup daha sonra kullanılmak üzere önbelleğe alınacak şekilde oluşturmanız gerekir.

Kotlin

class Triangle {
    ...

    private var mProgram: Int

    init {
        ...

        val vertexShader: Int = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        val fragmentShader: Int = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)

        // create empty OpenGL ES Program
        mProgram = GLES20.glCreateProgram().also {

            // add the vertex shader to program
            GLES20.glAttachShader(it, vertexShader)

            // add the fragment shader to program
            GLES20.glAttachShader(it, fragmentShader)

            // creates OpenGL ES program executables
            GLES20.glLinkProgram(it)
        }
    }
}

Java

public class Triangle() {
    ...

    private final int mProgram;

    public Triangle() {
        ...

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

        // create empty OpenGL ES Program
        mProgram = GLES20.glCreateProgram();

        // add the vertex shader to program
        GLES20.glAttachShader(mProgram, vertexShader);

        // add the fragment shader to program
        GLES20.glAttachShader(mProgram, fragmentShader);

        // creates OpenGL ES program executables
        GLES20.glLinkProgram(mProgram);
    }
}

Bu noktada, şeklinizi çizen gerçek çağrıları eklemeye hazırsınız. OpenGL ES ile şekil çizmek için, oluşturma hattına ne çizmek istediğinizi ve bunun nasıl çizileceğini bildirmek için birkaç parametre belirtmeniz gerekir. Çizim seçenekleri şekle göre değişebileceğinden, şekil sınıflarınızın kendi çizim mantığını içermesi iyi bir fikirdir.

Şekli çizmek için bir draw() yöntemi oluşturun. Bu kod, konum ve renk değerlerini şeklin köşe gölgelendiricisine ve parça gölgelendiricisine ayarlar ve ardından çizim işlevini yürütür.

Kotlin

private var positionHandle: Int = 0
private var mColorHandle: Int = 0

private val vertexCount: Int = triangleCoords.size / COORDS_PER_VERTEX
private val vertexStride: Int = COORDS_PER_VERTEX * 4 // 4 bytes per vertex

fun draw() {
    // Add program to OpenGL ES environment
    GLES20.glUseProgram(mProgram)

    // get handle to vertex shader's vPosition member
    positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition").also {

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

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

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor").also { colorHandle ->

            // Set color for drawing the triangle
            GLES20.glUniform4fv(colorHandle, 1, color, 0)
        }

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

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

Java

private int positionHandle;
private int colorHandle;

private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

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

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

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

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

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

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

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

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

Tüm bu kodları yerleştirdikten sonra, bu nesneyi çizmek için yalnızca oluşturucunuzun onDrawFrame() yönteminden draw() yöntemine çağrı yapılması gerekir:

Kotlin

override fun onDrawFrame(unused: GL10) {
    ...

    mTriangle.draw()
}

Java

public void onDrawFrame(GL10 unused) {
    ...

    mTriangle.draw();
}

Uygulamayı çalıştırdığınızda, uygulama aşağıdaki gibi görünecektir:

Şekil 1. Projeksiyon veya kamera görünümü olmadan çizilmiş üçgen.

Bu kod örneğinde birkaç sorun var. Öncelikle, arkadaşlarınızı etkilemeyeceksiniz. İkinci olarak, cihazın ekran yönünü değiştirdiğinizde üçgenin şekli biraz dardır. Şeklin eğik olmasının nedeni, nesnenin dik kenarlarının GLSurfaceView öğesinin görüntülendiği ekran alanının oranları için düzeltilmemiş olmasıdır. Bir sonraki derste projeksiyon ve kamera görünümü kullanarak bu sorunu çözebilirsiniz.

Son olarak, üçgen sabit olduğundan biraz sıkıcı. Hareket ekleme dersinde, bu şeklin dönmesini sağlayacak ve OpenGL ES grafik ardışık düzeninden daha ilginç bir şekilde yararlanacaksınız.