Simulateur VR / Projet d'école

DriveForest

Conduire en VR avec un téléphone comme volant

UnityC#VRRustOSCBlender

Le projet

DriveForest est un simulateur de conduite VR construit en 2026 dans le cadre d’un cours. On était deux : Alice Bert s’est occupée de la modélisation et de l’environnement, j’ai pris toute la partie tech.

Côté code, j’ai privilégié la largeur plutôt que la profondeur : cinq technologies branchées autour d’un gameplay qui tourne, plutôt qu’une seule bien polie. La boucle jouable fonctionne, le reste n’est pas finalisé.

Les cinq couches :

  • un client Unity (C#) pour le contrôleur véhicule et la VR
  • un serveur Rust pour lire les quaternions du téléphone via OSC
  • un téléphone comme volant physique via ZIGSIM
  • un pipeline PowerShell qui crée le workspace de chaque nouvel asset (arborescence de dossiers + fichiers DCC de base)
  • des addons DCC Python qui exposent ce pipeline dans les logiciels

Unity : contrôleur véhicule

J’ai écrit le contrôleur véhicule de zéro en C#. Car_Drive.cs gère la vitesse, l’accélération et un braquage proportionnel à la vitesse. Pour que la voiture colle au terrain, j’ai ajouté un ground-snap par raycast qui lit la normale du sol et aligne le véhicule dessus en temps réel.

Les entrées passent par trois scripts séparés. Car_Input.cs lit le clavier et la manette, Car_JoinControler.cs fusionne toutes les sources en un vecteur commun, et Car_Honk.cs déclenche le klaxon depuis n’importe laquelle (clavier, manette ou OSC réseau). Du coup, on branche le serveur Rust comme une manette et le reste du gameplay ne bouge pas.

Unity : VR et recentrage

La partie VR repose sur XR Interaction Toolkit. En VR, le recentrage pose problème : si le joueur met son casque sans être bien assis dans la direction du volant, tout est décalé.

J’ai écrit VR_SeatRecenter.cs pour corriger ça. Dès que le HMD est tracké, il recale le point de vue sur la position du siège virtuel défini dans la scène. J’ai aussi câblé un trigger de recentrage manuel via l’Input System, au cas où le joueur se retrouve quand même de travers en cours de partie.

Serveur Rust : quaternions et OSC

Le téléphone joue le rôle du volant. ZIGSIM tourne dessus et envoie les données IMU en OSC via UDP. Le serveur Rust écoute sur le port 50000 et reconstruit l’orientation du contrôleur physique à partir des quaternions reçus.

Les dépendances du serveur :

  • nalgebra 0.33 : calcul vectoriel et quaternions
  • eframe 0.30 : UI de debug embarquée
  • if-addrs 0.13 : liste des IP locales pour l’appairage

Pour l’angle de braquage, j’utilise UnitQuaternion pour calculer la rotation relative à une pose de référence calibrée. La projection sur l’axe voulu (braquage ou accélération) donne un float normalisé, avec inversion de signe si nécessaire selon l’orientation physique du téléphone.

Le serveur renvoie trois messages OSC à Unity sur 127.0.0.1:9000 :

  • /driveforest/steering : angle de braquage normalisé
  • /driveforest/accel : niveau d’accélération normalisé
  • /driveforest/honk : déclenché par un détecteur de shake sur le delta d’accéléromètre

L’UI debug eframe expose la calibration en quatre phases (turn right, turn left, accel, brake). Elle liste aussi les IP locales via if-addrs pour appairer le téléphone au PC facilement.

Pipeline d'assets PowerShell et addons DCC

En parallèle du gameplay, j’ai mis en place un mini-pipeline d’assets pour qu’Alice puisse itérer sur ses fichiers Blender et Substance Painter sans friction.

Deux scripts PowerShell font l’essentiel du pipeline : Create-AssetTemplate.ps1 crée la structure de dossiers et les fichiers de base d’un nouvel asset, et Increment-AssetVersion.ps1 versionne les fichiers d’asset.

Un troisième script gère l’installation et la mise à jour des plugins Substance Painter.

Pour que ce pipeline soit utilisable sans ouvrir un terminal, j’ai écrit deux addons Python : un pour Blender et un pour Substance Painter. Ils exposent ces actions directement dans les menus des DCC.

Livrable

Le livrable final se lance en deux processus côte à côte : Build_Unity/Unity_DriveSim.exe en standalone Windows, et le serveur Rust en parallèle. Une fois le téléphone appairé via ZIGSIM et le casque sur la tête, c’est jouable.

Équipe

VR Simulator / School project

DriveForest

5 technologies, 1 week, playable in headset

UnityC#VRRustOSCBlender

The project

DriveForest is a VR driving simulator built in one week in 2026 for a course. I worked with an artist: I did the tech, she modeled the environment and handled the visuals. With so little time, I spread the code across five stacks instead of polishing one: a Unity VR client, a Rust server, a phone IMU as steering wheel, a PowerShell pipeline that scaffolds each new asset workspace (folder tree and base DCC files), and Python DCC addons. They all connect around one gameplay loop you can play in the headset, though not everything is polished.

The Unity code

In Unity (C#), I wrote the vehicle controller from scratch: Car_Drive.cs handles speed, acceleration, speed-proportional steering, and a raycast-based ground snap that aligns the car to the terrain normal. Car_Input.cs, Car_JoinControler.cs and Car_Honk.cs aggregate input sources (keyboard, gamepad, network OSC). Keeping inputs separate means the Rust server plugs in like a gamepad and the rest of the gameplay doesn’t change.

The VR layer is built on XR Interaction Toolkit. If the player puts the headset on without sitting square to the wheel, everything is offset, so I wrote VR_SeatRecenter.cs to re-center the headset onto the virtual seat as soon as it starts tracking. A manual recenter trigger, wired through the Input System, covers the case where the player ends up crooked mid-game.

The Rust server: OSC and quaternions

The Rust server (nalgebra 0.33, eframe 0.30, if-addrs 0.13) listens for ZIGSIM OSC packets on UDP port 50000. It rebuilds the physical controller’s orientation from incoming quaternions, computes the angle relative to a calibrated reference via UnitQuaternion, projects onto the configured axis (steering / accel) with sign inversion, and pushes two normalized floats back to Unity at 127.0.0.1:9000 (/driveforest/steering, /driveforest/accel).

A shake detector on the accelerometer delta fires a /driveforest/honk. The eframe debug UI exposes a four-phase calibration (turn right/left, accel, brake) and lists local IPs via if-addrs so pairing is easy.

Asset pipeline

I also set up a small asset pipeline so she could work on her Blender and Substance Painter files without opening a terminal. In PowerShell, Create-AssetTemplate.ps1 creates the folders and base files of a new asset, Increment-AssetVersion.ps1 handles asset versioning, and a third script installs and updates the Substance Painter plugins.

Two Python addons, one for Blender and one for Substance Painter, expose these actions directly in the DCC menus.

Deliverable

You run Build_Unity/Unity_DriveSim.exe (a standalone Windows executable) and start the Rust server next to it. Once the phone is paired through ZIGSIM and the headset is on, it is playable.

Team