rotating model while color updating - opengl

In OpenGL, I draw tree(composed of lines) like structure(neurons), and based on activity, i apply a color on each of the branches of the tree. Each branch portion may have a different color at an instance. I keep record of the color at an instance corresponding to the branch.
I am able to rotate (by changing the modelview matrix) the tree. I can see the changing color (activity) on the branches when updating.
However, i am not able to rotate the tree while the color change is happening. (the rotation is seen after the complete updating) This is also true with translating the model, not able to translate while updating.
How should i be doing this to see them simultaneously?
i call the updateViz function to update the colors.
def render(self):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
self.renderAxis() #draws 3 axes at origin
for obj in self.vizObjects:
glPushMatrix()
glColor(obj.r, obj.g, obj.b)
glLineWidth(2)
glBegin(GL_LINES)
glVertex3f(obj.l_coords[0],obj.l_coords[1],obj.l_coords[2])
glVertex3f(obj.l_coords[3],obj.l_coords[4],obj.l_coords[5])
glEnd()
glPopMatrix()
def updateViz(self,vals):
inds = digitize(vals,colrMapVals)
for i in range(0,len(self.vizObjects)):
self.vizObjects[i].r,self.vizObjects[i].g,self.vizObjects[i].b= colorMap[inds[i]-1]
def translate(self, _trans):
self.makeCurrent()
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslated(_trans[0], _trans[1], _trans[2])
glMultMatrixd(self.modelview_matrix_)
self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
self.translate_vector_[0] = self.modelview_matrix_[3][0]
self.translate_vector_[1] = self.modelview_matrix_[3][1]
self.translate_vector_[2] = self.modelview_matrix_[3][2]
def rotate(self, _axis, _angle):
#self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
t = [self.modelview_matrix_[0][0] * self.center_[0] +
self.modelview_matrix_[1][0] * self.center_[1] +
self.modelview_matrix_[2][0] * self.center_[2] +
self.modelview_matrix_[3][0],
self.modelview_matrix_[0][1] * self.center_[0] +
self.modelview_matrix_[1][1] * self.center_[1] +
self.modelview_matrix_[2][1] * self.center_[2] +
self.modelview_matrix_[3][1],
self.modelview_matrix_[0][2] * self.center_[0] +
self.modelview_matrix_[1][2] * self.center_[1] +
self.modelview_matrix_[2][2] * self.center_[2] +
self.modelview_matrix_[3][2]]
self.makeCurrent()
glLoadIdentity()
glTranslatef(t[0], t[1], t[2])
glRotated(_angle, _axis[0], _axis[1], _axis[2])
glTranslatef(-t[0], -t[1], -t[2])
glMultMatrixd(self.modelview_matrix_)
self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
def keyPressEvent(self, ev):
if (ev.key() == QtCore.Qt.Key_Left):
self.translate([-0.25, 0.0, 0.0])
self.updateGL()
elif (ev.key() == QtCore.Qt.Key_Right):
self.translate([0.25, 0.0, 0.0])
self.updateGL()
elif (ev.key() == QtCore.Qt.Key_A):
self.rotate([1.0, 0.0, 0.0],2.0)
self.updateGL()
elif (ev.key() == QtCore.Qt.Key_Q):
self.rotate([1.0, 0.0, 0.0],-2.0)
self.updateGL()
I use PyQt4 and PyGLWidget

your code looks all right to me. I think the problem is caused by how you update the rotation and color. OpenGL is a state machine, you feed it with all kinds of info (vertex pos, color, etc) and things get rendered, so MAKE SURE updateVis and translate/rotate are called on EVERY FRAME.
maybe your rotation/translation depends on Qt's signal/event mechanism, and it's not called every frame?

OpenGL is not a scene graph, in which you update rotation or translation. Those glRotate, glTranslate calls, they are meant to be called from the drawing function NOT in a event handler. Update some variables in the event handler, issue a redraw and then in the drawing code call glTranslate/glRotate according to the values in the variable.

Related

Mouse position on (OpenGL) scene

I'm trying to get the mouse coordinate on OpenGL scene.
My Code:
from PySide.QtGui import (QColor)
from PySide.QtCore import (Qt, QSize)
from PySide.QtOpenGL import (QGLWidget)
from OpenGL.GL import *
from OpenGL.GLU import *
class QGL(QGLWidget):
def __init__(self, parent=None):
self._pan_valid = False
super(QGL, self).__init__(parent)
self.setFocusPolicy(Qt.ClickFocus)
self.local_translate = (0.0, 0.0, 0.0)
self.zoomVal = 1.2
def minimumSizeHint(self):
return QSize(50, 50)
def sizeHint(self):
return QSize(800, 800)
def initializeGL(self):
self.qglClearColor(QColor.fromCmykF(0.0, 0.1, 0.0, 0.882))
glViewport( 0, 0, self.width(), self.height())
glEnable(GL_TEXTURE_2D)
glEnable(GL_CULL_FACE)
glEnable(GL_MULTISAMPLE)
glEnable(GL_LINE_SMOOTH, GL_LINE_WIDTH, GL_ALIASED_LINE_WIDTH_RANGE)
glShadeModel(GL_FLAT)
glEnable(GL_DEPTH_TEST)
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
glDepthRange (0.1, 1.0)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
gluOrtho2D(-self.zoomVal, +self.zoomVal, -self.zoomVal, +self.zoomVal)
glLoadIdentity()
genList = glGenLists(1)
glNewList(genList, GL_COMPILE)
vertices = [
(0,0,0),
(0.5,0,0),
(0.5,0.5,0),
(0,0.5,0)
]
glBegin(GL_QUADS)
self.qglColor(QColor(0,255,255))
for vertex in vertices:
glVertex3fv(vertex)
glEnd()
glEndList()
glCallList(genList)
def mousePressEvent(self, event):
print event.pos()
print self.mapToGlobal(event.pos())
when I do this:
print event.pos()
it will give me the mouse position on the window.
and when I do this:
print self.mapToGlobal(event.pos())
it will give me the mouse position on the monitor.
How can I get the mouse position on the scene?
I'm using 2D viewport (gluOrtho2D).
I don't think there is a convenient built-in function for this, but it should be trivial to calculate, especially given that this is a 2D, orthographic scene. You know the size of the window in pixels, and you know where in that window the user clicked, given whatever event.pos() returns (also in pixels). What needs to happen then is that you need to map that range in pixels to your range specified in your gluOrtho2D call. The following code could be adapted as you see fit:
#specifying a bunch of example values
zoom_val = 1.2
window_size = (800, 600)
mouse_pos = (300, 150)
ortho_2d = (-zoom_val, +zoom_val, -zoom_val, +zoom_val)
#First, calculate the "normalized" mouse coordinates by dividing by window_size
mouse_norm_x = mouse_pos[0] / window_size[0]
mouse_norm_y = mouse_pos[1] / window_size[1]
#Now map those coordinates to your orthographic projection range
mouse_ortho_x = (mouse_norm_x * (ortho_2d[1] - ortho_2d[0])) + ortho_2d[0]
mouse_ortho_y = (mouse_norm_y * (ortho_2d[3] - ortho_2d[2])) + ortho_2d[2]
mouse_ortho = (mouse_ortho_x, mouse_ortho_y)
print(mouse_ortho)
Getting the z-coordinate is trickier. I would suggest reading up on the concept of "mouse-picking" for that. You would need to get the depth buffer, store its results in a texture, and sample the mouse coordinate at the appropriate location in that texture to get the z-coordinate. You can combine these two answers (1, 2) I have previously written for other questions together to get something working. Let me know if this helps!

gluLookAt() not looking where it should

I don't understand what the glLookAt() function does exactly.
I have an object at position x,y,z . I want to place the camera at position x+20,y+20,z+20 while the object is moving, so that it should look like stationary. However, this is not the case : when I do the following code, I see a cross which is slowly moving to the right and even goes out of the window !
while (keystate[SDLK_ESCAPE] == false) {
SDL_PollEvent(&event);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
n+=0.1;
float x = 10;
float y = 10+n*n;
float z = 10;
// drawing an object at x,y,z (here a cross)
glBegin(GL_LINES);
glColor3ub(200,0,0);
glVertex3f(x-2,y,z);
glVertex3f(x+2,y,z);
glVertex3f(x,y-2,z);
glVertex3f(x,y+2,z);
glEnd();
// looking at the object
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
gluLookAt(x+20,y+20,z+20,x,y,z,0,0,1);
glFlush();
SDL_GL_SwapBuffers();
}
If the camera were correctly looking at x,y,z , the cross should always appear at the center ?
If I put y = 10 + n , the object looks stationary.
With y = 10 + n * n , the object moves at constant speed, and with y = 10 + n * n * n, the object moves and accelerates.
I also did
gluPerspective(70,(double)640/480,1,1000);
at the beginning of my code.
Thank you in advance ! :S
OpenGL is a state machine, not a scene graph library. It does not remember the objects you have drawn. With your code, you first draw the object (with whatever matrices are current), and after that, set the new view matrix. This will have no effect on the object already drawn during this frame.
When the above code is executed in a loop, this will have the effect that the camera always looks at the object's position from last frame, and as faster your object is moving, the more away from the camera it will get.
Set the matrices before you draw the object.

Transformation hierarchy causes object to jump in space?

I have two objects that I want to parent together so that Tri is a child of Torus. When I do so and multiply the matricies together by adding the parents modelView to the childs, the child jumps in space initially, over to the right and up by a few units. Where do I insert an offset into this, and how do I calculate it?
obj = make_shared<Object>(*this);
obj->rename("tri");
obj->type->val_s = "tri";
obj->t->val_3 = glm::vec3(-4.f, 1.5f, 0.f);
allObj.push_back(obj);
obj = make_shared<Object>(*this);
obj->rename("torus");
obj->type->val_s = "obj";
obj->t->val_3 = glm::vec3(3.f, 2.f, 0.f);
allObj.push_back(obj);
//Matrix
scaleM = glm::scale(glm::mat4(), s->val_3);
rotationM = glm::toMat4(r_quat);
glm::vec3 usablePivot = t->val_3 - pivot->val_3;
glm::mat4 localAxis1M = glm::translate(glm::mat4(), usablePivot);
glm::mat4 localAxis2M = glm::translate(glm::mat4(), -usablePivot);
translationM = glm::translate(glm::mat4(), t->val_3);
modelM = translationM * localAxis2M * rotationM * scaleM * localAxis1M;
//View
usableView = myGL->ViewM;
//Projection
usableProjection = myGL->ProjectionM;
//MVP
if (parent == "world") { MVP = usableProjection * usableView * modelM; }
else { MVP = usableProjection * usableView * parentTo->modelM * modelM; }
Matrix order in mine OpenGL apps:
sub-object matrices
the lowest in ownership hierarchy are first
they are local to their parents
their have offset to point (0,0,0) of parent space
if not then and they are local to world then this is the jump reason
in that case the sub-objects are not really sub objects
and handle them as normal object without parent
object to world
is transform matrix of objects without parent
they are local to your scene world
then goes camera view
it is inverse of camera space
where Z-axis is view direction
last is projection
like gluPerspective(...)
this one is usually stored in GL_PROJECTION matrix on fixed pipeline
instead of GL_MODELVIEW
Clipping is done by OpenGL separately via glViewport
(your usable view I think)
Look for more info here
you can check the content of your matrices
look at positions 12,13,14 where the offset vector is stored
do not forget that this vector is local to parent coordinate system!!!
so it is more likely rotated by it ...
also a good idea is to draw axis lines for each tested matrix in its parent space
to see if they are correct
I use red,gree,blue lines for x,y,z - axis
just extract origin of coordinate system [12,13,14]
and draw line from it to the same point + a*axis vector
a is line length (big enough so you see a line not a point)
axis vectors are at positions x=[0,1,2], y=[4,5,6], z=[8,9,10]
do not forget to set matrices to parent coordinate system !!!
if you handle matrices your self via GLSL then do not forget that
direction vectors like Normals are transformed without offset
so get the whole transform matrix (all multilicated together without projection and sometimes also camera)
set the offset to zero [12,13,14]=(0.0,0.0,0.0)
and multiply by this matrix

How to Rotate a object3D in PyOpenGL?

I am trying to rotate one object in the X-axis, but I don't get.
I have a class Object 3D it's:
class Object3D():
implements( IRenderizable )
def __init__(self, parameters={} ):
self.parameters = parameters
self.ID= Engine().addObject3D()
self.parent = None
self.childrens =[]
self.position = (parameters.get('POSITION') is None ) is True and Vector4() or parameters.get('POSITION')
self.rotation = (parameters.get('ROTATION') is None ) is True and Quaternion() or parameters.get('ROTATION')
self.direction = Vector4()
self.scale = Vector3(1,1,1)
self.matrix = Matrix4()
self.matrixLocal = Matrix4()
self.matrixWorld = Matrix4()
self.matrixRotationWorld = Matrix4()
self.up = Vector3(0,1,0 )
self.parameters =parameters
self.rotationAngle= 10.
self.currentMatrix = None
self.initCurrentMatrix()
def initCurrentMatrix(self):
glPushMatrix()
glLoadIdentity()
self.currentMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
glPopMatrix()
return
def setID(self, Id ):
self.ID = Id
def moveTo( self, x,y,z ):
v=Vector4(x,y,z)
#self.position.addSelf( self.rotation.rotateVector(v) )
self.position.addSelf( v )
glPushMatrix()
glLoadIdentity()
glTranslatef( float(self.position.x),float(self.position.y),float(self.position.z) )
self.currentMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
glPopMatrix()
return self
def render(self):
pass
In this chunk of code you see how to implements the rotation:
def rotateX(self, angle=2 ):
glPushMatrix()
glRotated( angle, 0,1,0)
glPopMatrix()
return self
when Vector4, Vector3 , Quaternion, Matrix4 are my own classes.
what this my mistake? and How to make a Rotation?
I don't know, whether it helps, but the general workflow for moving or rotating an object is like the following:
draw static stuff
push actual matrix on stack (glPushMatrix)
load identity matrix (initial matrix) (glLoadIdentity)
use your own matrix and load and set it as the actual matrix
transform the actual matrix via glRotate / gl....
save the actual matrix as your own matrix
draw your object
pop matrix from stack (glPopMatrix)
draw rest of the static stuff
In step 5/6 you have updated your transformation matrix. This is necessary, because glRotate is like a makro for multiply an rotation matrix onto the actual transformation matrix. If you always load the identity matrix and then do an glRotate then it transforms the identity matrix by only the given degree --> your object will be drawn rotated by this degree and then never do something else - i guess, this is your fault...
if you use the 9 steps above, the matrix for your object will be multiplied by the rotation matrix and the result is used for the next multiply in the next iteration step.
I hope, this will help in general understanding =)
In your rotate func, it should be degrees not angle:
glRotatef(degrees, 0, 0, -1)
Does that work?
what this my mistake?
You mistake OpenGL for a math library, which it is not. Do not use OpenGL for doing math on matrices you keep around in some variable. Actually, don't use OpenGL matrix functions at all. They're part of the fixed function pipeline and have been removed from later versions of OpenGL.

Preserving rotations in OpenGL

I'm drawing an object (say, a cube) in OpenGL that a user can rotate by clicking / dragging the mouse across the window. The cube is drawn like so:
void CubeDrawingArea::redraw()
{
Glib::RefPtr gl_drawable = get_gl_drawable();
gl_drawable->gl_begin(get_gl_context());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
{
glRotated(m_angle, m_rotAxis.x, m_rotAxis.y, m_rotAxis.z);
glCallList(m_cubeID);
}
glPopMatrix();
gl_drawable->swap_buffers();
gl_drawable->gl_end();
}
and rotated with this function:
bool CubeDrawingArea::on_motion_notify_event(GdkEventMotion* motion)
{
if (!m_leftButtonDown)
return true;
_3V cur_pos;
get_trackball_point((int) motion->x, (int) motion->y, cur_pos);
const double dx = cur_pos.x - m_lastTrackPoint.x;
const double dy = cur_pos.y - m_lastTrackPoint.y;
const double dz = cur_pos.z - m_lastTrackPoint.z;
if (dx || dy || dz)
{
// Update angle, axis of rotation, and redraw
m_angle = 90.0 * sqrt((dx * dx) + (dy * dy) + (dz * dz));
// Axis of rotation comes from cross product of last / cur vectors
m_rotAxis.x = (m_lastTrackPoint.y * cur_pos.z) - (m_lastTrackPoint.z * cur_pos.y);
m_rotAxis.y = (m_lastTrackPoint.z * cur_pos.x) - (m_lastTrackPoint.x * cur_pos.z);
m_rotAxis.z = (m_lastTrackPoint.x * cur_pos.y) - (m_lastTrackPoint.y * cur_pos.x);
redraw();
}
return true;
}
There is some GTK+ stuff in there, but it should be pretty obvious what it's for. The get_trackball_point() function projects the window coordinates X Y onto a hemisphere (the virtual "trackball") that is used as a reference point for rotating the object. Anyway, this more or less works, but after I'm done rotating, and I go to rotate again, the cube snaps back to the original position, obviously, since m_angle will be reset back to near 0 the next time I rotate. Is there anyway to avoid this and preserve the rotation?
Yeah, I ran into this problem too.
What you need to do is keep a rotation matrix around that "accumulates" the current state of rotation, and use it in addition to the rotation matrix that comes from the current dragging operation.
Say you have two matrices, lastRotMx and currRotMx. Make them members of CubeDrawingArea if you like.
You haven't shown us this, but I assume that m_lastTrackPoint is initialized whenever the mouse button goes down for dragging. When that happens, copy currRotMx into lastRotMx.
Then in on_motion_notify_event(), after you calculate m_rotAxis and m_angle, create a new rotation matrix draggingRotMx based on m_rotAxis and m_angle; then multiply lastRotMx by draggingRotMx and put the result in currRotMx.
Finally, in redraw(), instead of
glRotated(m_angle, m_rotAxis.x, m_rotAxis.y, m_rotAxis.z);
rotate by currRotMx.
Update: Or instead of all that... I haven't tested this, but I think it would work:
Make cur_pos a class member so it stays around, but it's initialized to zero, as is m_lastTrackPoint.
Then, whenever a new drag motion is started, before you initialize m_lastTrackPoint, let _3V dpos = cur_pos - m_lastTrackPoint (pseudocode).
Finally, when you do initialize m_lastTrackPoint based on the mouse event coords, subtract dpos from it.
That way, your cur_pos will already be offset from m_lastTrackPoint by an amount based on the accumulation of offsets from past arcball drags.
Probably error would accumulate as well, but it should be gradual enough so as not to be noticeable. But I'd want to test it to be sure... composed rotations are tricky enough that I don't trust them without seeing them.
P.S. your username is demotivating. Suggest picking another one.
P.P.S. For those who come later searching for answers to this question, the keywords to search on are "arcball rotation". An definitive article is Ken Shoemake's section in Graphical Gems IV. See also this arcball tutorial for JOGL.