OpenGL ES — to graficzny API o otwartej specyfikacji, przeznaczony dla systemów wbudowanych i mobilnych. Zapewnia sprzętowo przyspieszane renderowanie grafiki 2D i 3D poprzez programowalny potok shaderów. Według danych Khronos Group, 2025, OpenGL ES pozostaje najpopularniejszym graficznym API na urządzeniach mobilnych, obsługując ponad 10 miliardów instalacji na całym świecie. Biblioteka jest używana w grach, serwisach mapowych, aplikacjach AR i interfejsach na Androidzie i iOS.
Najważniejsze
OpenGL ES (Open Graphics Library for Embedded Systems) — to podzbiór desktopowego OpenGL API, zaadaptowany dla urządzeń mobilnych, konsol do gier i systemów wbudowanych. Specyfikacja jest opracowywana przez konsorcjum Khronos Group i dostępna bezpłatnie dla wszystkich producentów. W przeciwieństwie do desktopowego OpenGL, OpenGL ES usuwa przestarzałe funkcje stałego potoku, pozostawiając tylko programowalny potok shaderów — zmniejsza to zużycie energii i upraszcza sterowniki.
Głównym obszarem zastosowania OpenGL ES jest renderowanie grafiki w czasie rzeczywistym. API jest używane w grach mobilnych (Unity, Unreal Engine), aplikacjach nawigacyjnych, rozwiązaniach AR opartych na ARCore i ARKit, a także w interfejsach systemowych Android i iOS. Według danych StatCounter, 2026, udział urządzeń obsługujących OpenGL ES 3.0+ przekracza 92% wśród aktywnych smartfonów.
Kluczową zaletą OpenGL ES jest wieloplatformowość. Ta sama aplikacja napisana w OpenGL ES może działać na Androidzie, iOS, Linux i Windows z minimalnymi zmianami. To czyni API optymalnym wyborem dla projektów ukierunkowanych na wiele platform bez przepisywania silnika graficznego.
Wczesne wersje OpenGL (przed 2.0) używały stałego potoku — zestawu predefiniowanych etapów przetwarzania wierzchołków i pikseli. Deweloper mógł tylko skonfigurować parametry: położenie źródeł światła, właściwości materiałów, macierze transformacji. Programowalny potok, wprowadzony w OpenGL ES 2.0, zastąpił stałe etapy shaderami — małymi programami wykonywanymi na GPU. Dało to deweloperom pełną kontrolę nad wyświetlaniem geometrii.
Przejście na programowalny potok było rewolucją dla grafiki mobilnej. Deweloperzy zyskali możliwość implementacji złożonych efektów: PBR (Physically Based Rendering), dynamicznych cieni, postprocessingu i HDR. Stały potok wymagał mniej kodu, ale nie pozwalał na tworzenie unikalnych stylów wizualnych. Nowoczesne gry mobilne w pełni działają na programowalnym potoku.
Potok graficzny OpenGL ES składa się z kilku następujących po sobie etapów, z których każdy przekształca dane wejściowe na drodze od wierzchołków do pikseli na ekranie. Zrozumienie architektury potoku jest kluczowe dla optymalizacji wydajności renderowania na urządzeniach mobilnych z ograniczonym budżetem energetycznym i termicznym.
| Etap potoku | Przeznaczenie | Programowalny |
|---|---|---|
| Vertex Shader | Transformacja wierzchołków, zastosowanie macierzy model-widok-projekcja | Tak — GLSL |
| Tessellation | Podział geometrii (tylko ES 3.2) | Tak — GLSL |
| Geometry Shader | Generowanie nowej geometrii z prymitywów | Tak — GLSL |
| Rasterization | Konwersja prymitywów na fragmenty (piksele) | Nie — stałe |
| Fragment Shader | Obliczanie koloru każdego fragmentu, teksturowanie, oświetlenie | Tak — GLSL |
| Per-Fragment Operations | Depth test, stencil test, blending, scissor test | Konfiguracja parametrów |
Pierwszym etapem jest shader wierzchołków — przetwarza każdy wierzchołek niezależnie. Na tym etapie stosowane są transformacje: przejście z lokalnej przestrzeni modelu do przestrzeni świata, następnie do przestrzeni kamery i w końcu do przestrzeni obcięcia (clip space). Transformacje są zadawane przez uniform-macierze MVP (Model-View-Projection), które są aktualizowane w każdej klatce przy ruchu kamery lub obiektów.
Po złożeniu prymitywów (punktów, linii, trójkątów) następuje rasteryzacja — proces określania, które piksele ekranu pokrywa każdy prymityw. Rasteryzator generuje fragmenty — potencjalne piksele z interpolowanymi atrybutami (kolorem, normalnymi, współrzędnymi UV). Liczba fragmentów zależy bezpośrednio od rozdzielczości ekranu i pola projekcji prymitywu.
Shader fragmentów jest wykonywany dla każdego wygenerowanego fragmentu. Oblicza on końcowy kolor piksela z uwzględnieniem tekstur, źródeł światła i materiałów. Na wyjściu shadera fragmentów przechodzi seria testów per-fragment: depth test określa, czy fragment jest widoczny; stencil test ogranicza renderowanie według maski; blending miesza kolor fragmentu z kolorem już zapisanym w buforze ramki.
OpenGL ES działa jako automat stanów (state machine): wszystkie ustawienia — bieżący shader, powiązane tekstury, włączone testy — są przechowywane w globalnym stanie kontekstu. Zmiana stanu przez glEnable, glBindTexture lub glUseProgram wpływa na wszystkie kolejne polecenia rysowania. Każde przełączanie stanu powoduje narzuty w sterowniku, dlatego grupowanie wywołań draw według stanu jest podstawową techniką optymalizacji.
OpenGL ES 1.0 i 1.1 (wydane w latach 2003–2004) opierały się na stałym potoku. Obsługiwały transformacje, teksturowanie, oświetlenie i blending, ale nie pozwalały na programowanie shaderów. API było używane w pierwszych telefonach komórkowych i urządzeniach opartych na Symbian i Windows Mobile. Obecnie te wersje są uważane za przestarzałe — nowoczesne urządzenia ich nie obsługują.
OpenGL ES 2.0 (2007) wprowadził programowalny potok z shaderami wierzchołków i fragmentów w języku GLSL ES. Ta wersja stała się standardem dla Android 2.2+ i iOS 5+ i jest obsługiwana przez zdecydowaną większość urządzeń do dziś. OpenGL ES 2.0 — minimalna wersja wymagana do działania Unity, Unreal Engine i Cocos2d-x na platformach mobilnych.
OpenGL ES 3.0 (2012) dodał kilka kluczowych możliwości: wiele celów renderowania (MRT), transform feedback, instancing, tekstury dowolnego formatu przez ETC2/EAC. Wydajność renderowania wzrosła o 30–50% w porównaniu z wersją 2.0 dzięki zmniejszeniu liczby wywołań draw. OpenGL ES 3.1 (2014) wprowadził shadery obliczeniowe (compute shaders) i operacje atomowe na buforach — umożliwiło to wykonywanie na GPU nie tylko zadań graficznych, ale także obliczeniowych (postprocessing, symulacja tkanin, obliczenia fizyczne).
OpenGL ES 3.2 (2015) — ostatnia wersja specyfikacji — dodała shadery teselacyjne i geometryczne oraz rozszerzony zestaw float-tekstur i trybów blend. Pomimo wydania bardziej nowoczesnego Vulkan w 2016 roku, OpenGL ES 3.2 pozostaje aktualnym API dzięki ogromnej bazie istniejącego kodu i prostocie przenoszenia aplikacji między platformami.
| Wersja | Rok | Kluczowe możliwości | Kompatybilność (2026) |
|---|---|---|---|
| 1.x | 2003 | Stały potok, oświetlenie, tekstury | Przestarzała |
| 2.0 | 2007 | Programowalny potok, GLSL ES | 99% urządzeń |
| 3.0 | 2012 | MRT, instancing, ETC2, transform feedback | 92% urządzeń |
| 3.1 | 2014 | Shadery obliczeniowe, bufory atomowe | 80% urządzeń |
| 3.2 | 2015 | Teselacja, shadery geometryczne | 65% urządzeń |
GLSL ES (OpenGL Shading Language for Embedded Systems) — język programowania shaderów oparty na składni C z dodatkowymi typami do pracy z wektorami i macierzami. Każdy shader to program kompilowany do kodu maszynowego GPU na etapie inicjalizacji aplikacji. W przeciwieństwie do kodu CPU, shadery są wykonywane masowo-równolegle: tysiące wierzchołków lub fragmentów są przetwarzane jednocześnie.
Shader wierzchołków przetwarza każdy wierzchołek siatki. Jego głównym zadaniem jest obliczenie końcowej pozycji wierzchołka w clip space poprzez pomnożenie pozycji wejściowej przez macierz MVP. Ponadto shader wierzchołków może obliczać normale, współrzędne UV, kolory i przekazywać je do shadera fragmentów przez zmienne varying. Każde wywołanie shadera wierzchołków działa niezależnie, co pozwala GPU przetwarzać miliony wierzchołków w jednej klatce.
// Prosty shader wierzchołków dla OpenGL ES 3.0
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec2 a_texCoord;
uniform mat4 u_mvpMatrix;
out vec3 v_normal;
out vec2 v_texCoord;
void main() {
gl_Position = u_mvpMatrix * a_position;
v_normal = mat3(u_mvpMatrix) * a_normal;
v_texCoord = a_texCoord;
}
Shader fragmentów określa kolor każdego piksela na ekranie. Przyjmuje interpolowane wartości varying z shadera wierzchołków, pobiera teksela z powiązanych tekstur i stosuje oświetlenie. Do poprawnego oświetlenia używany jest model Phonga lub Blinna-Phonga z obliczaniem składowych diffuse, specular i ambient. Każde wywołanie shadera fragmentów odpowiada jednemu pikselowi, więc całkowita liczba wywołań jest równa polu projekcji obiektu na ekranie.
// Prosty shader fragmentów z teksturą i oświetleniem
#version 300 es
precision mediump float;
in vec3 v_normal;
in vec2 v_texCoord;
uniform sampler2D u_texture;
uniform vec3 u_lightDir;
out vec4 fragColor;
void main() {
vec4 texel = texture(u_texture, v_texCoord);
vec3 normal = normalize(v_normal);
float diffuse = max(dot(normal, u_lightDir), 0.0);
fragColor = vec4(texel.rgb * diffuse, texel.a);
}
W powyższym przykładzie shader fragmentów pobiera teksel z tekstury 2D według współrzędnych UV, oblicza oświetlenie diffuse jako iloczyn skalarny normalnej i kierunku światła, a następnie mnoży kolor teksela przez intensywność oświetlenia. Mediump — zalecana precyzja dla shaderów fragmentów na mobilnych GPU: zapewnia wystarczającą jakość przy minimalnym zużyciu energii.
Do pracy z OpenGL ES na Androidzie wymagane jest utworzenie kontekstu EGL — powierzchni, na którą będzie wyświetlana grafika. Na iOS używana jest warstwa EGL-podobna EAGL, dostarczana przez framework GLKit. W obu przypadkach proces inicjalizacji obejmuje utworzenie powierzchni okienkowej, konfigurację atrybutów kontekstu i powiązanie z bieżącym wątkiem renderowania.
// Inicjalizacja OpenGL ES 3.0 na Androidzie
class MyGLRenderer : GLSurfaceView.Renderer {
private val vertexShaderCode = "#version 300 es\n..."
private val fragmentShaderCode = "#version 300 es\n..."
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
GLES30.glClearColor(0.1f, 0.1f, 0.2f, 1.0f)
GLES30.glEnable(GLES30.GL_DEPTH_TEST)
}
override fun onDrawFrame(gl: GL10?) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
// bind VBO, set uniforms, draw elements
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES30.glViewport(0, 0, width, height)
}
}
Po utworzeniu kontekstu deweloper musi skonfigurować bufory: bufor wierzchołków (VBO) zawiera współrzędne wierzchołków, normale i UV; bufor indeksów (EBO) określa kolejność przechodzenia wierzchołków do formowania trójkątów. VAO (Vertex Array Object) łączy konfigurację wszystkich atrybutów w jeden obiekt, zmniejszając liczbę wywołań API przy zmianie meshy.
EGL (Native Platform Graphics Interface) — to warstwa pośrednia między OpenGL ES a systemem okienkowym. Na Androidzie EGL zarządza tworzeniem powierzchni rysowania, wyborem konfiguracji framebuffera (głębia koloru, stencil, MSAA) i synchronizacją z vsync. Typowa konfiguracja żąda RGBA8888 z 24-bitowym buforem depth i 8-bitowym buforem stencil. Na iOS rolę EGL pełni EAGL w połączeniu z CAEAGLLayer.
Optymalizacja wydajności OpenGL ES na urządzeniach mobilnych obejmuje kilka kluczowych praktyk. Używaj instancingu (glDrawArraysInstanced) do renderowania wielu identycznych obiektów — zmniejsza to liczbę wywołań draw. Stosuj pule tekstur i unikaj przełączania tekstur między wywołaniami draw. Sortuj obiekty według shadera, następnie według tekstury, a potem według mesha — taka kolejność minimalizuje przełączanie stanu kontekstu.
Metal — niskopoziomowe graficzne API od Apple, dostępne na iOS i macOS od układu A7. Metal zapewnia bezpośredni dostęp do GPU z minimalnymi narzutami sterownika, ale działa tylko na urządzeniach Apple. Według danych WWDC 2024, Metal zapewnia do 40% wyższą wydajność w porównaniu z OpenGL ES na tym samym sprzęcie dzięki zmniejszeniu liczby sprawdzeń stanu w czasie wykonania.
Vulkan — wieloplatformowy następca OpenGL ES, opracowany przez Khronos Group. Vulkan używa jawnego zarządzania zasobami: deweloper sam przydziela pule pamięci, tworzy bufory poleceń i synchronizuje dostęp do GPU. Daje to maksymalną kontrolę nad wydajnością, ale kod inicjalizacji Vulkan jest 3–4 razy obszerniejszy niż dla OpenGL ES. Vulkan jest zalecany dla gier AAA i aplikacji z wymagającą grafiką na Android 7+.
Wybór między OpenGL ES, Metal i Vulkan zależy od docelowych platform i wymagań wydajnościowych. OpenGL ES pozostaje najlepszym wyborem dla projektów wieloplatformowych, gdzie ważna jest szybkość rozwoju. Metal jest preferowany dla ekosystemu iOS/macOS z maksymalną wydajnością. Vulkan — wybór dla projektów, gdzie krytyczna jest każda milisekunda klatki, a budżet rozwoju pozwala na inwestycję w niskopoziomową optymalizację.
| Charakterystyka | OpenGL ES | Metal | Vulkan |
|---|---|---|---|
| Platformy | Android, iOS, Windows, Linux | iOS, macOS tylko | Android, Windows, Linux (iOS brak) |
| Poziom API | Wysoki (state machine) | Średni | Niski (explicit) |
| Kod inicjalizacji | 50–100 linii | 100–200 linii | 300–500 linii |
| Kontrola pamięci | Automatyczna | Półautomatyczna | W pełni ręczna |
| Wydajność | Podstawowa | +20–40% vs ES | +30–60% vs ES |
Często zadawane pytania
OpenGL ES — to podzbiór desktopowego OpenGL, z którego usunięto przestarzałe funkcje stałego potoku. OpenGL ES ma mniejszą objętość specyfikacji, uproszczony profil precyzji i jest zoptymalizowany pod kątem niskiego zużycia energii urządzeń mobilnych.
Android obsługuje OpenGL ES 2.0 na wszystkich urządzeniach, 3.0 — na Android 4.3+, 3.1 — na Android 5.0+, 3.2 — na wybranych urządzeniach z Android 7.0+. Aktualny poziom wsparcia można sprawdzić przez EGL_CONFIG_CAVEAT.
GLSL ES (OpenGL Shading Language for Embedded Systems) — język podobny do C z typami vec2/vec3/vec4/mat4 i wbudowanymi funkcjami texture, normalize, dot. Dla ES 3.0+ używana jest dyrektywa #version 300 es.
Tak, OpenGL ES pozostaje aktualny dla projektów wieloplatformowych, gdzie priorytetem jest szybkość rozwoju i wsparcie szerokiego spektrum urządzeń. Dla ekosystemu iOS lepiej uczyć się Metal, dla nowych projektów z maksymalną wydajnością — Vulkan.
Na Androidzie wywołaj GLES30.glGetString(GLES30.GL_VERSION) po utworzeniu kontekstu. Ciąg zawiera numer wersji i informację o producencie. Na iOS użyj [EAGLContext currentContext] i właściwości API.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również