A cross-platform 3D simulation/game engine implemented in Java 21, featuring JSON-defined worlds, interconnected environments, and real-time rendering.
- Requirements
- Architecture Overview
- Project Structure
- Core Concepts
- Configuration
- JSON Configuration
- Building and Running
- Controls
- Platform Support
- World Model: A container for multiple interconnected 3D environments
- 3D Environments: Support for both outdoor and indoor environments
- Environment Transitions: Seamless navigation between environments via portals/gateways
- Object System: Support for various object types:
- Actors: Intelligent entities (creatures, NPCs) with autonomous behavior
- Static Objects: Natural features (trees, rocks, flowers)
- Interactive Objects: Tools (shovel, key, fishing rod)
- Containers: Storage objects (chest, crate, suitcase)
- Player/Observer: First-person camera with keyboard/mouse controls
- JSON Configuration: World and environment definitions loaded from JSON files
- Menu System: ESC key triggers pause menu with exit option
- FPS Display: Optional frames-per-second counter for performance monitoring
- Language: Java 21
- Build System: Gradle with Groovy DSL
- Graphics: LWJGL 3 (Lightweight Java Game Library) with OpenGL
- Platforms: Windows 11, macOS, Linux, Raspberry Pi (x64 and arm64)
┌─────────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Engine │ │ Input │ │ Menu System │ │
│ │ (Game Loop)│ │ Handler │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Rendering Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Renderer │ │ Camera │ │ Shader Manager │ │
│ │ │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Model Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ World │ │ Environment │ │ GameObject │ │
│ │ │ │ (Indoor/ │ │ (Actor/Static/ │ │
│ │ │ │ Outdoor) │ │ Container) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Data Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ JSON Loader │ │ Mesh │ │ Resource Manager │ │
│ │ │ │ Loader │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Component | Description |
|---|---|
| Engine | Main game loop handling update/render cycles at 60 FPS |
| Input Handler | Processes keyboard/mouse input for player movement and actions |
| Menu System | Overlay UI for pause menu and game options |
| Renderer | OpenGL-based 3D rendering pipeline |
| Camera | First-person camera with position, rotation, and projection |
| Shader Manager | Compiles and manages GLSL shaders |
| World | Root container for all environments |
| Environment | 3D space containing objects, with bounds and portals |
| GameObject | Base class for all renderable entities |
| JSON Loader | Parses world/environment configuration files |
| Resource Manager | Caches textures, meshes, and other assets |
java_3d_concept/
├── build.gradle # Gradle build configuration
├── settings.gradle # Gradle settings
├── README.md # This file
├── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── sim3d/
│ │ ├── Main.java # Application entry point
│ │ ├── engine/
│ │ │ ├── Engine.java # Main game loop
│ │ │ ├── Settings.java # Application settings management
│ │ │ ├── Window.java # GLFW window management
│ │ │ └── Timer.java # Frame timing
│ │ ├── graphics/
│ │ │ ├── Renderer.java # OpenGL rendering
│ │ │ ├── Camera.java # First-person camera
│ │ │ ├── ShaderProgram.java # GLSL shader handling
│ │ │ ├── Mesh.java # 3D mesh data
│ │ │ ├── Texture.java # OpenGL texture management
│ │ │ ├── TextureLoader.java # Texture loading with STB
│ │ │ ├── MenuRenderer.java # UI menu rendering
│ │ │ ├── TextRenderer.java # Text rendering with STB
│ │ │ └── primitives/
│ │ │ └── PrimitiveFactory.java # All primitive mesh generators
│ │ ├── input/
│ │ │ ├── InputHandler.java # Keyboard/mouse input
│ │ │ └── MouseInput.java # Mouse movement tracking
│ │ ├── model/
│ │ │ ├── World.java # World container
│ │ │ ├── Environment.java # Base environment class
│ │ │ ├── OutdoorEnvironment.java # Outdoor specialization
│ │ │ ├── IndoorEnvironment.java # Indoor specialization
│ │ │ ├── Portal.java # Environment transition
│ │ │ ├── GameObject.java # Base object class
│ │ │ ├── Actor.java # Intelligent entities
│ │ │ ├── StaticObject.java # Inanimate objects
│ │ │ ├── Container.java # Storage objects
│ │ │ ├── Player.java # Player/observer
│ │ │ └── Transform.java # Position/rotation/scale
│ │ ├── loader/
│ │ │ ├── WorldLoader.java # JSON world parser
│ │ │ ├── EnvironmentLoader.java # JSON environment parser
│ │ │ ├── ObjLoader.java # Wavefront OBJ model loader
│ │ │ ├── Model.java # Loaded 3D model container
│ │ │ └── AssetManager.java # Model caching and management
│ │ └── ui/
│ │ └── MenuSystem.java # Menu management
│ └── resources/
│ ├── settings.json # Application configuration
│ ├── logback.xml # Logging configuration
│ ├── shaders/
│ │ ├── vertex.glsl # Vertex shader
│ │ ├── fragment.glsl # Fragment shader
│ │ ├── ui_vertex.glsl # UI vertex shader
│ │ └── ui_fragment.glsl # UI fragment shader
│ ├── models/ # 3D model assets
│ │ ├── rabbit.obj # Rabbit model
│ │ ├── tree.obj # Tree model
│ │ ├── rock.obj # Rock model
│ │ ├── cabin.obj # Cabin model
│ │ ├── table.obj # Table model
│ │ └── chair.obj # Chair model
│ ├── textures/
│ │ ├── grass_tile.jpg # Ground texture
│ │ └── grass2_tile.jpg # Alternative ground texture
│ ├── assets/ # Complex textured assets
│ │ └── spot/ # Spot cow model with textures
│ │ ├── spot_control_mesh.obj # Control mesh (not for use)
│ │ ├── spot_triangulated.obj # Triangulated mesh
│ │ ├── spot_quadrangulated.obj # Quad mesh
│ │ ├── spot_texture.png # Texture map
│ │ └── spot_texture.svg # SVG texture
│ └── Roboto.ttf # Font for UI text
│ └── worlds/
│ ├── demo_world.json # Demo world definition
│ ├── outdoor_forest.json # Outdoor environment
│ └── indoor_cabin.json # Indoor environment
└── docs/
├── texture-best-practices.md # Texture usage guide
└── texture-implementation-plan.md # Implementation details
The application uses two main configuration files:
The settings.json file contains application-wide configuration that can be customized by users:
{
"window": {
"fullscreen": true,
"width": 1920,
"height": 1080
},
"logLevel": "info",
"display": {
"showFPS": true
}
}| Field | Type | Default | Description |
|---|---|---|---|
window.fullscreen |
boolean | true | Start application in fullscreen mode |
window.width |
integer | 1920 | Window width in pixels (when not fullscreen) |
window.height |
integer | 1080 | Window height in pixels (when not fullscreen) |
logLevel |
string | "info" | Logging level: "trace", "debug", "info", "warn", "error" |
display.showFPS |
boolean | true | Show FPS counter in upper-right corner of screen |
- trace: Most verbose logging, includes all trace messages
- debug: Debug information useful for development (includes debug messages)
- info: General information about application operation (default)
- warn: Warning messages for potential issues
- error: Error messages only
The application first loads default settings from src/main/resources/settings.json, then overrides them with user settings from:
- A custom settings file specified via command line (
--settings <path>) - The root
settings.jsonfile if it exists and no custom file is specified
This allows for flexible configuration management where users can have multiple configuration files for different use cases.
The logback.xml file configures the logging framework. It uses the log.level property from settings to control the logging level for the com.sim3d package:
<logger name="com.sim3d" level="${log.level:-INFO}" />This allows dynamic configuration of logging levels without modifying the logging configuration file.
The World is the top-level container that holds all environments. It manages:
- Registry of all environments
- The currently active environment
- Environment transitions via portals
- Global game state
Environments are 3D spaces where gameplay occurs:
| Type | Description | Characteristics |
|---|---|---|
| OutdoorEnvironment | Open areas like forests, fields | Sky rendering, terrain, natural lighting |
| IndoorEnvironment | Enclosed spaces like buildings | Walls, ceiling, artificial lighting |
All entities in an environment inherit from GameObject:
GameObject (abstract)
├── Actor (abstract)
│ ├── Creature # Animals, monsters
│ └── NPC # Non-player characters
├── StaticObject
│ ├── NaturalFeature # Trees, rocks, flowers
│ └── Tool # Shovel, key, fishing rod
└── Container
├── Chest
├── Crate
└── StorageBin
Portals connect environments. When the player enters a portal's trigger zone, they transition to the linked environment at the specified spawn point.
{
"id": "demo_world",
"name": "Demo World",
"startEnvironment": "outdoor_forest",
"environments": [
"outdoor_forest.json",
"indoor_cabin.json"
]
}{
"id": "outdoor_forest",
"type": "outdoor",
"name": "Forest Clearing",
"bounds": {
"width": 100.0,
"height": 50.0,
"depth": 100.0
},
"spawnPoint": { "x": 0.0, "y": 1.0, "z": 0.0 },
"objects": [...],
"portals": [...]
}{
"id": "tree_01",
"type": "static",
"subtype": "natural_feature",
"name": "Oak Tree",
"model": "pyramid",
"modelPath": "models/tree.obj",
"transform": {
"position": { "x": 10.0, "y": 0.0, "z": 5.0 },
"rotation": { "x": 0.0, "y": 45.0, "z": 0.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
},
"color": { "r": 0.2, "g": 0.6, "b": 0.2 }
}| Field | Required | Description |
|---|---|---|
id |
Yes | Unique identifier for the object |
type |
Yes | Object type: static, actor, or container |
subtype |
No | Category: natural_feature, furniture, creature, etc. |
name |
No | Display name |
model |
No | Fallback primitive: cube, sphere, pyramid, cylinder |
modelPath |
No | Path to OBJ model file (e.g., models/tree.obj) |
transform |
No | Position, rotation, and scale |
color |
No | RGB color applied to the model |
The engine currently supports Wavefront OBJ format (.obj files).
Models are specified in JSON using the modelPath field:
{
"id": "rabbit_01",
"modelPath": "models/rabbit.obj",
"model": "sphere",
"color": { "r": 0.8, "g": 0.7, "b": 0.6 }
}- If
modelPathis specified and the file exists, the OBJ model is loaded - If loading fails, the engine falls back to the primitive specified in
model - The
colorfield applies a uniform color to the entire model
- Create your model in any 3D software (Blender, Maya, etc.)
- Export as Wavefront OBJ format
- Place the
.objfile insrc/main/resources/models/ - Reference it in JSON:
"modelPath": "models/your_model.obj"
The OBJ loader supports:
- Vertex positions (
v x y z) - Vertex normals (
vn x y z) - Texture coordinates (
vt u v) - Triangular and polygon faces (
f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3) - Multiple objects/groups (
o name,g name) - Negative indices (relative to end of list)
The engine supports PNG and JPG textures applied via UV mapping. To add a texture to an object:
{
"id": "my_textured_object",
"modelPath": "assets/mymodel/model.obj",
"texturePath": "assets/mymodel/texture.png",
"color": { "r": 1.0, "g": 1.0, "b": 1.0 }
}Important requirements:
- OBJ files must include texture coordinates (
vtlines) and faces must reference them (f v/vt/vn) - Use triangulated meshes for best results (not control meshes or subdivision surfaces)
- Texture images should be power-of-2 dimensions (512×512, 1024×1024, etc.)
- Keep color white
(1, 1, 1)for unmodified texture colors
For detailed guidance, see docs/texture-best-practices.md.
| Model | File | Description |
|---|---|---|
| Rabbit | models/rabbit.obj |
Low-poly rabbit with body, head, ears, tail |
| Tree | models/tree.obj |
Pine tree with trunk and foliage cones |
| Rock | models/rock.obj |
Irregular boulder shape |
| Cabin | models/cabin.obj |
Simple house with walls and roof |
| Table | models/table.obj |
Rectangular table with legs |
| Chair | models/chair.obj |
Chair with seat, back, and legs |
- Java 21 JDK
- Gradle 8.x (or use included wrapper)
# Build the project
./gradlew build
# Run the application
./gradlew run
# Create distribution
./gradlew distZip# Run with default settings
java -jar build/libs/java_3d_concept.jar
# Run with custom settings file
java -jar build/libs/java_3d_concept.jar --settings my_config.json
# Run with custom settings file (short form)
java -jar build/libs/java_3d_concept.jar -s /path/to/custom_settings.json
# Show help
java -jar build/libs/java_3d_concept.jar --help| Option | Short Form | Description | Example |
|---|---|---|---|
--settings <path> |
-s <path> |
Path to custom settings file | --settings config.json |
--help |
-h |
Show help message | --help |
The application first loads default settings from src/main/resources/settings.json, then overrides them with the specified custom settings file if provided. If the custom settings file doesn't exist, the application continues with default settings.
| Input | Action |
|---|---|
| W | Move forward |
| S | Move backward |
| A | Strafe left |
| D | Strafe right |
| Space | Move up (fly mode) |
| Left Shift | Move down (fly mode) |
| Mouse Move | Look around |
| ESC | Toggle pause menu |
| Enter | Confirm menu selection |
| Arrow Keys | Navigate menu |
| Platform | Architecture | Status |
|---|---|---|
| Windows 11 | x64 | ✅ Supported |
| Windows 11 | arm64 | ✅ Supported |
| macOS | x64 | ✅ Supported |
| macOS | arm64 (Apple Silicon) | ✅ Supported |
| Linux | x64 | ✅ Supported |
| Linux | arm64 | ✅ Supported |
| Raspberry Pi OS | arm64 | ✅ Supported |
LWJGL 3 provides native binaries for all supported platforms. The Gradle build automatically includes the appropriate natives based on the runtime platform.
This application can run on Raspberry Pi devices with proper graphics drivers installed. The application supports running in fullscreen mode directly on the framebuffer without requiring an X11 server or window manager.
- Raspberry Pi 4 or 5 (recommended)
- Raspberry Pi OS (Lite or Desktop) with arm64 architecture
- OpenGL ES 2.0+ compatible graphics drivers
- At least 1GB of available RAM
First, check what OpenGL drivers are currently installed:
# Check OpenGL version and renderer
glxinfo | grep -E "OpenGL version|OpenGL renderer"If glxinfo isn't installed:
# Install mesa-utils if not already present
sudo apt update
sudo apt install mesa-utilsFor Raspberry Pi 5 specific information:
# Check for VC6/V7 firmware (Pi 5 uses VC6)
vcgencmd versionFor Raspberry Pi 5, you'll want to use the proprietary drivers for best performance:
# Update package lists
sudo apt update
# Install the full proprietary driver stack
sudo apt install libraspberrypi-bin libraspberrypi-dev libraspberrypi-doc libraspberrypi0
# Install OpenGL ES libraries
sudo apt install libgles2-mesa-dev
# Install additional graphics libraries
sudo apt install libegl1-mesa-dev libgbm1 libgl1-mesa-dev
# Install firmware updates
sudo apt install raspberrypi-bootloaderEdit the boot configuration:
sudo nano /boot/firmware/config.txtAdd or ensure these lines are present:
# Enable DRM/KMS (Direct Rendering Manager/Kernel Mode Setting)
dtoverlay=vc4-kms-v3d
# GPU memory allocation (adjust based on your needs)
gpu_mem=128
# Enable 64-bit mode if not already enabled
arm_64bit=1
After installation and reboot:
# Reboot to apply changes
sudo reboot
# After reboot, verify OpenGL ES support
es2_infoSince you're running a Java application with LWJGL, you may also need:
# Install additional libraries that LWJGL might need
sudo apt install libxrandr2 libxinerama1 libxi6 libxcursor1 libxcomposite1 libasound2-devTo test if the drivers are working properly before running the Java application:
# Install a simple OpenGL ES test
sudo apt install glmark2-es2-wayland
# Run the benchmark
glmark2-es2-wayland- Build the application on the Raspberry Pi or transfer the built JAR file
- Ensure the settings.json file is configured for fullscreen mode (default)
- Run the application:
java -jar build/libs/java_3d_concept.jar
The application should launch in fullscreen mode directly on the framebuffer, bypassing any need for a window manager.
If you encounter any issues with the proprietary drivers, you can fall back to the open-source Mesa drivers:
sudo apt install mesa-utils-extra libgl1-mesa-driFor performance issues, consider:
- Increasing GPU memory allocation in config.txt
- Ensuring the Raspberry Pi is properly cooled
- Using a high-quality power supply
| Library | Version | Purpose |
|---|---|---|
| LWJGL | 3.3.3 | OpenGL, GLFW, STB bindings |
| JOML | 1.10.5 | Math library (vectors, matrices) |
| Gson | 2.10.1 | JSON parsing |
| SLF4J + Logback | 2.0.9 | Logging |
- Texture loading and mapping
- Text rendering system with font support
- UI menu system with text rendering
- SVG placeholder texture support
- FPS display counter
- Collision detection
- Actor AI and pathfinding
- Sound system
- Save/load game state
- Multiplayer support
- Physics engine integration
- Normal mapping and advanced materials
- Texture atlases for performance optimization
MIT License - See LICENSE file for details.