Comment recalculer la zone de sélection alignée sur l'axe après translation / rotation?
Quand j'ai charger mon objet, je calculer la première AABB avec le max et min (x,y,z) des points. Mais c'est dans l'espace objet et l'objet se déplace à travers le monde et, plus important encore, tourne.
Comment recalculer le nouveau AABB chaque fois que l'objet est traduit/rotation? Cela se produit essentiellement de toutes les images, est-ce que ça va être une exploitation très intensive pour recalculer le nouveau AABB chaque image? Si oui, quelle serait l'alternative?
Je sais AABBs vais faire mes détection de collision, moins précis, mais c'est plus facile à mettre en œuvre la détection de collision code de OBBs et je veux prendre une étape à la fois.
Voici mon code actuel après un aperçu de l'réponses ci-dessous:
typedef struct sAxisAlignedBoundingBox {
Vector3D bounds[8];
Vector3D max, min;
} AxisAlignedBoundingBox;
void drawAxisAlignedBoundingBox(AxisAlignedBoundingBox box) {
glPushAttrib(GL_LIGHTING_BIT | GL_POLYGON_BIT);
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glColor3f(1.0f, 1.0f, 0.0f);
glBegin(GL_LINE_LOOP);
glVertex3f(box.bounds[0].x, box.bounds[0].y, box.bounds[0].z);
glVertex3f(box.bounds[1].x, box.bounds[1].y, box.bounds[1].z);
glVertex3f(box.bounds[2].x, box.bounds[2].y, box.bounds[2].z);
glVertex3f(box.bounds[3].x, box.bounds[3].y, box.bounds[3].z);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(box.bounds[4].x, box.bounds[4].y, box.bounds[4].z);
glVertex3f(box.bounds[5].x, box.bounds[5].y, box.bounds[5].z);
glVertex3f(box.bounds[6].x, box.bounds[6].y, box.bounds[6].z);
glVertex3f(box.bounds[7].x, box.bounds[7].y, box.bounds[7].z);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(box.bounds[0].x, box.bounds[0].y, box.bounds[0].z);
glVertex3f(box.bounds[5].x, box.bounds[5].y, box.bounds[5].z);
glVertex3f(box.bounds[6].x, box.bounds[6].y, box.bounds[6].z);
glVertex3f(box.bounds[1].x, box.bounds[1].y, box.bounds[1].z);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(box.bounds[4].x, box.bounds[4].y, box.bounds[4].z);
glVertex3f(box.bounds[7].x, box.bounds[7].y, box.bounds[7].z);
glVertex3f(box.bounds[2].x, box.bounds[2].y, box.bounds[2].z);
glVertex3f(box.bounds[3].x, box.bounds[3].y, box.bounds[3].z);
glEnd();
glPopAttrib();
}
void calculateAxisAlignedBoundingBox(GLMmodel *model, float matrix[16]) {
AxisAlignedBoundingBox box;
float dimensions[3];
//This will give me the absolute dimensions of the object
glmDimensions(model, dimensions);
//This calculates the max and min points in object space
box.max.x = dimensions[0] / 2.0f, box.min.x = -1.0f * box.max.x;
box.max.y = dimensions[1] / 2.0f, box.min.y = -1.0f * box.max.y;
box.max.z = dimensions[2] / 2.0f, box.min.z = -1.0f * box.max.z;
//These calculations are probably the culprit but I don't know what I'm doing wrong
box.max.x = matrix[0] * box.max.x + matrix[4] * box.max.y + matrix[8] * box.max.z + matrix[12];
box.max.y = matrix[1] * box.max.x + matrix[5] * box.max.y + matrix[9] * box.max.z + matrix[13];
box.max.z = matrix[2] * box.max.x + matrix[6] * box.max.y + matrix[10] * box.max.z + matrix[14];
box.min.x = matrix[0] * box.min.x + matrix[4] * box.min.y + matrix[8] * box.min.z + matrix[12];
box.min.y = matrix[1] * box.min.x + matrix[5] * box.min.y + matrix[9] * box.min.z + matrix[13];
box.min.z = matrix[2] * box.min.x + matrix[6] * box.min.y + matrix[10] * box.min.z + matrix[14];
/* NOTE: If I remove the above calculations and do something like this:
box.max = box.max + objPlayer.position;
box.min = box.min + objPlayer.position;
The bounding box will move correctly when I move the player, the same does not
happen with the calculations above. It makes sense and it's very simple to move
the box like this. The only problem is when I rotate the player, the box should
be adapted and increased/decreased in size to properly fit the object as a AABB.
*/
box.bounds[0] = Vector3D(box.max.x, box.max.y, box.min.z);
box.bounds[1] = Vector3D(box.min.x, box.max.y, box.min.z);
box.bounds[2] = Vector3D(box.min.x, box.min.y, box.min.z);
box.bounds[3] = Vector3D(box.max.x, box.min.y, box.min.z);
box.bounds[4] = Vector3D(box.max.x, box.min.y, box.max.z);
box.bounds[5] = Vector3D(box.max.x, box.max.y, box.max.z);
box.bounds[6] = Vector3D(box.min.x, box.max.y, box.max.z);
box.bounds[7] = Vector3D(box.min.x, box.min.y, box.max.z);
//This draw call is for testing porpuses only
drawAxisAlignedBoundingBox(box);
}
void drawObjectPlayer(void) {
static float mvMatrix[16];
if(SceneCamera.GetActiveCameraMode() == CAMERA_MODE_THIRD_PERSON) {
objPlayer.position = SceneCamera.GetPlayerPosition();
objPlayer.rotation = SceneCamera.GetRotationAngles();
objPlayer.position.y += -PLAYER_EYE_HEIGHT + 0.875f;
/* Only one of the two code blocks below should be active at the same time
Neither of them is working as expected. The bounding box doesn't is all
messed up with either code. */
//Attempt #1
glPushMatrix();
glTranslatef(objPlayer.position.x, objPlayer.position.y, objPlayer.position.z);
glRotatef(objPlayer.rotation.y + 180.0f, 0.0f, 1.0f, 0.0f);
glCallList(gameDisplayLists.player);
glGetFloatv(GL_MODELVIEW_MATRIX, mvMatrix);
glPopMatrix();
//Attempt #2
glPushMatrix();
glLoadIdentity();
glTranslatef(objPlayer.position.x, objPlayer.position.y, objPlayer.position.z);
glRotatef(objPlayer.rotation.y + 180.0f, 0.0f, 1.0f, 0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, mvMatrix);
glPopMatrix();
calculateAxisAlignedBoundingBox(objPlayer.model, mvMatrix);
}
}
Mais il ne fonctionne pas comme il devrait... Ce que je fais mal?
source d'informationauteur Ricardo Amaral
Vous devez vous connecter pour publier un commentaire.
Simplement recalculer l'AABB de la transformée AABB. Cela signifie transformer les 8 sommets ( vertex 8 - matrice de multiplications ) et 8 vertex vertex comparaisons.
Donc, lors de l'initialisation, vous calculez votre AABB dans l'espace de modélisation : pour chaque x,y,z de chaque vertex dans le modèle, vous vérifiez contre xmin, xmax, ymin, ymax, ...
Chaque image, vous générez une nouvelle matrice de transformation. En OpenGL c'est fait avec glLoadIdentity suivie par glTransform/Rotation/Échelle (si vous utilisez l'ancienne API). C'est le Modèle de la Matrice, comme lmmilewski dit.
Vous de calculer cette matrice de transformation un deuxième temps (en dehors de l'Opengl, par exemple à l'aide de glm). Vous pouvez également obtenir OpenGL de la matrice obtenue à l'aide de glGet.
Vous multipliez chacun de vos AABB huit sommets par cette matrice. Utilisation glm pour matrice-vecteur de multiplication. Vous aurez votre transformé AABB (dans l'espace). Il il est probablement tourné (pas d'axe aligné plus)
Maintenant votre algorithme probablement que le travail avec l'axe aligné trucs, donc votre question. Alors maintenant, vous approximative de la nouvelle boîte englobante de la transformation du modèle par takinf la boîte englobante de la transformée de la boîte englobante:
pour chaque x,y,z de chaque sommet de la nouvelle AABB, vous vérifiez contre xmin, xmax, ymin, ymax, ... cela vous donne un espace-monde AABB que vous pouvez utiliser dans votre écrêtage de l'algorithme.
Ce n'est pas optimal (AABB-sage), vous aurez beaucoup d'espace vide, mais en terme de performance, c'est beaucoup mieux que recalculant les AABB de l'ensemble du maillage.
Comme pour la matrice de transformation, dans drawObjectPlayer:
Ne peux pas expliquer plus que ça... comme dit dans les commentaires, vous avez dû le faire deux fois. Tu n'aurais pas ces problèmes et laid solutions de contournement en OpenGL 3, btw, parce que vous seriez entièrement responsable de vos propres matrices. Équivalent en OpenGL 2 :
beaucoup plus propre droit
Citer une réponse précédente: AABB @ Stackoverflow
Skurmedel
De l'intimé suggestion, et la mienne, est de mettre en œuvre orientée vers les boîtes englobantes une fois que vous avez AABB de travail, et également à noter que vous pouvez faire aabb est des parties d'un maillage de fudge de la détection de collision avec une précision plus grande que 1 carton énorme pour chaque objet.
Pour ce faire vous devez faire une boucle sur tous les sommets, calculer sa position dans le monde (multiplier par modelview) et trouver le minimum /maximum les coordonnées des vertices à l'intérieur de chaque objet (tout comme lorsque vous calculez pour la première fois).
Vous pouvez mettre à l'échelle un peu de votre AABB, de sorte que vous n'avez pas à recalculer - il suffit de l'agrandir par le facteur de sqrt(2) - votre rotation de l'objet puis s'adapte toujours à l'AABB.
Il y a aussi une quesion direction dans laquelle vous vous tourner? Si toujours dans un, alors vous pouvez agrandir l'AABB seulement dans cette direction.
Optionnellement, vous pouvez utiliser de délimitation des sphères au lieu d'AABBs.Alors vous n'avez pas de soins de la rotation et de mise à l'échelle n'est pas un problème.
À la fin je dois vous demander si vous êtes sûr que c'est un goulot d'étranglement dans votre application. Je crois qu'il n'est pas et dans ce cas, je voudrais utiliser la première option que j'ai mentionné (itérer sur tous les sommets).
Pourquoi ne pas utiliser votre GPU? Aujourd'hui, je implimented une solution de ce problème par rendening un couple de cadres.
vers le bas à l'objet.
quoi que ce soit.
Je sais que ce n'est pas une solution pour tous les cas, mais avec quelques connaissances antérieures, c'est très efficace.
Pour le rendu hors de l'écran, voir ici.