2010-10-18 6 views
1

En openGL, j'ai un modèle 3D sur lequel j'effectue une intersection rayon-triangle, en utilisant le code expliqué dans l'article "Fast, Minimum Storage Ray/Triangle Intersection" (http://jgt.akpeters.com/papers/MollerTrumbore97/).Transformation de rayon pour l'intersection rayon-triangle

Ma position du curseur est non projeté dans l'espace du monde en utilisant le code suivant:

bool SCamera::unproject(Vector3 input, Vector3 & output){ 

    GLint viewport[4]; 
    glGetIntegerv(GL_VIEWPORT,viewport); //Grab screen info 

    float x = input.mX; 
    float y = input.mY; 
    float z = input.mZ; 

    Matrix4 P, Mv, res; 

    P = getProjection(); 
    Mv = getCameraTransform(); 

    Vector3 N; //Cursor point translated to having 0,0 at screen center 
    N.mX = ((x-viewport[0])/viewport[2])*2 - 1; 
    N.mY = ((y-viewport[1])/viewport[3])*2 - 1; 
    N.mZ = z*2-1; 

    res = P * Mv; //Multiply P * Mv to get transform 
    Vector3 w = res.inverse() * N; //Apply transform to N. 

    output.mX = w[0]; 
    output.mY = w[1]; 
    output.mZ = w[2]; 
    return true; 
} 

Après cela, je forme un rayon en procédant comme suit:

unproject(Vector3(xClick, yClick,0),resultUnproject) 
ray.origin = cameraPosition; 
ray.direction = resultUnproject - ray.origin; 
ray.direction.normalize(); 

Maintenant, enfin je suis en train pour exécuter ce rayon à travers le code triangle (lié ci-dessus), mais je ne peux pas sembler le transformer correctement. Ma tentative actuelle est la suivante:

Matrix4 mview, T; 
mview = getModelview(); 
T = mview.inverse(); 
ray.origin = T*ray.origin; 
ray.direction = T*ray.direction; 
ray.direction.normalize(); 

Pour une raison quelconque, cela ne fonctionne pas. Est-ce que je forme mal mon rayon? Ou le transformer mal?

Répondre

0

J'ai finalement réussi à faire fonctionner ce système, même si je ne suis pas satisfait de la façon dont cela fonctionne. Dans mon cas, la rotation individuelle du modèle est appliquée comme une transformation avant le rendu, j'ai donc dû transformer le triangle cible par la matrice modelview. Ce que j'essayais de faire ci-dessus était de calculer un rayon qui servirait le même but, en déplaçant l'origine du rayon autour de l'objet, comme si l'objet avait été tourné. Malheureusement, je n'arrivais pas à bien comprendre les mathématiques. Le résultat final signifie une transformation par triangle, au lieu d'une par rayon. Heureusement, il ne semble pas être si mauvais d'un coup de performance, car je ne l'utilise que pour le picking.

2

Une méthode pourrait être:

Prenez votre origine de rayon, et d'élaborer un point à une distance de l'unité dans la direction du rayon dans l'espace mondial. Ensuite, faites votre transformation aux deux points, c'est-à-dire multipliez-la par l'inverse de la matrice de transformation. Vous pouvez ensuite déterminer la nouvelle direction du rayon à partir de la différence entre les deux points traduits. Vérifier si cette direction est différente de l'original vous indiquera rapidement s'il vous manque une étape.

+0

Génial! C'est une très bonne façon de déboguer des choses auxquelles je n'avais pas pensé. Merci. –

+0

Malheureusement, j'ai toujours des problèmes. Pourriez-vous regarder au-dessus des extraits de code court énumérés ci-dessus? –

+0

@Ian - Je ne pense pas que je puisse être d'une grande aide, car c'est un peu éloigné des trucs OGL auxquels je suis habitué, et je suis un quaternion;) La formation du rayon semble un peu soupçonnez-moi - habituellement avec glFrustum, vous pouvez travailler sur une 'pyramide' avec l'utilisateur à (0,0) et l'écran en bas - la base dépend * de * la taille de la fenêtre et des plages de coordonnées. – sje397

2

Ma solution à ceci était de faire ce que sje397 a suggéré mais juste utiliser le résultat comme votre nouveau rayon.

Donc dans mon projet (qui est XNA), étant donné ray non projeté du curseur:

rayTransform = Matrix.Invert(model_transform); 

//Transform ray (or more accurately its defining components into a new ray) 
Vector3 v1 = Vector3.Transform(ray.Position, rayTransform); 
Vector3 v2 = Vector3.Transform((ray.Position + ray.Direction), rayTransform); 
transformedray = new Ray(v1, v2 - v1); 

model_transform ici est généré la même manière que la transformation pour le shader (pas de multiplications Monde/Local swapping ou quoi que ce soit)

Cela fonctionne très bien dans mon projet avec la cible de la sélection étant tournée, transformée et mise à l'échelle de toutes sortes de façons.

En outre, vous pouvez trouver cela un peu plus important, mais si vous avez toujours des problèmes, êtes-vous sûr que le code pour annuler le projet et générer le rayon de prélèvement fonctionne correctement? J'imagine que ça devrait être le cas si votre code de sélection de triangle fonctionne, c'est juste que ça m'a l'air d'obtenir le rayon de façon «ronde».

Dans mon projet, je prends deux points, un 'sur' le 'plan' de la fenêtre, donc Vector3(cursorx,cursory,0) encore une fois mais avancé sur l'axe Z Vector3(cursorx,cursory,1).Ne projetez pas ces deux points, le résultat du premier est votre origine et la différence est votre direction.

Bonne chance!

+0

L'impertinence est bonne, surtout quand ça aide. Je n'ai pas regardé ma section de code depuis un moment (ça marche, donc je me suis dit que je m'inquiéterais de l'optimisation plus tard), mais il semblerait que vos suggestions seront d'une grande aide. Merci. –

0

Si vous avez un rayon (déjà transformé en espace du monde) et que vous voulez vérifier s'il croise un objet/triangle, vous devez le multiplier par les matrices inversées de l'objet. Voici quelques pseudo-code:

NewRayPosition = Vector3.Transform(OldRay.Position, Matrix.Invert(Transformation); 
NewRayDirection = Vector3.Transform(OldRay.Direction, Matrix.Invert(Rotation*Scale)); 
NewRayDirection.Normalize(); 

Multiply position de rayon par translation, rotation et échelle, mais seule direction par échelle et la rotation. Le faire de la façon dont vous l'avez fait est inacceptable en raison de la raison de la performance. Plus ici: http://www.cl.cam.ac.uk/teaching/1999/AGraphHCI/SMAG/node2.html#SECTION00024100000000000000