Jeux Libres
       
           

» Les Forums » Aide à propos de la création de jeux vidéo » Les OBB


Aller à la page : 1.

Les OBB
Lo



Grade : Maître
Inscrit le: 26 Dec 2007, 17:33
Ecrit le: 25 Jan 2010, 12:34             Message non corrigé

Voilà je penses que j'ai trouver l'algorithme pour les intersections rayon boîtes orientée, je dis bien je pense parce que je ne suis pas très sûr du résultat, si quelqu'un vois une erreur, merci de signaler...

Je dois mettre au point la sélection multiple parce que elle ne marche pas encore trop bien, ensuite je pourrai enfin attaquer des choses plus guais comme le texturages, les lampes, pcq là j'en bave.


package wotck.editeur.selection;

import java.nio.FloatBuffer;

import javax.media.opengl.GL;

import wotck.editeur.Quaternion;
import wotck.editeur.Vec3t;

public class OrientedBoundingBox {
private Vec3t centre;
private float bu, bv, bw;
private float milieuX, milieuY, milieuZ;
private int axe;
private Vec3t intersection1, intersection2;
private Vec3t[] corners;

public OrientedBoundingBox (Vec3t centre,float largeur, float hauteur, float longueur, float teta, float phi, float gamma) {
this.centre = centre;
bv = teta;
bu = phi;
bw = gamma;
milieuX = largeur / 2;
milieuY = hauteur / 2;
milieuZ = longueur / 2;

intersection1 = new Vec3t (0, 0, 0);
intersection2 = new Vec3t (0, 0, 0);
corners = new Vec3t[8];
computeCorners();
}
private Vec3t[] computeCorners () {
Vec3t[] corners = new Vec3t[8];
corners[0] = centre.additionner(new Vec3t (-milieuX, -milieuY, -milieuZ));
corners[1] = centre.additionner(new Vec3t (milieuX, -milieuY, -milieuZ));
corners[2] = centre.additionner(new Vec3t (milieuX, -milieuY, milieuZ));
corners[3] = centre.additionner(new Vec3t (-milieuX, -milieuY, milieuZ));
corners[4] = centre.additionner(new Vec3t (-milieuX, milieuY, -milieuZ));
corners[5] = centre.additionner(new Vec3t (milieuX, milieuY, -milieuZ));
corners[6] = centre.additionner(new Vec3t (milieuX, milieuY, milieuZ));
corners[7] = centre.additionner(new Vec3t (-milieuX, milieuY, milieuZ));

for (int i = 0; i < 8; i++) {
Vec3t tmp = corners[i];
tmp = tmp.rotationQ(Vec3t.xAxis,(float) Math.acos(bv));
tmp = tmp.rotationQ(Vec3t.yAxis, (float) Math.acos(bu));
corners[i] = tmp.rotationQ(Vec3t.zAxis, (float) Math.acos(bw));
}
return corners;
}
public void drawAbb (GL gl) {
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glBegin(GL.GL_LINE_LOOP);
for (int i = 0; i < 4; i++)
gl.glVertex3fv(FloatBuffer.wrap(corners[i].getVec3t()));
for (int i = 4; i < 8; i++)
gl.glVertex3fv(FloatBuffer.wrap(corners[i].getVec3t()));
gl.glEnd();
gl.glBegin(GL.GL_LINES);
for (int i = 0, j = 4; j < 8; i++, j++) {
gl.glVertex3fv(FloatBuffer.wrap(corners[i].getVec3t()));
gl.glVertex3fv(FloatBuffer.wrap(corners[j].getVec3t()));
}
gl.glEnd();
}
public boolean intersect (Ray rayon) {
float tFar = Float.MAX_VALUE;
float tNear = -Float.MAX_VALUE;

//On calcule les valeurs de t1 et t2 par rapport aux 3 axes.
Vec3t co = centre.soustraire(rayon.getOrig());
Vec3t d = rayon.getDest().soustraire(rayon.getOrig());


for (int i = 0; i < 3; i++) {
float milieu, d1, d1prim, e;
Vec3t l, v;
switch (i) {
case 0 :
l = new Vec3t (0, co.getY(), co.getZ());
v = new Vec3t (0, d.getY(), d.getZ());
milieu = milieuX;
e = d.getVec3t()[i] - co.getVec3t()[i];
d1 = l.longueur() * bv;
d1prim = v.normalize().produitScalaire(l.normalize()) * v.longueur();
break;
case 1 :
l = new Vec3t (co.getX(), 0, co.getZ());
v = new Vec3t (d.getX(), 0, d.getZ());
milieu = milieuX;
e = d.getVec3t()[i] - co.getVec3t()[i];
d1 = l.longueur() * bu;
d1prim = v.normalize().produitScalaire(l.normalize()) * v.longueur();
break;
default :
l = new Vec3t (co.getX(), co.getY(), 0);
v = new Vec3t (d.getX(), d.getY(), 0);
milieu = milieuX;
e = d.getVec3t()[i] - co.getVec3t()[i];
d1 = l.longueur() * bw;
d1prim = v.normalize().produitScalaire(l.normalize()) * v.longueur();

}

//Si la direction de la droite avec l'axe est nulle et que l'origine est supérieur à la taille de la boîte.

if (d1prim < e) {
if (d1 < -milieu || d1 > milieu) {

return false;
}

}
float t1, t2;


t1 = (d1 - milieu) / d1prim;
t2 = (d1 + milieu) / d1prim;
float tmp;

if(t1>t2){
tmp = t1;
t1 = t2;
t2 = tmp;
} else
tmp = t1;

if (t1 > tNear) {

axe = i;
tNear = t1;
}

if (t2 < tFar) {

tFar = t2;
}


// on prend le plus grand t1 et le plus petit t2, et si t1 > t2, c'est que
// la droite rencontre la face droite avant la face gauche, et donc n'est pas dans
// la boite.

if (tNear > tFar) {

return false;
}


// (a uniquement mettre si ton rayon est orienté (si le cube ne peut pas être derrière l'origine du rayon))
// si l'intersection à lieu avant l'origine

if (tFar < 0) {

return false;
}


}

intersection1 = rayon.getOrig().additionner(d.scale(tNear, true, true, true));
intersection2 = rayon.getOrig().additionner(d.scale(tFar, true, true, true));
return true;

}
public boolean intersect (OrientedBoundingBox obb) {
for (int i = 0; i < 3; i++) {
float r, rPrim, c, cPrim;
//Recherche de l'axe séparateur.
switch (i) {
case 0 :
r = milieuX * bv + milieuY * bu;
c = centre.getX() * bv; break;
case 1 :
r = milieuX * bv + milieuZ * bw;
c = centre.getY() * bu; break;
default :
r = milieuY * bu + milieuZ * bw;
c = centre.getZ() * bw;
}
for (int j = 0; j < 3; j++) {

switch(j) {
case 0 :
rPrim = obb.milieuX * obb.bv + obb.milieuY * obb.bu;
cPrim = obb.centre.getX() * bv; break;
case 1 :
rPrim = obb.milieuX * obb.bv + obb.milieuZ * obb.bw;
cPrim = obb.centre.getY() * bu; break;
default :
rPrim = obb.milieuY * obb.bu + obb.milieuZ * obb.bw;
cPrim = obb.centre.getZ() * bw;
}

float ccPriml = c - cPrim;


if (ccPriml - (r + rPrim) >= 0)
return false;
}
}
return true;
}
public Vec3t getCentre() {
return centre;
}
public float getBu() {
return bu;
}
public float getBv() {
return bv;
}
public float getBw() {
return bw;
}
public float getHu() {
return milieuY;
}
public float getHv() {
return milieuX;
}
public float getHw() {
return milieuZ;
}
public Vec3t getIntersection () {
return intersection1;
}
public Vec3t getIntersection2 () {
return intersection2;
}
public String toString (){
return centre.toString()+ "\n"
+ bv + " "+bu+" "+bw+" "+milieuX+" "+milieuY+" "+milieuZ;
}
public static void main (String[] args) {
Vec3t center = new Vec3t (0, 0, 50);
float teta = 1f;
float phi = 1f;
float gamma = 1f;
OrientedBoundingBox obb = new OrientedBoundingBox (center, 50, 50, 50,teta, phi, gamma);
OrientedBoundingBox obb2 = new OrientedBoundingBox (center, 50, 50, 50, teta, phi, gamma);
System.out.println(obb.intersect(obb2));
Ray rayon = new Ray (new Vec3t(0, 20, -10), new Vec3t (0, 20, 100));
if (obb.intersect(rayon))
System.out.println(obb.intersection1+" "+obb.intersection2);
}

}


C'est surtout au niveau de la projection sur les axes à partir des angles et des demi-longueur des arrête de l'OBB que j'ai du mal à comprendre.
Mais si ça ne marche toujours pas je vais laisser tomber et utiliser de simple AABB tant pis si c'est moins précis pour la sélection.

________
Parce qu'on ne peut s'exprimer que par nos créations. ^^
  Profil
Lo



Grade : Maître
Inscrit le: 26 Dec 2007, 17:33
Ecrit le: 21 Fev 2010, 13:01             Message non corrigé

Erf non, en fait je me suis trompé, bv, bu et bw sont des vecteurs, et voilà donc ce que ça donne :

(J'ai mis le code en c++ parce que en java j'ai un bug graphique avec JOGL depuis que j'ai remis mon chipset à jour.)

N'en pêche, c'est amusant à programmer.

bool OBB::intersect (Ray &ray) {
    float tFar = INT_MAX;
    float tNear = -INT_MAX;
    Vec4f l = center - ray.getSource();
    Vec4f v = ray.getDir().normalize();


    for (int i = 0; i < 3; i++) {
        float hi, d1, e, d1prim;


        d1 = l.proj(bi[i]);
        if (i == 0) {
            d1prim = l.proj(bi[i] * this->hi.x);
            e = l.x - this->hi.x;
        } else if (i == 1) {
            d1prim = l.proj(bi[i] * this->hi.y);
            e = l.y - this->hi.y;
        } else {
            d1prim = l.proj(bi[i] * this->hi.z);
            e = l.z - this->hi.z;
        }
        //Le rayon ne coupe pas la bo?te.
        if (d1prim < e) {
            if (d1 < -hi || d1 > hi) {
                return false;
            }
        }

        float t1 = (d1 - hi) / d1prim;
        float t2 = (d1 + hi) / d1prim;
        float tmp;
        if (t1 > t2) {
            tmp = t1;
            t1 = t2;
            t2 = tmp;
        } else
            tmp = t1;

        if (t1 > tNear)
            tNear = t1;
        if (t2 < tFar)
            tFar = t2;
        //Le rayon intersecte la fasse gauche avant la face droite.

        if (tNear > tFar)
            return false;
        if (tFar < 0)
            return false;

    }

    zOrder = Math::abs(tNear);
    nearInt = ray.getSource() + ray.getDir()  * tNear;
    farInt = ray.getSource() + ray.getDir()  * tFar;
    return true;
}
 

Cool, me restera plus qu'à voir les hiérarchie de volume englobant et niveau détection de collision, se sera fait.
Par contre le reste, les chocs et tout ça..., enfin, au moins, ça fait passer le temps.

________
Parce qu'on ne peut s'exprimer que par nos créations. ^^
  Profil
 


Aller à la page : 1.


Hébergeur du site : David
Version PHP : 5.4.45-0+deb7u2
Uptime : 55 jours 19 heures 11 minutes
Espace libre : 1512 Mo
Dernière sauvegarde : 30/03/2020
Taille de la sauvegarde : 1113 Mo


5888953 pages ont été consultées sur le site !
Dont 2753 pages pendant les 24 dernières heures.

Page générée en 0.424 secondes


Nos sites préférés
- Création d'un jeu de plateforme de A à Z avec SDL
- Zelda ROTH : Jeux amateurs sur le thème de Zelda
- Zeste de Savoir : la connaissance pour tous et sans pépins
- YunoHost : s'héberger soi-même en toute simplicité
- Site de Fvirtman : recueil de projets et de codes en C et C++
- Par ici la sortie : le site des idées de sorties


  © 2005-2020 linor.fr - Toute reproduction totale ou partielle du contenu de ce site est strictement interdite.