How can I create a bounding box around a 3d object that I've created in 3DS MAX, and then used it in an openGL application? I need the bounding box for collision detection, but I don't understand how to link a bounding box to an object. The function that creates the object is:
void drawR2D2(){
if (xrot <= 5.0) xrot = 5.0;
if (xrot >= 70.0) xrot = 70.0;
if (ztransKit2 >= 0.7) ztransKit2 = 0.7;
if (xtransS1 >= 0.2) xtransS1 = 0.2;
if (ztransKit2 <= 0.0) ztransKit2 = 0.0;
if (xtransS1 <= 0.0) xtransS1 = 0.0;
glPushMatrix();
drawBodyR2();
glPopMatrix();
glPushMatrix();
glTranslatef(0.0, 1.2, 0.0);
glScalef(2.85, 2.85, 2.85);
glRotatef(yrotHead, 0.0, 1.0, 0.0);
drawHeadR2();
glPopMatrix();
glPushMatrix();
glScalef(3.5, 3.5, 3.5);
drawLegsR2();
glPopMatrix();
glPushMatrix();
glTranslatef(-0.41, 0.45, 0.26);
glScalef(1.4, 1.4, 1.4);
glRotatef(xrotKit1, 1.0, 0.0, 0.0);
drawKit1R2();
glPopMatrix();
glPushMatrix();
glTranslatef(-0.2, 0.5, 0.0 + ztransKit2);
glScalef(2.0, 2.0, 2.0);
glRotatef(zrotKit2, 0.0, 0.0, 1.0);
drawKit2R2();
glPopMatrix();
glPushMatrix();
glTranslatef(-0.25 + xtransS1, 0.48, 0.45);
glScalef(1.55, 1.55, 1.55);
drawShield1R2();
glPopMatrix();
glPushMatrix();
glTranslatef(-0.44 + xtransS2, 0.48, 0.37);
glScalef(1.12, 1.12, 1.12);
drawShield2R2();
glPopMatrix();
}
The other functions: drawBodyR2(),drawHeadR2, etc are the components of the entire object.
The code for the drawBodyR2, for example, is:
void drawBodyR2(){
InitModel("r2d2/body.obj", &body);//function to initialize the object
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, bodyId);
glmDraw(body, GLM_SMOOTH | GLM_TEXTURE);
glDisable(GL_TEXTURE_2D);
}
Can anyone show me how to create a bounding box around the object resulted from the drawR2D2 function?
The "best" box you can build for collision detection is an oriented bounding box (OBB), that is the smallest possible box that fits the object. In order to do that you need to learn some maths (what eigenvectors are mainly) and use them for the OBB (check this answer for a detailed explanation about OBB computation).
Note that:
OBB has nothing to do with OpenGL. You can compute the OBB/ABB having a model and never drawing it. Separate the tasks!
An OBB should never be computed twice for the same model, it is computational nonsensical. The ideal thing would be to precompute the coordinates of the 8 points forming the OBB of each of the objects you are going to draw and store them. Remember that this implies that whatever geometric transformation you apply to your object, you need to also apply it to the OBB.
Related
I am using C++, OpenGL and glut. I am trying to make 5 houses that are rotated properly like this:
However, whenever I try to implement the glRotatef function, I seem to not be able to either get the proper coordinates or something is off somewhere in my code. Furthermore, I set the background color to white but it's still all black, how come? For now I have the houses set to white to counter this for now. Here is my code:
#include <GL/glut.h>
typedef int vert2D[2];
void initialize()
{
glClearColor(1.0, 1.0, 1.0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(10.0, 215.0, 0.0, 250.0);
glMatrixMode(GL_MODELVIEW);
}
void drawHouse(vert2D* sq, vert2D* tri)
{
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_LOOP);
glVertex2iv(sq[0]);
glVertex2iv(sq[1]);
glVertex2iv(sq[2]);
glVertex2iv(sq[3]);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2iv(tri[0]);
glVertex2iv(tri[1]);
glVertex2iv(tri[2]);
glEnd();
}
void render()
{
vert2D sqPts[4] = { {115, 150}, {115, 125}, {100,125}, {100,150} };
vert2D triPts[3] = { {120, 150}, {95,150}, {108,160} };
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glMatrixMode(GL_MODELVIEW);
drawHouse(sqPts, triPts);
glPushMatrix();
glTranslatef(1.0, 0.0, 0.0);
glRotatef(-10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glTranslatef(1.0, 0.0, 0.0);
glRotatef(-10.0, 0.0, 0.0, -1.0);
drawHouse(sqPts, triPts);
glPopMatrix();
glPushMatrix();
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(10.0, 0.0, 0.0, 1.0);
drawHouse(sqPts, triPts);
glPopMatrix();
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(640, 480);
glutCreateWindow("TestMeOut");
initialize();
glutDisplayFunc(render);
glutMainLoop();
}
Let's answer the simpler question of why your background is still black, first:
You simply never glClear(GL_COLOR_BUFFER_BIT) the color buffer. You tell OpenGL "hey, the next time I call glClear with (at least) the GL_COLOR_BUFFER_BIT, I want the color buffer to be cleared to white." but you never actually clear the buffer.
Now, onto how we can draw the houses with their correct locations and orientations:
You should first start by defining your house's vertices in a sensible local coordinate system/frame that is suitable for transforming them in further steps. Currently, with how you define your house's vertices, it is hard to do any transformations on those (mainly because linear transformations like rotation are always relative to the coordinate system's origin).
So, let's change that. Let's define the origin (0, 0) for your house to be the center of the bottom/base line of the house. And let's also define that your house's quad has a side length of 10 "units":
vert2D sqPts[4] = {
{-5, 0}, // <- bottom left
{ 5, 0}, // <- bottom right
{ 5,10}, // <- top right
{-5,10} // <- top left
};
Now, for the roof of the house, we assume the same coordinate system (with (0, 0) being the center of the house's base/bottom line), so we start at Y=10:
vert2D triPts[3] = {
{-6, 10}, // <- left
{ 6, 10}, // <- right
{ 0, 12} // <- top
};
Next, we need to define where (0, 0) should be in our "world", so to speak. One definition could be: (0, 0) should be the center of the bottom of the viewport/screen and the viewport should have a length of 100 "units". Right now, we don't care about a correct aspect ratio when the viewport's width does not equal the viewport's height. This can be added later.
Starting from the clip space coordinate system, we can transform this clip space into our own "world space" by using these transformations:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(0.0, -1.0, 0.0); // <- move the origin down to the bottom of the viewport
glScalef(1.0 / 50.0, 1.0 / 50.0, 1.0); // <- "scale down" the clip space to cover more space in the viewport
Now, the above part is essentially what gluOrtho2D() does as well, but highlighting the actual coordinate system transformation steps is useful here.
Now that we defined our house's local coordinate system and our "world" coordinate system, we can rotate and translate the world coordinate system such that the houses appear at their correct locations and orientations in our world.
In order to draw 5 houses, we just use a for-loop:
glMatrixMode(GL_MODELVIEW);
for (int i = -2; i <= 2; i++) { // <- 5 steps
glPushMatrix();
glRotatef(i * 20.0, 0.0, 0.0, 1.0);
glTranslatef(0.0, 50.0, 0.0);
drawHouse(sqPts, triPts);
glPopMatrix();
}
So, starting from our world coordinate system, we transform it by rotating the appropriate amount around its origin (0, 0) for the house with index i to have the correct rotation, and then translate the coordinate system by 50 units along its (now rotated) Y axis.
These two transformations will now result in a house to be drawn at the desired location. So, repeat that 5 times in total with differing rotation angles, and you're done.
I am currently working on a project with OpenGL. I wanted to stick an image onto the sign below to make it more realistic. Is there a way to do this with OpenGL? Maybe loading the image in and paint it onto the shape?
Here is the code to create the block of sign:
//Set the size and position
glPushMatrix();
glTranslatef(-550.0, 500.0, fltSignOffset);
glScalef(700.0, 150.0, 20.0);
//Create the shape
glPushMatrix();
glColor3f(0.0, 0.55, 0.27); //Use SpringGreen4 for sign
glutSolidCube(1);
//Create the wireframe of the shape
glColor3f(0.0, 0.0, 0.0);
glutWireCube(1);
glPopMatrix();
glPopMatrix();
I'm trying to simulate the solar system and need to get the moon to orbit a planet orbiting the sun
i am currently using the following code to rotate the planets
glPushMatrix();
glRotated((GLdouble)(spin*earth.speed), 0.0, 0.0, 1.0);
glTranslated(earth.xPos, earth.yPos, earth.zPos);
earth.draw();
glPopMatrix();
i'm trying to use the code below to make my moon orbit the earth however at the moment all i can do is rotate around a specific point.
glPushMatrix();
//define one time only start location
bool start = true;
if (start)
{
glTranslated(earthMoon.xPos, earthMoon.yPos, earthMoon.zPos);
start = false;
}
//orbit earths start point
//perfectly fits around earth
glTranslatef(-0.1, -0.1, 0);
glRotatef(spin*10, 0, 0, 1);
glTranslatef(0.1, 0.1, 0);
// need translation vector to follow earth
//glTranslated(earthMoon.xPos, earthMoon.yPos, earthMoon.zPos);
earthMoon.draw();
glPopMatrix();
i think what i need to do is find some way of knowing earths position from the rotatef function.
I have a class for the planets with the following attributes and methods:
float radius;
float xPos;
float yPos;
float zPos;
float speed;
planet(float r, float x, float y, float z, float speed);
~planet();
void draw(void)
{
glPushMatrix();
glColor3f(0.0, 1.0, 1.0);
glutSolidSphere(radius, 20, 10);
glPopMatrix();
}
the class' coordinates do not get updated when the planet rotates
Does anyone know how to get this to work?
Don't pop your matrix once you drew earth,
then your new referential will be the earth position,
you just have to call the moon drawing code and it will rotate around your earth.
Found a fix that works as intended in case anyone else is struggling with this concept
//earth
glPushMatrix();
//earth orbit
glRotated((GLdouble)(spin*earth.speed), 0.0, 0.0, 1.0);
glTranslated(earth.xPos, earth.yPos, earth.zPos);
//earth mooon
glPushMatrix();
//orbit around earth
glRotatef(spin * 5, 0, 0, 1);
glTranslatef(0.1, 0.1, 0.0);
//rotate around self
glRotated((GLdouble)spin, 0.0, 1.0, 0.0);
//draw moon
earthMoon.draw();
glPopMatrix();
//rotate around self
glRotated((GLdouble)spin, 0.0, 1.0, 0.0);
//draw earth
earth.draw();
glPopMatrix();
//
Hope this helps anyone else
I draw a solid sphere like the followings:
glPushMatrix();
glScalef(0.015, 0.015, 0.015);
glRotatef(90, 1.0, 0.0, 0.0);
glTranslatef(0.0, 200, 0.0);
glRotatef(-20, 0.0, 0.0, 1.0);
glRotatef(-20, 1.0, 0.0, 0.0);
glTranslatef(78.75, -110.74, -13.53);
glutSolidSphere(4.0f,15,15);
glPopMatrix();
How can I get the transformed coordinates of this solid sphere?
You can get the state variables GL_MODELVIEW_MATRIX by the function glget.
It returns the current matrix from ModelView stack. I think that is what you need.
Put the translated coordinates in variables, then you won't have to retrieve the transformed coordinates of the shape.
float solidSphereX = whatever;
float solidSphereY = whatever;
float solidSphereZ = whatever;
float solidSphereRotationX = whatever in radians;
float solidSphereRotationY = whatever in radians;
float solidSphereRotationZ = whatever in radians;
...
glPushMatrix();
glRotatef(solidSphereRotationX, solidSphereRotationY, solidSphereRotationZ);
glTranslatef(solidSphereX, solidSphereY, solidSphereZ);
glPopMatrix();
I'm having problems in OpenGL getting my object (a planet) to rotate relative to the current camera rotation. It seems to work at first, but then after rotating a bit, the rotations are no longer correct/relative to the camera.
I'm calculating a delta (difference) in mouseX and mouseY movements on the screen. The rotation is stored in a Vector3D called 'planetRotation'.
Here is my code to calculate the rotation relative to the planetRotation:
Vector3D rotateAmount;
rotateAmount.x = deltaY;
rotateAmount.y = deltaX;
rotateAmount.z = 0.0;
glPushMatrix();
glLoadIdentity();
glRotatef(-planetRotation.z, 0.0, 0.0, 1.0);
glRotatef(-planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(-planetRotation.x, 1.0, 0.0, 0.0);
GLfloat rotMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, rotMatrix);
glPopMatrix();
Vector3D transformedRot = vectorMultiplyWithMatrix(rotateAmount, rotMatrix);
planetRotation = vectorAdd(planetRotation, transformedRot);
In theory - what this does is, sets up a rotation in the 'rotateAmount' variable. It then gets this into model space, by multiplying this vector with the inverse model transform matrix (rotMatrix).
This transformed rotation is then added to the current rotation.
To render this is the transform being setup:
glPushMatrix();
glRotatef(planetRotation.x, 1.0, 0.0, 0.0);
glRotatef(planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(planetRotation.z, 0.0, 0.0, 1.0);
//render stuff here
glPopMatrix();
The camera sort of wobbles around, the rotation I'm trying to perform, doesn't seem relative to the current transform.
What am I doing wrong?
GAH! Don't do that:
glPushMatrix();
glLoadIdentity();
glRotatef(-planetRotation.z, 0.0, 0.0, 1.0);
glRotatef(-planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(-planetRotation.x, 1.0, 0.0, 0.0);
GLfloat rotMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, rotMatrix);
glPopMatrix();
OpenGL is not a math library. There are proper linear algebra libraries for that kind of job.
As for your problems. A vector is not fit to store a rotation. You need at least a Vector (axis of rotation) and the angle itself, or better yet a Quaternion.
Also rotations don't add. They're no commutative, however addition is a commutative operation. Rotations in fact multiply.
How to fix your code: Rewrite it from scratch using the proper mathematical methods. For this please read up the topics of "Rotation matrices" and "Quaternions" (Wikipedia has them).