Reputation: 365
I want to make simple 3D robotic arm using blender. At the moment I can import obj files and textures, rotate, translate and scale.
Problem: To simplify, robotic arm will have 3 parts, base (cylinder to rotate), and two cuboids. I have no problems with rotating cilinder and cuboids. But these two cuboids have to be connected and I have no idea how to do it. I can use simple sinus and cosinus functions to compute position of second cuboid when first one is rotated but I have no idea how to measure lenth of the object.
Second problem: Can I export all 3 objects in one obj file and divide them later in openGL?
Upvotes: 1
Views: 4458
Reputation: 365
To find more about solution please refer to denavit hartenberg notation
My solution was simple. I have class kinematicChain were I stored a vectors with positions, orientations of all models. I iterate through all elements in this class using for loop, and multiply position and rotation of each element.
Suppose we had 3 elements Position of the last element in this chain will be(in pseudocode):
currentElementposition * currentElementorientation
Position of second element:
(currentElementPosition*currentElementorientation)*positionOfPreviousElement
Position of first element:
(currentElementPosition*currentElementorientation)*positionOfPreviousElement
And later object is scaled.
Move and rotate is 4x4 matrix
glm::mat4 rotate;
glm::mat4 move;
Function that I use:
void Model::moveModel(std::vector<glm::vec3> & positions, std::vector<glm::vec3> & orienations, int id)
{
try
{
if (positions.size() != orienations.size()) throw "Size of positions vector should be equal to orienations vector";
glm::mat4 objPosition;
for (int i = id ; i >= 0 ; --i)
{
rotate = glm::eulerAngleYXZ(orienations[i].y, orienations[i].x, orienations[i].z);
move = glm::translate(glm::mat4(), positions[i]);
objPosition = (move * rotate) * objPosition;
}
objScale = scale(glm::mat4(), objSize); // scaling object
objPosition = objPosition * objScale;
glUniformMatrix4fv(objPositionID, 1, GL_FALSE, &objPosition[0][0]);
glUniformMatrix4fv(perspectiveGL, 1, GL_FALSE, &perspective[0][0]);
glUniformMatrix4fv(lookAtGL, 1, GL_FALSE, &lookAt[0][0]);
glUniform3f(lightPositionGL, lightPosition.x, lightPosition.y, lightPosition.z); // przesłanie 3 liczb float
}
catch(char const * errorMsg)
{
std::cout << errorMsg << std::endl;
}
}
Upvotes: 1
Reputation: 502
You haven't responded to the comment, but I figured I'd post this code anyways. I wrote this to render a 3D robotic hand in OpenGL. I had the blender model files for all the fingers and the hand (made by someone else), which I exported individually to .obj files.
The final result can be seen here. As you can see, I also added the functionality to change the viewpoint using the mouse. I determined the offsets for the finger phalanges via trial-and-error approach, but perhaps you can find the offset between the points using Blender as described here. I cannot test this right now since I don't have Blender on my work computer.
The code below describes as I implemented this. I broke it up so that I can write some explanation, but putting all the pieces sequentially will generate my complete function to draw a single finger attached to a hand.
My drawing function starts as:
double t_x, t_y, t_z;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer
glLoadIdentity();
// Set viewpoint:
gluLookAt(eyex+3.0f, eyey+3.0f, eyez+3.0f, focusx, focusy, focusz, 0, 1, 0);
glPushMatrix();
glRotatef(g_xRotation, 0,1,0); // Rotate with mouse (g_x and g_y are determined elsewhere)
glRotatef(g_yRotation, 1,0,0);
Now that we are set up at the origin (rotated as the mouse directed), we can start off by drawing the palm of the hand. No shifting is required (it is at the origin).
// DRAW PALM
glColor3f(1.0f, 1.0f, 1.0f); // Use proper color - white
palmHand -> draw();
After the palm is rendered, we move to draw the first finger. The 1.87f in the translate is determined experimentally. The value here also depended on my quality of exporting items from Blender, but once you export it once, it will not change. (I'm actually rather surprised at the rather smug comments I left for myself - this code is a few years old). The phalanges only rotate about one axis, and the rotation values (angles) are stored in f_p[]
.
// DRAW FINGER 1
// CONSTANT: Move to first vertex
glTranslatef(0.0f, 0.0f, 1.87f);
glRotatef(f_p[0].theta, 0, 0, 1); // Do rotation for phalanx 1 with specified angle
glColor3f(16.0f/255.0f, 78.0f/255.0f, 139.0f/255.0f); // Use proper color - blue
phalanx1Hand -> draw();
// CONSTANT: Necessary adjustment because of model file offset (nobody's perfect, okay?)
glTranslatef(0.0f, 0.03f, 0.0f);
Drawing the second (middle) phalanx follows the same process as the bottom one, except it rotates around a different axis.
// CONSTANT: Move to second vertex
glTranslatef(1.3f, 0.0f, 0.0f);
glRotatef(f_p[1].theta, 0, 1, 0); // Do rotation for phalanx 2 with specified angle
phalanx2Hand -> draw();
There was no extra offset for phalanx #2 because I guess when I exported it from Blender, I lined up the model properly.
// CONSTANT: Rotate to third vertex
glRotatef(-90.0f, 0, 1, 0);
// CONSTANT: Move to third vertex
glTranslatef(2.0f, 0.0f, 0.0f);
glRotatef(f_p[2].theta, 0, 1, 0); // Do rotation for phalanx 3 with specified angle
phalanx3Hand -> draw();
That completes drawing a single finger. Now we reverse all the rotations and translations to go back to the starting location (because there were so many rotations in the way, you have to make sure you keep the order consistent, or you'll end up somewhere else and fingers will be all over the place).
// CONSTANT: Return to origin
// Undo rotations and translations in proper order
glRotatef((-1.0f*f_p[2].theta), 0, 1, 0); // Phalanx 3 rotation
glTranslatef(-2.0f, 0.0f, 0.0f); // Phalanx 3 translation
glRotatef(90.0f, 0, 1, 0); // Rotation to Phalanx 3
glRotatef((-1.0f*f_p[1].theta), 0, 1, 0); // Phalanx 2
glTranslatef(-1.3f, -0.03f, 0.0f); // Phalanx 2 translation and adjustment
glRotatef((-1.0f*f_p[0].theta), 0, 0, 1); // Rotation to Phalanx 1
glTranslatef(0.0f, 0.0f, -1.87f); // Phalanx 1 translation
Lastly, since my model has two fingers on one side, and one on the other, I had to rotate before drawing the other two fingers:
// CONSTANT: Keep parts right side up
glRotatef(90.0f, 0, 0, 1);
At this point I would follow the same process for fingers 2 and 3 (basically the code starting at the // DRAW FINGER 1
comment). You probably would not need to do this since I think your model doesn't have all these extra parts. At this point, you could forego all the rotations/translations back to origin and just finish with:
glPopMatrix();
and return to whatever you were doing before (waiting for user input, etc).
The draw()
functions I use is a standard one to draw triangles using the data extracted from the .obj files.
Upvotes: 1
Reputation: 46
Have you considered rigging the object as you would the arm of a human? That way the objects are all linked and don't get out of sync. and then animations can be applied to the rig as a whole. Less calculations, and easier for you.
Examples (other pages from this site are helpful as well): http://www.blender.org/api/htmlI/x7613.html http://www.blender.org/api/htmlI/x7891.html
Reference: http://wiki.blender.org/index.php/Doc:2.6/Manual/Rigging
Upvotes: 0