I am working with C and OpenGL. I am trying to load a 3D model with skeletal animation, but I just can't seem to calculate the absolute matrix of each bone for each frame of the animation.
I have: For each bone, I have a matrix and an inverse matrix and for each frame of the animation, I have a rotation(Euler) and a translation for each bone.
Blender Import/Export scripts:
http://pastebin.com/xMJ2fG26
http://pastebin.com/9D42RKRf
edit: if someone knows how to get a bone's absolute matrix with blender and export that, that would also be fine (I'm new to Blender)
for each frame f
for each bone i
glLoadIdentity();
glMultMatrixd(bones[i].matrix);
for each parent bone ii(starting from the top)
glTranslated(bones[ii].translation[f].x, bones[ii].translation[f].y, bones[ii].translation[f].z);
glRotated(bones[ii].degrees[f].z, 0.0, 0.0, 1.0);
glRotated(bones[ii].degrees[f].x, 1.0, 0.0, 0.0);
glRotated(bones[ii].degrees[f].y, 0.0, 1.0, 0.0);
glMultMatrixd(bones[i].inversematrix);
glGetDoublev(GL_PROJECTION_MATRIX, bones[i].absmatrix[f]);
Those scripts look like they were written for the obsolete 2.4*x* versions of Blender. For 2.5*x*/2.6*x*, you have a much-improved Python API that includes Bone objects with “matrix” and “matrix_local” attributes.
I’d recommend you try to do what you want to do with a current version of Blender. Much less likely to be hitting your head against a brick wall that way.
In your comment to Lawrence you're right that your 2.4 scripts will not work for Blender 2.5. However your problem is not very complicated. The matrices you get are the local transformation from each bone to the next one. So all you need to do it multiplying them one after another in the dependency tree.
So what you do is a depth-first traversal of the tree, and for each iteration down the tree you ad a glPushMatrix(); glMultMatrix(bone_matrix); and when going up a step reverse the effect with glPopMatrix();
Related
I am doing in a simplistic experiment as below:
glPushMatrix();
glGetDoublev(GL_MODELVIEW, modelMatrix);
glTranslatef(...);
glGetDoublev(GL_MODELVIEW, modelMatrix);
glPopMatrix();
However, after the translation, there is not change in the modelview matrix. I am wondering why is that, and how can I see the effect of this translation? In other words, how can I get the transformation marix?
Your code is invalid. The correct enum for glGet...() is GL_MODELVIEW_MATRIX, not GL_MODELVIEW (which is a constant for use glMatrixMode()), so all you get is some GL error, and the memory at modelMatrix will be not touched at all, so it is probably just left uninitialized.
I am in the process of making a simple racing game using Apple's SceneKit library. I have modeled a left turn section of the race track. I am able to successfully load the model into an SCNGeometry that I can then render. However, I would like to be able to use this model for both a left and right turn segment. To do this, I need to mirror the SCNGeometry over the y-z plane, though I can't for the life of me figure out how.
In SpriteKit, one can mirror a sprite by setting the corresponding SKNode's scale to -1. However, if I set the SCNGeometry's SCNNode's x scale to -1, the SCNGeometry will not render at all. While I can mirror the model in my modeling software, I would prefer not to have two basically identical models. Any suggestions would be appreciated.
Alright, turns out setting the SCNNode's x scale to -1 does in fact mirror the SCNGeometry.The issue is, when an SCNGeometry is mirrored that way, all of the faces are pointed inwards instead of outwards so none are rendered. If the object's material is changed so that the front faces are culled instead of the back faces, the SCNGeometry will be mirrored as expected.
If you don't want to change the geometry, but just change the texture, you can do:
let flip = SCNMatrix4Translate(
SCNMatrix4Scale(material.diffuse.contentsTransform, 1.0, -1.0, 1.0),
0, 1, 0
)
material.diffuse.contentsTransform = flip
or directly,
material.diffuse.contentsTransform = SCNMatrix4FromGLKMatrix4(GLKMatrix4(m: (
-1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
-1.0, 0.0, 0.0, 1.0
)))
This will replace the texture x coordinate by 1-x which should flip it. I've played around with shaders, and I believe the relevant shader code showing how SceneKit uses the content transform is
v_texcoord0 = (u_diffuseTextureMatrix * vec4(_geometry.texcoords[0], 0., 1.)).xy;
(see here)
When you scale the geometry to any "-" negative it flip the normals face. the default for normal faces are "One sided"
Set the "Material" property to "Double Sided"
with swift it might look like this
yourNode.geometry?.firstMaterial?.doubleSided = true
I'm currently trying to get to know the basics with the means of OpenGL.
At the time I try to render a Floating Cube with a Pyramid beneath it. I want the Cube to rotate on Input (which is already working) and the Pyramid to stay where it's supposed to be.
After figuring out the use of Push- and PopMatrix I managed to rotate only the cube.
My Problem is, that the Cube stops rotating as soon as I let go of the key.
The player.X and Player.Z aren't reset at that point (checked that).
So my guess is that PushMatrix puts some kind of standard matrix onto the stack, then rotates it and displays it. Because of 1 * x always equalling x there is no rotation.
So the question is:
How do I manage to push the "old" matrix onto the stack, rather than the new one?
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glRotatef( -(player->Z), 1.0f, 0.0f, 0.0f );
glRotatef( -(player->X), 0.0f, 1.0f, 0.0f );
glBegin( GL_QUADS );
//Draw Cube
glEnd();
glPopMatrix( );
glBegin( GL_TRIANGLES );
//Draw Pyramid
glEnd();
glFlush();
SwapBuffers (hDC);
glPushMatrix() does not push a 'standard' matrix onto the stack, it pushes the current matrix. Hopefully you've initialised the matrix at some point with a glLoadIdentity(), and possibly some initial transforms to set up the view, and so this is what will be pushed.
You should not generally keep updating that matrix from frame to frame, as errors will eventually accumulate.
Instead, update your rotation values in some update loop, rather than in the key-down routine.
Also, note that this method of rendering with GL is considered deprecated. The recommended approach is to use the programmable pipeline, which involves creating your own matrices (amongst other changes).
(if you desperately want to keep a persistent transform while also pushing and popping to render other things, it is possible to read the current matrix with a glGet(), store it somewhere, and then perform a glLoadMatrix() to restore it again later... but don't do that for this.)
(Using OpenGL, GLUT, GLU, and C)
I am trying to create a 3D game in C, and I have the camera movement, collision detection and all of the main stuff ready, however I have failed at the first hurdle. To create my rectangles I am using
glutSolidCube (2.0);
And I know about tranformations and scale and rotations, however I am looking for how to place it in a precise location. Say I had a 3D space, with XYZ. Say I had the camera at 5,5,20, looking towards 0,0,0 (So at an angle) and wanted to place a Cube at 5,2,10, and then another at -5,-2,20. How would I use these absolute positions? Also, how would I use absolute sizes, so say I wanted the one at -5,-2,20 to be 20,5,10 in size. How would I do this in OpenGL?
You'll have to use the functions:
glTranslatef()
glRotatef()
glScalef()
Additionally, also learn these:
glPushMatrix()
glPopMatrix()
Read the OpenGL reference for details.
First forget about glutSolidCube. GLUT is not a part of OpenGL, it's just a small convenience library for it.
You must understand the OpenGL only deals with points, lines and tranangles. And it doesn't maintain a scene, but its merely drawing points, lines and triangles. Each on its own without any connotation of topology. Also OpenGL should not be confused for some math library. The functions glTranslate, glRotate, glScale and so on are a pure legacy and have been removed from contemporary OpenGL versions.
That being said...
Say I had the camera at 5,5,20, looking towards 0,0,0 (So at an angle) and wanted to place a Cube at 5,2,10, and then another at -5,-2,20. How would I use these absolute positions? Also, how would I use absolute sizes, so say I wanted the one at -5,-2,20 to be 20,5,10 in size. How would I do this in OpenGL?
I'll go along with what you already know (which mans old OpenGL-1.1 and GLUT):
void draw()
{
/* Viewport and projection really should be set in the
drawing handler. They don't belong into the reshape. */
glViewport(...);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
your_projection();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5, 5, 20, 0, 0, 0, 0, 1, 0);
glPushMatrix();
glTranslatef(5, 2, 10);
draw_cube();
glPopMatrix();
glPushMatrix();
glTranslatef(-5, -2, 20);
draw_cube();
glPopMatrix();
glPushMatrix();
glTranslatef(-5, -2, 20);
glScalef(20, 5, 10);
draw_cube();
glPopMatrix();
}
I am reading a book on OpenGL, SDL, and have read some of the OpenGL documentation. I have also read this post: What does glLoadIdentity() do in OpenGL?
I am grasping what glLoadIdentity() does, and why it is used in a general sense (to return the current matrix back to its original state). What I do not know is why I am returning it to its original state. For instance:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, 640, 480, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
I am not exactly sure why glLoadIdentity() has to be called after each call to glMatrixMode.
When to call glMatrixMode() -- 1st answer tries to explain:
glLoadIdentity() is typically called immediately after a matrix mode change so you are starting "fresh" if you will. Matrix transforms such as the gluPerspective(), glOrtho(), glFrustum(), glRotate(), glMultMatrix(), glTranslate() are cumulative operations because they aggregate to allow you to describe complex 3D world space transforms or to describe your OpenGL viewing volume. Example: if I want a cube translated in the +X direction then rotated around the Z axis I issue a glRotate() followed by a glTranslate().
glLoadIdentity() wipes out the matrix (of the current matrix mode) with the identity matrix so following a gluPerspective() by glLoadIdentity() is equivalent to a single call to glLoadIdentity(). In other words, that sequence is nonsensical.