libGDX Android: Disegnare con OpenGL ES – Shader, Vertici e FrameLayout in Java (Parte 1)
In questa guida imparerai a usare libGDX OpenGL ES shader per disegnare grafica 2D su Android con Java, integrando vertici, Mesh e FrameLayout in un’unica applicazione. Questa è la prima parte di una serie dedicata allo sviluppo di applicazioni grafiche con libGDX, in cui esploreremo passo dopo passo come sfruttare le API di basso livello di OpenGL ES per creare rendering personalizzati, scrivere shader GLSL e integrare la surface OpenGL ES in un layout Android con FrameLayout. Se preferisci un approccio più tradizionale alla grafica 2D, consulta anche la guida su Canvas Android.

Prerequisiti per libGDX OpenGL ES shader su Android
Per seguire questa guida ti servono:
- Conoscenza base di Java
- Conoscenza base di Android Studio (creare e avviare un progetto)
- Android Studio installato (ultima versione stabile)
- Gradle configurato (normalmente incluso in Android Studio)
1. Introduzione a libGDX e OpenGL ES
Cos’è libGDX?
libGDX è un framework Java multipiattaforma pensato soprattutto per lo sviluppo di videogiochi, ma adatto anche a qualunque applicazione grafica avanzata (visualizzatori, simulazioni, prototipi UI custom). Inoltre, fornisce un layer di astrazione sopra OpenGL/OpenGL ES e gestisce per te molti dettagli complessi:
- Creazione della finestra / surface di rendering
- Gestione del ciclo di vita (create, render, resize, pause, resume, dispose)
- Gestione input (touch, tastiera, gamepad)
- Caricamento risorse (texture, font, audio, ecc.)
- Supporto multipiattaforma (Desktop, Android, iOS, HTML5)
Cos’è OpenGL ES e perché usarlo su Android
OpenGL ES (OpenGL for Embedded Systems) è una versione semplificata di OpenGL pensata per dispositivi mobili e embedded (Android, iOS, set-top box, ecc.). Di conseguenza, è lo standard di fatto per la grafica 2D/3D accelerata su Android.
Usare direttamente OpenGL ES richiede molto codice “boilerplate”. Tuttavia, libGDX si appoggia a OpenGL ES su Android, ma ti espone un’API Java più comoda. In altre parole, quando usi Mesh, ShaderProgram e altri componenti libGDX, sotto al cofano vengono eseguite chiamate OpenGL ES.
Perché usare libGDX + OpenGL ES su Android?
- Controllo totale sulla grafica: linee, triangoli, mesh 2D/3D, shader personalizzati.
- Prestazioni elevate: rendering GPU altamente ottimizzato.
- Portabilità: scrivi in Java, esegui su Desktop, Android (e altre piattaforme) con poche modifiche.
- Strumenti e community: tanti esempi, wiki, forum, progetti open source.
In questa serie useremo i libGDX OpenGL ES shader tramite l’API di basso livello (Mesh + ShaderProgram) per capire bene come dialogare con OpenGL ES.
2. Setup del progetto libGDX su Android Studio
Creare un nuovo progetto libGDX
Il modo consigliato è usare il Setup Application ufficiale di libGDX (un tool desktop che genera il progetto multipiattaforma). Tuttavia, per semplicità, in questa guida ci concentriamo sul modulo Android e sulla parte grafica.
Se utilizzi il setup ufficiale, otterrai una struttura di progetto simile a questa:
my-gdx-project/
├── core/ # Codice principale condiviso (Java)
├── android/ # Launcher Android + integrazione con OS
├── desktop/ # Launcher desktop (facoltativo)
└── gradle/ # Configurazione Gradle condivisa
Noi, in particolare, ci concentreremo su core (dove vivono Mesh e ShaderProgram) e su android (dove useremo FrameLayout).
Dipendenze Gradle
Nel modulo core, innanzitutto assicurati di avere la dipendenza libGDX nel build.gradle (versione indicativa, controlla sempre l’ultima sul sito ufficiale):
dependencies {
implementation "com.badlogicgames.gdx:gdx:1.12.0" // esempio di versione
}
Nel modulo android avrai qualcosa del genere:
dependencies {
implementation project(":core")
implementation "com.badlogicgames.gdx:gdx-backend-android:1.12.0"
// Per supporto audio facoltativo
implementation "com.badlogicgames.gdx:gdx-platform:1.12.0:natives-armeabi-v7a"
implementation "com.badlogicgames.gdx:gdx-platform:1.12.0:natives-arm64-v8a"
}
La versione 1.12.0 è solo un esempio: quindi usa la versione corrente indicata nella documentazione libGDX.
Struttura del codice
- core: contiene la tua classe
ApplicationListener(oGame) che rappresenta l’applicazione libGDX. Qui scriveremo il codice dei nostri esempi. - android: contiene l’Activity di lancio (tipicamente
AndroidLauncher) che crea e configura la view OpenGL ES e la integra con Android.
3. FrameLayout e integrazione con libGDX
Perché usare un FrameLayout con libGDX OpenGL ES?
Di default, il progetto libGDX Android usa una Activity che mostra solo la surface OpenGL (full-screen). Tuttavia, spesso vogliamo integrare il rendering con una UI Android standard: bottoni, Toolbar, overlay, ecc. In questo caso, un FrameLayout è una scelta semplice per ospitare la view di libGDX insieme ad altre view Android.
Esempio di layout XML con FrameLayout
Nel modulo android, per esempio crea un layout activity_main.xml come questo:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Qui inseriremo la view di libGDX a runtime -->
<Button
android:id="@+id/overlay_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Overlay UI"
android:layout_gravity="top|end"
android:layout_margin="16dp" />
</FrameLayout>
Integrazione in AndroidLauncher con AndroidApplicationConfiguration
La classe tipica di lancio Android estende AndroidApplication. Invece di usare initialize() (che crea e imposta direttamente la view), useremo initializeForView() per ottenere una view da aggiungere al nostro FrameLayout.
package com.mio.progetto.android;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.mio.progetto.MyGdxApp; // classe nel modulo core
public class AndroidLauncher extends AndroidApplication {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FrameLayout root = findViewById(R.id.root_frame);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useImmersiveMode = true; // facoltativo
config.useAccelerometer = false;
config.useCompass = false;
// Crea la view OpenGL ES di libGDX
View gameView = initializeForView(new MyGdxApp(), config);
// Aggiungi la view al FrameLayout
root.addView(gameView,
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
// Qui puoi configurare altri widget (es. il bottone overlay)
findViewById(R.id.overlay_button).setOnClickListener(v -> {
// Azione sul bottone, ad esempio pausa del gioco o apertura di un menu
});
}
}
In questo modo, la surface OpenGL ES di libGDX vive all’interno del tuo layout Android, sotto (o sopra) altri widget a seconda dell’ordine in cui li aggiungi.
4. Concetti base di OpenGL ES in libGDX
Sistema di coordinate normalizzato (NDC)
Quando lavori direttamente con Mesh e ShaderProgram, di solito operi in Normalized Device Coordinates (NDC), dove:
- L’asse X va da -1.0 a +1.0 orizzontalmente
- L’asse Y va da -1.0 a +1.0 verticalmente
- L’asse Z va da -1.0 a +1.0 in profondità (per 3D)
In questo spazio di coordinate:
- (0, 0) è il centro dello schermo
- (-1, -1) è l’angolo in basso a sinistra
- (+1, +1) è l’angolo in alto a destra
Viewport e dimensioni della finestra
La viewport è l’area dello schermo in cui OpenGL ES disegna. Di norma, libGDX la imposta automaticamente quando la finestra viene ridimensionata, ma puoi anche farlo manualmente con Gdx.gl.glViewport(x, y, width, height).
Nel metodo resize(int width, int height) della tua applicazione libGDX, puoi gestire il cambio di orientamento o di dimensioni della view. In questa prima parte, tuttavia, useremo coordinate NDC semplici e non introdurremo ancora le matrici di proiezione/visualizzazione (che tratteremo nella Parte 2).
5. Vertici e Mesh in libGDX
Cosa sono i vertici negli shader OpenGL ES di libGDX?
Un vertice è un punto nello spazio 2D/3D con una serie di attributi: tipicamente posizione, colore, coordinate di texture (UV) e altro. OpenGL ES, quindi, disegna triangoli a partire da questi vertici.
Per esempio, un vertice 2D con colore RGBA:
- posizione: (x, y)
- colore: (r, g, b, a)
Totale: quindi 6 valori float per vertice.
Cosa è una Mesh in libGDX con OpenGL ES shader?
Una Mesh in libGDX è un contenitore di vertici (e opzionalmente indici) pronto per essere inviato alla GPU. In particolare, definisci:
- Numero massimo di vertici
- Numero massimo di indici (facoltativo)
- Formato dei vertici (quali attributi: posizione, colore, UV, ecc.)
Per esempio, ecco un esempio di creazione di una Mesh che rappresenta un triangolo 2D colorato:
package com.mio.progetto;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
public class MyGdxApp implements ApplicationListener {
private Mesh triangleMesh;
@Override
public void create() {
// 3 vertici, nessun indice (disegniamo direttamente in ordine)
triangleMesh = new Mesh(true, 3, 0,
new VertexAttribute(Usage.Position, 2, "a_position"), // x, y
new VertexAttribute(Usage.ColorUnpacked, 4, "a_color") // r, g, b, a
);
// Definiamo i vertici: (x, y, r, g, b, a)
float[] vertices = new float[]{
// Vertice 1: in alto
0.0f, 0.5f, 1f, 0f, 0f, 1f, // rosso
// Vertice 2: in basso a sinistra
-0.5f, -0.5f, 0f, 1f, 0f, 1f, // verde
// Vertice 3: in basso a destra
0.5f, -0.5f, 0f, 0f, 1f, 1f // blu
};
triangleMesh.setVertices(vertices);
}
@Override
public void resize(int width, int height) { }
@Override
public void render() { }
@Override
public void pause() { }
@Override
public void resume() { }
@Override
public void dispose() {
if (triangleMesh != null) triangleMesh.dispose();
}
}
In questo esempio abbiamo definito solo la Mesh. Nel prossimo passo, quindi, vedremo come usare gli shader per disegnare effettivamente il triangolo sullo schermo.
6. Shader in libGDX (GLSL)
Vertex shader e fragment shader in libGDX OpenGL ES
In OpenGL ES moderno, non esistono più le “fixed pipeline” (funzioni predefinite) per trasformare e colorare i vertici. Di conseguenza, tutto passa da due piccoli programmi che scrivi tu in GLSL (OpenGL Shading Language): per scrivere un libGDX OpenGL ES shader, devi usare un vertex shader e un fragment shader.
- Vertex shader: eseguito per ogni vertice, calcola la posizione finale (e passa dati al fragment shader).
- Fragment shader: eseguito per ogni pixel (frammento) visibile del triangolo, calcola il colore finale da disegnare.
Esempio di vertex shader per un triangolo colorato
Creiamo un vertex shader semplice che, innanzitutto, prende posizione e colore da attributi del vertice e li passa al fragment shader:
// triangle.vert (vertex shader)
#ifdef GL_ES
precision mediump float;
#endif
// Attributi dal vertice (devono corrispondere ai nomi nella Mesh)
attribute vec2 a_position;
attribute vec4 a_color;
// Variazione verso il fragment shader
varying vec4 v_color;
void main() {
// Passiamo il colore al fragment shader
v_color = a_color;
// Convertiamo da vec2 a vec4 per clip space
gl_Position = vec4(a_position, 0.0, 1.0);
}
Esempio di fragment shader per un triangolo colorato
Il fragment shader, allo stesso modo, riceve il colore interpolato tra i vertici e lo scrive come colore finale del pixel:
// triangle.frag (fragment shader)
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
Creare uno ShaderProgram in libGDX
In libGDX, uno ShaderProgram compila e collega i sorgenti di un libGDX OpenGL ES shader in un unico programma utilizzabile per disegnare.
Possiamo caricare gli shader da stringhe (utile per esempi) o da file. Per semplicità, in questo caso useremo stringhe inline:
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class MyGdxApp implements ApplicationListener {
private Mesh triangleMesh;
private ShaderProgram shader;
@Override
public void create() {
// (Creazione della mesh come visto prima...)
String vertexShader =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"attribute vec2 a_position;\n" +
"attribute vec4 a_color;\n" +
"varying vec4 v_color;\n" +
"void main() {\n" +
" v_color = a_color;\n" +
" gl_Position = vec4(a_position, 0.0, 1.0);\n" +
"}\n";
String fragmentShader =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"varying vec4 v_color;\n" +
"void main() {\n" +
" gl_FragColor = v_color;\n" +
"}\n";
ShaderProgram.pedantic = false; // evita errori troppo severi
shader = new ShaderProgram(vertexShader, fragmentShader);
if (!shader.isCompiled()) {
Gdx.app.error("Shader", "Errore compilazione shader: " + shader.getLog());
}
}
// ... altri metodi
}
Con shader.isCompiled() verifichiamo che la compilazione sia andata a buon fine, altrimenti stampiamo il log di errore. Più avanti, nella sezione “Errori comuni e debug”, vedremo meglio come usare getLog().
7. Disegnare con ShaderProgram e Mesh
Il ciclo render() con shader OpenGL ES in libGDX
libGDX chiama il metodo render() della tua applicazione molte volte al secondo (tipicamente 60 fps). In questo metodo, quindi, devi:
- Pulire lo schermo (clear)
- Attivare lo shader (
begin()) - Disegnare la mesh (bind + draw)
- Disattivare lo shader (
end())
Esempio completo di draw con ShaderProgram e Mesh
@Override
public void render() {
// Puliamo lo schermo con uno sfondo grigio scuro
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Abilitiamo il blending per supportare alpha (se necessario)
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
// Iniziamo a usare lo shader
shader.begin();
// (Se avessimo uniform, qui settiamo i valori con shader.setUniformf / setUniformMatrix, ecc.)
// Disegniamo la mesh
triangleMesh.render(shader, GL20.GL_TRIANGLES);
// Fine utilizzo shader
shader.end();
}
Il metodo mesh.render(shader, mode) si occupa internamente di fare il bind degli attributi, abilitare gli array di vertici e inviare il draw call a OpenGL ES.
Nota: se usi indici nella mesh, puoi anche passare offset e count per specificare quanti indici disegnare.
8. Esempi pratici completi in Java
Esempio 1: Triangolo con colori interpolati
Questo esempio mostra un triangolo con un colore diverso per ogni vertice. OpenGL ES, di conseguenza, interpola i colori tra un vertice e l’altro, creando un gradiente.
package com.mio.progetto;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class ColoredTriangleExample implements ApplicationListener {
private Mesh mesh;
private ShaderProgram shader;
@Override
public void create() {
// 1) Creazione Mesh
mesh = new Mesh(true, 3, 0,
new VertexAttribute(Usage.Position, 2, "a_position"),
new VertexAttribute(Usage.ColorUnpacked, 4, "a_color"));
float[] vertices = new float[]{
// x, y, r, g, b, a
0.0f, 0.5f, 1f, 0f, 0f, 1f, // Rosso (alto)
-0.5f, -0.5f, 0f, 1f, 0f, 1f, // Verde (basso sx)
0.5f, -0.5f, 0f, 0f, 1f, 1f // Blu (basso dx)
};
mesh.setVertices(vertices);
// 2) Creazione Shader
String vertexShader =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"attribute vec2 a_position;\n" +
"attribute vec4 a_color;\n" +
"varying vec4 v_color;\n" +
"void main() {\n" +
" v_color = a_color;\n" +
" gl_Position = vec4(a_position, 0.0, 1.0);\n" +
"}\n";
String fragmentShader =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"varying vec4 v_color;\n" +
"void main() {\n" +
" gl_FragColor = v_color;\n" +
"}\n";
ShaderProgram.pedantic = false;
shader = new ShaderProgram(vertexShader, fragmentShader);
if (!shader.isCompiled()) {
throw new IllegalStateException("Errore compilazione shader: " + shader.getLog());
}
}
@Override
public void resize(int width, int height) {}
@Override
public void render() {
// Pulizia schermo
Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Blending opzionale
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
// Disegno
shader.begin();
mesh.render(shader, GL20.GL_TRIANGLES);
shader.end();
}
@Override
public void pause() {}
@Override
public void resume() {}
@Override
public void dispose() {
if (mesh != null) mesh.dispose();
if (shader != null) shader.dispose();
}
}
Cosa osservare:
- Ogni vertice ha il proprio colore RGBA.
- Il triangolo risultante mostrerà transizioni morbide di colore tra rosso, verde e blu.
- Non stiamo usando matrici: le coordinate NDC sono passate direttamente a
gl_Position.
Esempio 2: Quadrato con libGDX OpenGL ES shader personalizzato
In questo esempio disegneremo un quadrato (composto da due triangoli) e useremo uno shader che prende il colore da una uniform (stessa tinta per tutto il quadrato), invece che da un attributo per vertice.
Per costruire un quadrato, innanzitutto definiamo 4 vertici in un rettangolo centrato e due triangoli tramite indici.
package com.mio.progetto;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class ColoredSquareExample implements ApplicationListener {
private Mesh mesh;
private ShaderProgram shader;
private float time;
@Override
public void create() {
// 1) Mesh con 4 vertici (posizione 2D), 6 indici (2 triangoli)
mesh = new Mesh(true, 4, 6,
new VertexAttribute(Usage.Position, 2, "a_position"));
float size = 0.5f;
float[] vertices = new float[]{
// x, y
-size, size, // 0: alto sx
-size, -size, // 1: basso sx
size, -size, // 2: basso dx
size, size // 3: alto dx
};
short[] indices = new short[]{
0, 1, 2, // primo triangolo
2, 3, 0 // secondo triangolo
};
mesh.setVertices(vertices);
mesh.setIndices(indices);
// 2) Shader con uniform per il colore
String vertexShader =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"attribute vec2 a_position;\n" +
"void main() {\n" +
" gl_Position = vec4(a_position, 0.0, 1.0);\n" +
"}\n";
String fragmentShader =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"#endif\n" +
"uniform vec4 u_color;\n" +
"void main() {\n" +
" gl_FragColor = u_color;\n" +
"}\n";
ShaderProgram.pedantic = false;
shader = new ShaderProgram(vertexShader, fragmentShader);
if (!shader.isCompiled()) {
throw new IllegalStateException("Errore compilazione shader: " + shader.getLog());
}
}
@Override
public void resize(int width, int height) {}
@Override
public void render() {
// Aggiorniamo il tempo
time += Gdx.graphics.getDeltaTime();
// Pulizia schermo
Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Calcoliamo un colore che cambia nel tempo
float r = (float) ((Math.sin(time) + 1.0) / 2.0); // 0..1
float g = (float) ((Math.cos(time) + 1.0) / 2.0);
float b = 0.5f;
shader.begin();
// Passiamo la uniform u_color allo shader
shader.setUniformf("u_color", r, g, b, 1.0f);
mesh.render(shader, GL20.GL_TRIANGLES);
shader.end();
}
@Override
public void pause() {}
@Override
public void resume() {}
@Override
public void dispose() {
if (mesh != null) mesh.dispose();
if (shader != null) shader.dispose();
}
}
Osserva come u_color viene calcolato in base a time per creare un effetto di pulsazione del colore del quadrato.
9. Errori comuni e debug degli shader
Verificare la compilazione degli shader GLSL in libGDX
Gli errori negli shader GLSL sono tra i problemi più frequenti quando si inizia con OpenGL ES. Per questo, ogni volta che crei uno ShaderProgram, controlla isCompiled() e stampa il log:
shader = new ShaderProgram(vertexShader, fragmentShader);
if (!shader.isCompiled()) {
Gdx.app.error("Shader", "Errore compilazione: " + shader.getLog());
}
Se isCompiled() restituisce false, il testo di getLog() ti dirà quasi sempre:
- La riga esatta dove c’è un errore di sintassi (es. punto e virgola mancante).
- Eventuali variabili usate ma non dichiarate.
- Tipi incompatibili nelle operazioni (es. sommare un
vec3a unvec4).
Errori di mismatch tra Mesh e shader OpenGL ES in libGDX
Un altro errore classico è la mancata corrispondenza tra:
- Il nome dell’attributo nella
Mesh(es.new VertexAttribute(Usage.Position, 2, "a_position")) - Il nome dell’attributo nello shader (es.
attribute vec2 a_position;)
Devono essere identici (rispettando maiuscole/minuscole). Se sbagli nome, di conseguenza, quell’attributo potrebbe essere ignorato o ottimizzato via, portando a risultati inattesi (es. tutto nero o tutto in un angolo).
Versione di OpenGL ES e precision qualifier
Su Android è quasi sempre necessario specificare la precisione nei fragment shader:
#ifdef GL_ES
precision mediump float;
#endif
Se la ometti, potresti avere errori di compilazione su alcuni dispositivi (“precision qualifier is not specified” o simili).
Schermo nero con libGDX OpenGL ES shader: checklist veloce
- Shader compilato? Controlla
isCompiled()egetLog(). - Clear color nero? Potresti star disegnando, ma il triangolo è nero su sfondo nero.
- Coordinate fuori dallo schermo? Verifica che i vertici siano compresi tra -1 e +1 in NDC, se non usi matrici.
- Mesh vuota? Controlla che
setVertices()esetIndices()siano chiamati correttamente. - Uniform non settate? Se lo shader usa una
uniform(es.u_color), assicurati di chiamaresetUniformf()prima del draw.
10. Conclusione e anticipazione Parte 2
In questa prima parte abbiamo visto come:
- Impostare un progetto libGDX su Android e integrarlo in un
FrameLayoutconAndroidApplicationConfiguration. - Capire il sistema di coordinate NDC e il ruolo della viewport.
- Definire vertici e
Meshin libGDX, con attributi di posizione e colore. - Scrivere vertex shader e fragment shader in GLSL e creare uno
ShaderProgram. - Disegnare un triangolo e un quadrato colorati usando
Mesh.render()eShaderProgram.begin()/end(). - Debuggare errori comuni di compilazione shader.
Nella Parte 2 entreremo, infine, più in profondità in temi fondamentali per la grafica 2D/3D. Inoltre, se desideri vedere subito come utilizzare questi concetti in un progetto pratico, puoi consultare la guida su come creare un Gioco Pong su Android con OpenGL ES:
- Matrici di proiezione e vista (ortografica e prospettica).
- Trasformazioni (traslazione, rotazione, scala) applicate alla mesh.
- Gestione di più oggetti sulla scena.
- Introduzione alle texture (UV mapping) e sampling nei fragment shader.
Con queste basi, quindi, sei pronto a sperimentare cambiando vertici, colori e shader per creare i tuoi primi effetti grafici personalizzati con libGDX e OpenGL ES su Android.