Moteur De Jeu en 4 dimensions

Introduction

J’ai commencé cette année un projet de moteur de jeu, écrit en Kotlin. Le moteur de jeu se base sur la technologie du Raymarching, et l’approche utilisée permet des rendus et des calculs sur des objets définis en 3 ou 4 dimensions1.

Le rendu

Définition des objets

Objet Nombre de dimensions Paramètres
Cube 3 taille sur les axes x, y, z
Hyper cube 4 taille sur les axes x, y, z, w
Hyper sphère 4 rayon

Raymarching

J’ai implémenté un algorithme de raymarching, qui utilise une scène décrite par des SDFs2.

Voici une implémentation simple en GLSL, permettant d’envoyer un rayon :

float castRay(vec4 rayOrigin, vec3 rayDirection) {
    float epsilon = 0.001;
    float maxDistance = 100.0;
    float distance = 0.0;

    for (int i = 0; i < 1000; i++) {
        vec3 position = rayOrigin + rayDirection * distance;
        float objectDistance = map(position);
        distance += objectDistance;

        if (objectDistance < epsilon) {
            return distance;
        }
        else if(distance >= maxDistance) {
            return -1;
        }
    }
    return -1;
}

A chaque itération, la fonction effectue plusieurs étapes :
1. Calcul de la nouvelle position temporaire, en fonction de la direction du rayon et de la précédente distance,
2. Détermine la nouvelle distance à l’aide de la fonction map(position), qui renvoie la distance entre la position donnée et la scène,
3. Vérifie si la distance est inférieure à un epsilon donné, si oui, on considère q’un objet et touché et on renvoie la distance calculée,
4. Vérifie si on n’excède pas une limite de distance.

La fonction renvoie -1 si le rayon n’intersecte avec aucun objet.

Caméra

L’algorithme de raymarching est exécuté sur chaque pixel de l’écran, chaque pixel est associé à une position et une direction dans la scène. On peut convertir la position p du pixel (qui est dans un espace normalisé entre 0 et 1 sur les axes x et y) en direction d avec la relation suivante :
formule1

On utilise les constantes aspect ratio et fov qui sont respectivement le rapport largeur/hauteur de l’écran, et l’angle du champ de vision de la caméra.

Exemples de rendu

Simple sphère (à gauche) et hyper cube (à droite)

Les physiques

Possédant des fonctions permettant de mesurer la distance entre un point et un objet, il est facile de déterminer si deux objets sont en collision et y répondre.
Voici un exemple de code présent dans le moteur permettant de savoir si deux objets sont effectivement en collision :

fun detect() {
    for (i in objectsPairs) {
        val data = collisionData(i.first, i.second)
        if (data.distance <= 0) {
            // Si la distance est négative, les objets sont en collision
            collidingObjetcs.add(data)
        }
    }
}

Afin de repousser deux objets entre eux dans la direction n, on reflète les vecteurs normaux a et b résultant de la collision en utilisant la relation suivante :
formule2

Statut du projet


Liens externes


  1. La 4ème dimension est un axe imaginaire en plus des axes x, y et z. Il est noté w.↩︎

  2. SDF : Signed Distance Function, la fonction renvoyant la distance entre un point et l’objet, la distance est positive si le point est à l’extérieur de l’objet, négative sinon.↩︎