Mouse position on (OpenGL) scene - python-2.7

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!

Related

In OpenGL 3.3, is there any more efficient and correct way of drawing a point?

I intend to draw points that usually only change the position on the screen.
The color and size do not usually vary.
So I did this class Point in Python:
class Point2D():
_verts = None
_vshader_code = '''
#version 330
in vec2 pos;
uniform float size;
void main() {
gl_Position = vec4(pos, 0.0, 1.0);
gl_PointSize = size;
}
'''
_fshader_code = '''
#version 330
uniform vec4 col;
void main() {
gl_FragColor = col;
}
'''
def __init__(self, size, col):
## CREATE PROGRAM/SHADER ##
self.program = GL.glCreateProgram()
self.shaders = [
CreateShader(self._vshader_code, GL.GL_VERTEX_SHADER),
CreateShader(self._fshader_code, GL.GL_FRAGMENT_SHADER)
]
for shader in self.shaders:
GL.glAttachShader(self.program, shader)
GL.glLinkProgram(self.program)
#CheckShaderError(self.program, GL.GL_LINK_STATUS, True, "Error: Program linking failed:")
GL.glValidateProgram(self.program)
#CheckShaderError(self.program, GL.GL_VALIDATE_STATUS, True, "Error: Program is invalid:")
self.unif_size = GL.glGetUniformLocation(self.program, 'size')
self.unif_col = GL.glGetUniformLocation(self.program, 'col')
GL.glUseProgram(self.program)
GL.glUniform1f(self.unif_size, size)
GL.glUniform4fv(self.unif_col, 1, col)
## FLAGS ##
#GL.glEnable(GL.GL_PROGRAM_POINT_SIZE);
GL.glEnable(GL.GL_VERTEX_PROGRAM_POINT_SIZE)
def bind_array(self, array):
self._verts = array
## BIND BUFFER ##
self.vertexArrayObject = GL.glGenVertexArrays(1)
GL.glBindVertexArray(self.vertexArrayObject)
self.buff = GL.glGenBuffers(1)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.buff)
GL.glBufferData(GL.GL_ARRAY_BUFFER, self._verts.nbytes, self._verts, GL.GL_STATIC_DRAW)
self.attr_pos = GL.glGetAttribLocation(self.program, 'pos')
GL.glEnableVertexAttribArray(0)
GL.glVertexAttribPointer(self.attr_pos, 2, GL.GL_FLOAT, GL.GL_FALSE, 8, None)
GL.glBindVertexArray(0)
def update_size_and_color(self, size, col):
#GL.glPointSize(size)
GL.glUseProgram(self.program)
GL.glUniform1f(self.unif_size, size)
GL.glUniform4fv(self.unif_col, 1, col)
def update_elem(self, index, value):
GL.glUseProgram(self.program)
self._verts[index] = value
GL.glBindVertexArray(self.vertexArrayObject)
GL.glBufferSubData(GL.GL_ARRAY_BUFFER, index * 8, 8, value)
GL.glBindVertexArray(0)
def Draw(self):
GL.glUseProgram(self.program)
GL.glBindVertexArray(self.vertexArrayObject)
GL.glDrawArrays(GL.GL_POINTS, 0, len(self._verts))
GL.glBindVertexArray(0)
def __del__(self):
try:
#if the context is alive, you want to try and delete shader/program stuff manually
#this could be triggered with e.g. `del Display`
for shader in self.shaders:
GL.glDetachShader(self.program, shader)
GL.glDeleteShader(shader)
GL.glDeleteProgram(self.program)
except OpenGL.error.NullFunctionError as error:
print("context already deleted my shader/program stuff!")
GL.glDisable(GL.GL_VERTEX_PROGRAM_POINT_SIZE)
With the created point object, I can do the point drawing as follows:
point = Point2D(10.0, numpy.array((1.0, 0.0, 0.0, 1.0), 'f4'))
point.bind_array(numpy.zeros((2, 2), 'f4'))
## DRAW ##
point.update_elem(0, numpy.array((0.5, 0.0), 'f4'))
point.update_elem(1, numpy.array((-0.5, 0.0), 'f4'))
point.Draw()
(...code...)
point.update_elem(1, numpy.array((0.25, 0.25), 'f4'))
point.Draw()
The drawing is practical and seemingly efficient, but the question is am I doing it right?
The way you're doing it will work and is reasonable. If you're drawing lots of points (thousands to millions), you might want to make a single array with all the coordinates and another array with the vertex attributes for all the points and issue a single draw call with those arrays. That will reduce the number of draw calls, which can be a performance limiting factor. But if you're only drawing a few dozen to maybe a few hundred, you probably won't notice a huge difference. As always, it pays to profile your code and see where the slowdowns are rather than guessing.
You should use instanced drawing. Load only one model of your point as a static data, and use array of positions (any other attributes) for those objects.
There is many tutorials about this method. Here is one for example.

Recurive game in pygame, using recursive rectangles.(pygame)

Ive been trying to make a recursive rectangles and I wanted to make the rectangles move in the forward direction like each time it recursed, so that it gives a motion as one is going into an endless rectangles. Ive tried making the size bigger each time it recursed but failed as it wont recurse or nothing would show up. Any tips or how to do this would be appreciated. This sample I implemented from pygamearcade. I want to get the feeling as one is going into the rectangles and that can be implemented as the rectangles get bigger each time it goes through recurion. So any tips or how to do it is fine. Thank you
import pygame
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, WHITE,
[x, y, width, height],
1)
speed = [10,0]
# Is the rectangle wide enough to draw again?
while (width > 14):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
pygame.init()
#rectanglelist = [big()]
# Set the height and width of the screen
size = [700, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(BLACK)
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
recursive_draw(0, 0, 700, 500)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
The problem is that your recursive_draw() function is not really a recursive function, because a recursive function is a function that conditionally calls itself:
Every properly designed recursive function must have at least one base case [A] and must redefine the problem into sub problems that work towards a base case [B].
def countdown(n):
if n < 1:
print "Lift Off" #[A]
else:
print n
countdown(n - 1) #[B]
What you could do for your code:
First fix the indent of your code.
Second, replace your while loop by an ´if´ statement.
This is the important part or recursion: The function calls itself unless a certain condition is not true anymore (in your case width > 14). For more information see How can I build a recursive function in python? or Recursion function in python on SO.
The updated function (code from http://www.balloonbuilding.com/ by Paul Vincent Craven):
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, BLACK, (x, y, width, height), 1)
# Is the rectangle wide enough to draw again?
if(width > 14):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
I hope this helps :)
EDIT:
The updated program:
import pygame
# Colors
BLUE = (55, 155, 255)
WHITE = (255, 255, 255)
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, WHITE, (x, y, width, height), 2)
# Is the rectangle wide enough to draw again?
if(width > 14):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
speed = [10,0]
pygame.init()
#rectanglelist = [big()]
# Set the height and width of the screen
size = [700, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(BLUE)
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
recursive_draw(0, 0, 700, 500)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
Screenshot:

Get depth from camera for each pixel

I have a mesh model and, using VTK, have rendered a view of it from a given camera position (x,y,z). I can save this to an RGB image (640x480) but I also want to save a depth map where each pixel stores the value of the depth from the camera.
I have tried using the Zbuffer values given by the render window by following this example. The problem is that the Zbufer only stores values in the range [0,1]. Instead I am trying to create synthetic range image, where I store the depth/distance of each pixel from the camera. Analogous to the image produced by the Kinect, I am trying to create one from a specific viewpoint of a mesh model.
EDIT - adding some code
My current code:
Load the mesh
string mesh_filename = "mesh.ply";
vtkSmartPointer<vtkPLYReader> mesh_reader = read_mesh_ply(mesh_filename);
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(mesh_reader->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//Add the actors to the scene
renderer->AddActor(actor);
renderer->SetBackground(1, 1, 1);
Create a camera and place it somewhere
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
renderer->SetActiveCamera(camera);
camera->SetPosition(0,0,650);
//Render and interact
renderWindow->Render();
Get result from the z buffer
double b = renderer->GetZ(320, 240);
In this example, this gives 0.999995. As the values are between [0,1] I don't know how to interpret this, as you can see I have set the camera to be 650 units away on the z-axis so I assume the z distance at this pixel (which is on the object in the rendered RGB) should be near to 650.
This python snippet illustrates how to convert z buffer values to real distances. The non-linear mapping is defined as follows:
numerator = 2.0 * z_near * z_far
denominator = z_far + z_near - (2.0 * z_buffer_data_numpy - 1.0) * (z_far - z_near)
depth_buffer_data_numpy = numerator / denominator
Here, a full example:
import vtk
import numpy as np
from vtk.util import numpy_support
import matplotlib.pyplot as plt
vtk_renderer = vtk.vtkRenderer()
vtk_render_window = vtk.vtkRenderWindow()
vtk_render_window.AddRenderer(vtk_renderer)
vtk_render_window_interactor = vtk.vtkRenderWindowInteractor()
vtk_render_window_interactor.SetRenderWindow(vtk_render_window)
vtk_render_window_interactor.Initialize()
source = vtk.vtkCubeSource()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(source.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.RotateX(60.0)
actor.RotateY(-35.0)
vtk_renderer.AddActor(actor)
vtk_render_window.Render()
active_vtk_camera = vtk_renderer.GetActiveCamera()
z_near, z_far = active_vtk_camera.GetClippingRange()
z_buffer_data = vtk.vtkFloatArray()
width, height = vtk_render_window.GetSize()
vtk_render_window.GetZbufferData(
0, 0, width - 1, height - 1, z_buffer_data)
z_buffer_data_numpy = numpy_support.vtk_to_numpy(z_buffer_data)
z_buffer_data_numpy = np.reshape(z_buffer_data_numpy, (-1, width))
z_buffer_data_numpy = np.flipud(z_buffer_data_numpy) # flipping along the first axis (y)
numerator = 2.0 * z_near * z_far
denominator = z_far + z_near - (2.0 * z_buffer_data_numpy - 1.0) * (z_far - z_near)
depth_buffer_data_numpy = numerator / denominator
non_depth_data_value = np.nan
depth_buffer_data_numpy[z_buffer_data_numpy == 1.0] = non_depth_data_value
print(np.nanmin(depth_buffer_data_numpy))
print(np.nanmax(depth_buffer_data_numpy))
plt.imshow(np.asarray(depth_buffer_data_numpy))
plt.show()
Side note:
On my system, a few times the imshow command did not display anything. Re-running the script did solve that issue.
Sources:
http://web.archive.org
open3d

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.

rotating model while color updating

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.