Definisci le forme

La prima cosa da fare è poter definire le forme da tracciare nel contesto di una visualizzazione OpenGL ES creando grafiche di fascia alta per la tua app. Disegnare con OpenGL ES può essere un po' complicato senza sapendo alcune cose di base su come OpenGL ES si aspetta di definire oggetti grafici.

Questa lezione illustra il sistema di coordinate OpenGL ES relativo allo schermo di un dispositivo Android, nozioni di base per la definizione di una forma e delle facce, nonché per la definizione di triangolo e quadrato.

Definisci un triangolo

OpenGL ES consente di definire gli oggetti disegnati utilizzando le coordinate nello spazio tridimensionale. Quindi, prima di poter disegnare un triangolo, occorre definirne le coordinate. In OpenGL, il modo tipico questo serve a definire un array di vertici di numeri in virgola mobile per le coordinate. Per il massimo efficienza, scrivi queste coordinate in un valore ByteBuffer, che viene passato all'interno Pipeline grafica OpenGL ES per l'elaborazione.

Kotlin

// number of coordinates per vertex in this array
const val COORDS_PER_VERTEX = 3
var triangleCoords = floatArrayOf(     // in counterclockwise order:
        0.0f, 0.622008459f, 0.0f,      // top
        -0.5f, -0.311004243f, 0.0f,    // bottom left
        0.5f, -0.311004243f, 0.0f      // bottom right
)

class Triangle {

    // Set color with red, green, blue and alpha (opacity) values
    val color = floatArrayOf(0.63671875f, 0.76953125f, 0.22265625f, 1.0f)

    private var vertexBuffer: FloatBuffer =
            // (number of coordinate values * 4 bytes per float)
            ByteBuffer.allocateDirect(triangleCoords.size * 4).run {
                // use the device hardware's native byte order
                order(ByteOrder.nativeOrder())

                // create a floating point buffer from the ByteBuffer
                asFloatBuffer().apply {
                    // add the coordinates to the FloatBuffer
                    put(triangleCoords)
                    // set the buffer to read the first coordinate
                    position(0)
                }
            }
}

Java

public class Triangle {

    private FloatBuffer vertexBuffer;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
    static float triangleCoords[] = {   // in counterclockwise order:
             0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
             0.5f, -0.311004243f, 0.0f  // bottom right
    };

    // Set color with red, green, blue and alpha (opacity) values
    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

    public Triangle() {
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (number of coordinate values * 4 bytes per float)
                triangleCoords.length * 4);
        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder());

        // create a floating point buffer from the ByteBuffer
        vertexBuffer = bb.asFloatBuffer();
        // add the coordinates to the FloatBuffer
        vertexBuffer.put(triangleCoords);
        // set the buffer to read the first coordinate
        vertexBuffer.position(0);
    }
}

Per impostazione predefinita, OpenGL ES assume un sistema di coordinate in cui [0,0,0] (X,Y,Z) specifica il centro di il frame GLSurfaceView, [1,1,0] è l'angolo in alto a destra del riquadro e [-1,-1,0] è l'angolo in basso a sinistra del riquadro. Per un'illustrazione di questo sistema di coordinate, vedere il Sviluppatore OpenGL ES .

Tieni presente che le coordinate di questa forma sono definite in ordine antiorario. Il disegno è importante perché definisce quale lato corrisponde alla faccia anteriore della forma, che in genere che desideri tracciare e la faccia posteriore, che puoi scegliere di non disegnare con la modalità OpenGL ES facciale. Per ulteriori informazioni su volti e eliminazione, vedi Guida per gli sviluppatori di OpenGL ES.

Definisci un quadrato

La definizione dei triangoli è abbastanza facile in OpenGL, ma cosa succede se vuoi ottenere complessi? Di', un quadrato? Ci sono molti modi per farlo, ma un percorso tipico per tracciare un in OpenGL ES consiste nell'utilizzare due triangoli disegnati insieme:

Figura 1. Disegno di un quadrato usando due triangoli.

Anche in questo caso, devi definire i vertici in ordine antiorario per entrambi i triangoli che rappresentano questa forma e inserisci i valori in un ByteBuffer. Per evitare definendo le due coordinate condivise da ciascun triangolo due volte, utilizza un elenco di disegni per indicare Pipeline grafica OpenGL ES come disegnare questi vertici. Ecco il codice per questa forma:

Kotlin

// number of coordinates per vertex in this array
const val COORDS_PER_VERTEX = 3
var squareCoords = floatArrayOf(
        -0.5f,  0.5f, 0.0f,      // top left
        -0.5f, -0.5f, 0.0f,      // bottom left
         0.5f, -0.5f, 0.0f,      // bottom right
         0.5f,  0.5f, 0.0f       // top right
)

class Square2 {

    private val drawOrder = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw vertices

    // initialize vertex byte buffer for shape coordinates
    private val vertexBuffer: FloatBuffer =
            // (# of coordinate values * 4 bytes per float)
            ByteBuffer.allocateDirect(squareCoords.size * 4).run {
                order(ByteOrder.nativeOrder())
                asFloatBuffer().apply {
                    put(squareCoords)
                    position(0)
                }
            }

    // initialize byte buffer for the draw list
    private val drawListBuffer: ShortBuffer =
            // (# of coordinate values * 2 bytes per short)
            ByteBuffer.allocateDirect(drawOrder.size * 2).run {
                order(ByteOrder.nativeOrder())
                asShortBuffer().apply {
                    put(drawOrder)
                    position(0)
                }
            }
}

Java

public class Square {

    private FloatBuffer vertexBuffer;
    private ShortBuffer drawListBuffer;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
    static float squareCoords[] = {
            -0.5f,  0.5f, 0.0f,   // top left
            -0.5f, -0.5f, 0.0f,   // bottom left
             0.5f, -0.5f, 0.0f,   // bottom right
             0.5f,  0.5f, 0.0f }; // top right

    private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

    public Square() {
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
        // (# of coordinate values * 4 bytes per float)
                squareCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(
        // (# of coordinate values * 2 bytes per short)
                drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);
    }
}

Questo esempio ti offre un'idea di ciò che serve per creare forme più complesse con OpenGL. Nella in generale si usano raccolte di triangoli per disegnare oggetti. Nella prossima lezione imparerai a disegnare queste forme sullo schermo.