https://en.wikipedia.org/wiki/Homogeneous_coordinates
Don't ask me any questions about it though. I only ever know as much as I need to when I need to
Hi everyone !
So I'm trying to change two vertices coordinates over time in python and then send this information to OpenGL. I was able to do it in glumpy using :
x = .5*np.cos(totalTime)
program['position'] = np.array([(x, 0.), (-x, 0.)])
In vispy however it has been more complicated. I looked a bit in the code and finally managed to do it using :
x = .5*np.cos(totalTime)
newPos = np.array([(x, 0.), (-x, 0.)])
self.program['position'].base.set_subdata(newPos.astype(np.float32))
So this works but I was wondering about why this is so different and wether it's really the simplest way to do that. Does anyone have an idea ? Thank you !
(I think my variables are quite clear but if not I would be happy to send a more complete source.)
Hey. Thanks for your answer.
With :
self.program['position'][:] = np.array([(x, 0.), (-x, 0.)]) #even with .astype(np.float32)
I get the following error :
File "/home/.../vispy/gloo/buffer.py", line 400, in __setitem__
raise RuntimeError("Cannot set data on Buffer view")
RuntimeError: Cannot set data on Buffer view
Looking in buffer.py I concluded that I had to access to the DataBuffer that is associated with this DataBufferView. Therefore I added .base
. Then I found the method set_subdata
in DataBuffer
. Finally I had to convert my np.float64
x
to a np.float32
(because of line 426 in buffer.py).
The relevant variables are instantiated that way (in the __init__
method):
self.program = gloo.Program(vertex, fragment, count=2)
self.program['position'] = [(.5, 0), (-.5, 0)]
And I'm updating the position this way :
class MyCanvas(app.Canvas):
def __init__....
...
self.timer = app.Timer('auto', self.on_timer)
self.timer.start()
def on_timer(self, event):
totalTime = self.timer.elapsed
x =...
newPos =...
self.program['position'].base.set_subdata(newPos.astype(np.float32))
self.update()
from vispy import app, gloo
import numpy as np
vertex = """
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0., 1.);
}
"""
fragment = """
void main() {
gl_FragColor = vec4(1., 0., 0., 1.);
}
"""
class MyCanvas(app.Canvas):
def __init__(self):
app.Canvas.__init__(self)
self.program = gloo.Program(vertex, fragment, count=2)
self.program['position']= [(.5, 0), (-.5, 0)]
self.timer = app.Timer("auto", self.on_timer)
self.timer.start()
self.show()
def on_timer(self, event):
totalTime = self.timer.elapsed
x = .5*np.cos(totalTime)
newPos = np.array([(x, 0), (-x, 0)])
self.program['position'].base.set_subdata(newPos.astype(np.float32))
self.update()
def on_draw(self, event):
gloo.clear()
self.program.draw("lines")
c = MyCanvas()
app.run()
And with
self.program['position'] = newPos
I get the following error :
File "testVispy.py", line 34, in on_timer
self.program['position'] = newPos
File "/home/chams/.local/lib/python3.6/site-packages/vispy/gloo/program.py", line 409, in __setitem__
vbo.set_data(data)
File "/home/chams/.local/lib/python3.6/site-packages/vispy/gloo/buffer.py", line 381, in set_data
raise RuntimeError("Cannot set data on buffer view.")
RuntimeError: Cannot set data on buffer view.
_pos
:class MyCanvas(app.Canvas):
def __init__(self):
app.Canvas.__init__(self)
self.program = gloo.Program(vertex, fragment, count=2)
self._pos = gloo.VertexBuffer()
self.program['position'] = np.array([[.5, 0], [-.5, 0]], dtype=np.float32)
self.timer = app.Timer("auto", self.on_timer)
self.timer.start()
self.show()
def on_timer(self, event):
totalTime = self.timer.elapsed
x = .5*np.cos(totalTime)
newPos = np.array([(x, 0), (-x, 0)])
self._pos.set_data(newPos.astype(np.float32))
self.program['position'] = self._pos
self.update()
@almarklein @rougier Any memory why gloo.Program
creates a View for each of the buffers? Meaning self.program['position']
is a DataBufferView
when the program is created?
@cgharib Actually if you set the VertexBuffer
in the __init__
and then do self.program['position'] = newPos.astype(np.float32)
then it seems to work. The main problem seems to be that the gloo.Program
creation defaults to creating a View. I'm not exactly sure why the original self.program['position'] =
works as that should be a View too.
Hey. Thanks for all your answers. So here's how I would write it based on @djhoese 's code.
import numpy as np
from vispy import app, gloo
vertex = """
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0., 1.);
}
"""
fragment = """
void main() {
gl_FragColor = vec4(1.,0.,0.,1.);
}
"""
class MyCanvas(app.Canvas):
def __init__(self):
app.Canvas.__init__(self)
self.program = gloo.Program(vertex, fragment, count=2)
self.vertexBuffer = gloo.VertexBuffer(np.array([(.5, 0), (-.5, 0)], dtype=np.float32))
self.program['position'] = self.vertexBuffer
self.timer = app.Timer('auto', self.on_timer)
self.timer.start()
self.show()
def on_draw(self, event):
gloo.clear()
self.program.draw('lines')
def on_timer(self, event):
totalTime = self.timer.elapsed
x = .5*np.cos(totalTime)
newPos = np.array([(x, 0), (-x, 0)], dtype=np.float32)
self.vertexBuffer.set_data(newPos)
self.update()
c = MyCanvas()
app.run()
Does it seem idiomatic to you ? Thanks a lot !
self.program['position'] = newPos
. It feels more future-proof and avoids the possibility of the VertexBuffer being copied inside the Program and your set_data
not having an effect. Hopefully that makes sense. Either way should work so do what feels good to you.
ellipse.transform = STTransform(translate=(0, 0, some_z_shift))
. You may also run into issues with drawing order between the Image and Ellipse where you may need to do something like ellipse.order = -5
, but see if the Z position works well enough first.
Hello guys. I'm developing a software to visualize thickness maps by using PyQt as Desktop Framework, however, I'm experiencing some problems. The central widget is a grid layout with multiple scatter plots, in a sub grid each, When i minimize and maximize the window multiple times the layout tends to collapse, then i get the following error
WARNING: Traceback (most recent call last):
File ".\src\CrushingApp.py", line 324, in <module>
sys.exit(app.exec_())
File "C:\Users\site-packages\vispy\app\backends\_qt.py", line 508, in event
out = super(QtBaseCanvasBackend, self).event(ev)
File "C:\Users\site-packages\vispy\app\backends\_qt.py", line 825, in paintGL
self._vispy_canvas.events.draw(region=None)
File "C:\Users\\site-packages\vispy\util\event.py", line 455, in __call__
self._invoke_callback(cb, event)
File "C:\Users\site-packages\vispy\util\event.py", line 475, in _invoke_callback
self, cb_event=(cb, event))
<< caught exception here: >>
File "C:\Users\site-packages\vispy\util\event.py", line 471, in _invoke_callback
cb(event)
File "C:\Users\site-packages\vispy\scene\canvas.py", line 217, in on_draw
self._draw_scene()
File "C:\Users\site-packages\vispy\scene\canvas.py", line 266, in _draw_scene
self.draw_visual(self.scene)
File "C:\Users\site-packages\vispy\scene\canvas.py", line 304, in draw_visual
self.add_with_artificial_variable(expr)
File "C:\Users\site-packages\vispy\ext\_bundled\cassowary\simplex_solver.py", line 381, in
add_with_artificial_variable
raise RequiredFailure()
vispy.ext._bundled.cassowary.error.RequiredFailure
ERROR: Invoking <bound method SceneCanvas.on_draw of <CanvasMapaEspesores (PyQt5) at 0x149ed69fe08>> for DrawEvent
is there a way to avoi
self.t2 = scene.visuals.Text('Test Text', parent=self.view.scene, color='green')
self.t2.font_size = 14
self.plane = scene.visuals.Plane(
width=1000,
height=300,
parent=self.t2
)
self.plane.transform = vispy.visuals.transforms.STTransform(translate=(0, 0, 0),
scale=(1., 1., 1.)).as_matrix()
def on_mouse_move(self, event):
if event.button == 1 and event.is_dragging:
self.plane.transform.reset()
self.plane.transform.rotate(self.view.camera.azimuth, (0, 0, 1))
self.plane.transform.rotate(90 - self.view.camera.elevation, (0, 1, 0))
self.plane.transform.rotate(self.view.camera.roll, (1, 0, 0))
This is what i tried
import numpy as np
import vispy.scene
from vispy.scene import visuals
from vispy.visuals import text
class CustomCanvas(vispy.scene.SceneCanvas):
def __init__(self):
super(CustomCanvas, self).__init__(keys='interactive', show=True)
self.unfreeze()
self.view = self.central_widget.add_view()
self.xyz_top = None
self.textLabelMax = None
self.backgroundLabelMax = None
self.events.mouse_move.connect(self.on_mouse_move)
self.freeze()
def on_mouse_move(self, event):
if(event.button == 1 and event.is_dragging):
self.backgroundLabelMax.transform.reset()
self.backgroundLabelMax.transform.rotate(self.view.camera.azimuth, (0, 0, 1))
self.backgroundLabelMax.transform.rotate(90 - self.view.camera.elevation, (1, 0, 0))
self.backgroundLabelMax.transform.translate(self.xyz_top)
def draw_cloud_points(self):
pos = np.random.normal(size=(100000, 3), scale=0.2)
# one could stop here for the data generation, the rest is just to make the
# data look more interesting. Copied over from magnify.py
centers = np.random.normal(size=(50, 3))
indexes = np.random.normal(size=100000, loc=centers.shape[0]/2.,
scale=centers.shape[0]/3.)
indexes = np.clip(indexes, 0, centers.shape[0]-1).astype(int)
scales = 10**(np.linspace(-2, 0.5, centers.shape[0]))[indexes][:, np.newaxis]
pos *= scales
pos += centers[indexes]
# create scatter object and fill in the data
scatter = visuals.Markers()
scatter.set_data(pos, edge_color=None, face_color=(1, 1, 1, .5), size=5)
self.view.add(scatter)
# Adding text label at center / top (Z axis)
self.xyz_top = (pos[:,0].max(), pos[:,1].max(), pos[:,2].max())
self.textLabelMax = visuals.Text(pos=self.xyz_top, text="Test_Label_Max", font_size=24, color="white", parent=self.view.scene)
# Adding plane as background for texts
self.backgroundLabelMax = visuals.Plane(width=5, height = 1, color=(1, 0, 0, 0.4), parent=self.view.scene)
self.backgroundLabelMax.transform = vispy.scene.transforms.STTransform(
scale=(1, 1, 1),
translate=self.xyz_top
).as_matrix()
# Adding turntable with ortographic view
self.view.camera = vispy.scene.TurntableCamera(fov=0, azimuth=0, elevation=90, roll=0)
# Auto focus
self.view.camera.set_range()
def main():
custom_canvas = CustomCanvas()
custom_canvas.draw_cloud_points()
if __name__ == '__main__':
import sys
if sys.flags.interactive != 1:
main()
vispy.app.run()
self.backgroundLabelMax.transform.matrix = self.view.camera.transform.matrix
and self.backgroundLabelMax.transform.translate(self.xyz_top)
gets it pretty close...somehow