LWJGL 3 exposes the entire OpenGL API as static Java methods, mirroring the C function names one-to-one. There is no object wrapper around a context — you work directly with integer handles for programs, shaders, buffers, and vertex arrays, exactly as you would in C. This guide starts from a working GLFW window (see Create Windows and Handle Input with GLFW) and walks through the additional OpenGL steps needed to draw geometry on screen.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/LWJGL/lwjgl3/llms.txt
Use this file to discover all available pages before exploring further.
LWJGL wraps OpenGL faithfully but does not define its semantics. Once you understand the LWJGL call patterns shown here, the OpenGL wiki and the official specification are the authoritative references for what each function does.
The OpenGL class hierarchy
LWJGL splits the OpenGL API across version-named classes. Import from the most specific class your application targets:| Class | Covers |
|---|---|
org.lwjgl.opengl.GL11C | OpenGL 1.1 core (glClear, glDrawArrays, …) |
org.lwjgl.opengl.GL15C | OpenGL 1.5 (glGenBuffers, glBindBuffer, glBufferData, …) |
org.lwjgl.opengl.GL20C | OpenGL 2.0 (glCreateShader, glCompileShader, glUseProgram, …) |
org.lwjgl.opengl.GL30C | OpenGL 3.0 (glGenVertexArrays, glBindVertexArray, …) |
org.lwjgl.opengl.GL | Capabilities bootstrap (GL.createCapabilities()) |
C-suffixed classes contain only core-profile functions. The non-C classes add compatibility-profile functions. Use the C variants for new code.
Create an OpenGL context via GLFW
Follow the windowing guide to create a GLFW window. Before making any OpenGL call, bind the context and initialise LWJGL’s capabilities:
GL.createCapabilities() is mandatory. It probes the driver, populates a thread-local GLCapabilities object, and sets up all the function pointers that LWJGL will use. Call it exactly once per thread that will issue GL commands.Install a debug message callback
During development, enable the OpenGL debug message extension so driver errors are reported immediately rather than surfacing as silent misbehaviour later.
GLUtil.setupDebugMessageCallback() checks for GL_KHR_debug or GL_ARB_debug_output, installs a callback that prints every message to System.err, and returns the callback object so you can free its native memory when you are done.Clear the screen
Set the background colour once and clear the framebuffer at the start of every frame:
GL_COLOR_BUFFER_BIT fills the colour attachment with the clear colour. GL_DEPTH_BUFFER_BIT resets depth values to 1.0 so depth testing works correctly for the new frame. This pattern is used in every LWJGL OpenGL sample.Upload vertex data with a VAO and VBO
Modern OpenGL stores geometry in GPU-side Vertex Buffer Objects (VBOs) and records the layout in a Vertex Array Object (VAO). The GLXGears sample demonstrates both:
GL_STATIC_DRAW tells the driver the data will be uploaded once and drawn many times. Use GL_DYNAMIC_DRAW for geometry that changes every frame.Compile and link GLSL shaders
The following pattern is used in Minimal GLSL shaders for the triangle above:Compile and link:
GLXGears.java to compile a vertex shader, a fragment shader, and link them into a program:Checking driver support at runtime
Use theGLCapabilities object returned (or accessible via GL.getCapabilities()) to branch on optional features:
GLXGears sample checks caps.OpenGL30 before calling glGenVertexArrays and falls back to per-bind attribute setup on older drivers.
Uniform variables
Pass per-draw data to shaders via uniform locations:Cleaning up
Free GPU resources in reverse order of creation. The Gears demo frees thedebugProc callback and the OpenGL capabilities buffer on shutdown:
glDeleteShader, glDeleteProgram, glDeleteBuffers, and glDeleteVertexArrays when they are no longer needed.