So I’m working on some project with using 3d interaction
I want to give VTK Interactor a Unity’s Feel( That is hold right mouse and move to rotate camera)
But seemingly all the inputs detection is on WxPython frame
I just want to Input my keyboard and right mouse movement to vtk render window directly.
Why is this happening? And how could I fix this?
import vtk
import wx
from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor
import numpy as np
import pyautogui as pag
def hypot(*a):
return np.sqrt(np.sum(np.array(a)**2))
def norm(*a):
return np.array(a)/hypot(*a)
class CustomInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
def __init__(self):
super().__init__()
self.AddObserver("KeyPressEvent", self.keyPressEvent)
self.AddObserver("CharEvent", self.OnChar)
self.AddObserver("RightButtonPressEvent", self.rightButtonPressEvent)
self.AddObserver("RightButtonReleaseEvent", self.rightButtonReleaseEvent)
self.AddObserver("MouseMoveEvent", self.OnMouseMove)
self.step_size=0.5
self.wireframe_mode = False
self.right_button_hold = False
def get_camera(self):
return self.GetCurrentRenderer().GetActiveCamera()
def update_renderer(self):
self.GetCurrentRenderer().ResetCameraClippingRange()
self.GetCurrentRenderer().GetRenderWindow().Render()
def get_camera_position(self):
camera = self.get_camera()
return camera.GetPosition()
def get_forward_vector_camera(self):
camera = self.get_camera()
position = camera.GetPosition()
focal_point = camera.GetFocalPoint()
forward_vector = [f - p for f,p in zip(focal_point,position)] # Calculate view vector
forward_vector = norm(*forward_vector)
return forward_vector
def get_up_vector_camera(self):
camera = self.get_camera()
up_vector = camera.GetViewUp()
up_vector = norm(*up_vector)
return camera.GetViewUp()
def get_left_vector_camera(self):
forward_vector = self.get_forward_vector_camera()
up_vector = self.get_up_vector_camera()
left_vector = [0,0,0]
vtk.vtkMath.Cross(up_vector, forward_vector,left_vector)
left_vector = [v/hypot(left_vector) for v in left_vector]
return left_vector
def OnChar(self,obj,event):
pass
def OnMouseMove(self, obj, event):
if self.right_button_hold:
self.end_pose = pag.position()
azimuth_angle=-(self.end_pose[0]-self.started_mouse_position[0])/1920*45
elevation_angle=(self.end_pose[1]-self.started_mouse_position[1])/1080*45
old_focal_point=self.get_camera().GetFocalPoint()
fixed_position=self.get_camera_position()
self.get_camera().Azimuth(azimuth_angle)
self.get_camera().Elevation(elevation_angle)
functioned_focal_point=self.get_camera().GetFocalPoint()
functioned_position=self.get_camera_position()
self.get_camera().SetFocalPoint(
[
functioned_focal_point[0]-functioned_position[0]+fixed_position[0],
functioned_focal_point[1]-functioned_position[1]+fixed_position[1],
functioned_focal_point[2]-functioned_position[2]+fixed_position[2]
]
)
self.get_camera().SetPosition(fixed_position)
print(self.get_camera_position())
self.started_mouse_position = self.end_pose
self.update_renderer()
def rightButtonPressEvent(self, obj, event):
self.right_button_hold = True
self.started_mouse_position = pag.position()
def rightButtonReleaseEvent(self, obj, event):
self.right_button_hold = False
self.started_mouse_position = None
def IsRightButtonHold(self):
return self.right_button_hold
def keyPressEvent(self, obj, event):
# key = self.GetInteractor().GetKeySym()
key = self.GetInteractor().GetKeyCode().lower()
print(key)
if self.right_button_hold:
if key == "w" or key == "W":
self.moveCameraForward()
elif key == "s" or key == "S":
self.moveCameraBackward()
elif key == "a" or key == "A":
self.moveCameraLeft()
elif key == "d" or key == "D":
self.moveCameraRight()
elif key == "b" or key == "B":
self.toggleWireframeMode()
elif key == "q" or key == "Q":
self.moveCameraUp()
elif key == "e" or key == "E":
self.moveCameraDown()
else:
# super().OnKeyPress()
# super().OnChar()
pass
def set_camera_position(self, position):
camera = self.get_camera()
old_camera_position=camera.GetPosition()
old_focal_point=camera.GetFocalPoint()
camera.SetFocalPoint([f + p - o for f,p,o in zip(old_focal_point,position,old_camera_position)])
camera.SetPosition(position)
self.update_renderer()
def moveCameraForward(self):
forward_vector = self.get_forward_vector_camera()
position=self.get_camera_position()
step = [s * self.step_size for s in forward_vector] # Scale the view vector based on step size
new_position = [p + s for p, s in zip(position, step)]
self.set_camera_position(new_position)
def moveCameraBackward(self):
forward_vector = self.get_forward_vector_camera()
position=self.get_camera_position()
step = [s * self.step_size for s in forward_vector] # Scale the view vector based on step size
new_position = [p - s for p, s in zip(position, step)]
self.set_camera_position(new_position)
def moveCameraUp(self):
up_vector = self.get_up_vector_camera()
position=self.get_camera_position()
step = [s * self.step_size for s in up_vector]
new_position = [p + s for p, s in zip(position, step)]
self.set_camera_position(new_position)
def moveCameraDown(self):
up_vector = self.get_up_vector_camera()
position=self.get_camera_position()
step = [s * self.step_size for s in up_vector]
new_position = [p - s for p, s in zip(position, step)]
self.set_camera_position(new_position)
def moveCameraLeft(self):
left_vector = self.get_left_vector_camera()
position=self.get_camera_position()
step = [s * self.step_size for s in left_vector]
new_position = [p + s for p, s in zip(position, step)]
self.set_camera_position(new_position)
def moveCameraRight(self):
left_vector = self.get_left_vector_camera()
position=self.get_camera_position()
step = [s * self.step_size for s in left_vector]
new_position = [p - s for p, s in zip(position, step)]
self.set_camera_position(new_position)
# def moveCameraLeft(self):
# camera = self.GetCurrentRenderer().GetActiveCamera()
# view_up = camera.GetViewUp()
# view_vector = [f - p for p, f in zip(camera.GetFocalPoint(), camera.GetPosition())]
# left_vector = [0,0,0]
# vtk.vtkMath.Cross(view_vector, view_up,left_vector)
# step = [s * self.step_size for s in left_vector]
# new_position = [p + s for p, s in zip(camera.GetPosition(), step)]
# camera.SetPosition(new_position)
# self.GetCurrentRenderer().ResetCameraClippingRange()
# self.GetCurrentRenderer().GetRenderWindow().Render()
# def moveCameraRight(self):
# camera = self.GetCurrentRenderer().GetActiveCamera()
# view_up = camera.GetViewUp()
# view_vector = [f - p for p, f in zip(camera.GetFocalPoint(), camera.GetPosition())]
# left_vector = [0,0,0]
# vtk.vtkMath.Cross(view_vector, view_up,left_vector)
# step = [s * self.step_size for s in left_vector]
# new_position = [p - s for p, s in zip(camera.GetPosition(), step)]
# camera.SetPosition(new_position)
# self.GetCurrentRenderer().ResetCameraClippingRange()
# self.GetCurrentRenderer().GetRenderWindow().Render()
def toggleWireframeMode(self):
if self.wireframe_mode:
self.wireframe_mode = False
for actor in self.GetCurrentRenderer().GetActors():
actor.GetProperty().SetRepresentationToSurface()
else:
self.wireframe_mode = True
for actor in self.GetCurrentRenderer().GetActors():
actor.GetProperty().SetRepresentationToWireframe()
class VTKFrame(wx.Frame):
def __init__(self, parent, title):
super(VTKFrame, self).__init__(parent, title=title, size=(800, 600))
# Create a VTK renderer
self.renderer = vtk.vtkRenderer()
# Create a VTK render window
self.render_window = vtk.vtkRenderWindow()
self.render_window.AddRenderer(self.renderer)
# Create a VTK render window interactor without setting the style initially
self.interactor = wxVTKRenderWindowInteractor(self, -1)
self.interactor.SetRenderWindow(self.render_window)
# Set the custom interactor style after creating the interactor object
self.interactor_style = CustomInteractorStyle()
# self.interactor_style = vtk.vtkInteractorStyleUser()
self.interactor_style.SetInteractor(self.interactor)
self.interactor_style.SetCurrentRenderer(self.renderer)
self.interactor.SetInteractorStyle(self.interactor_style)
# Create a plane source
plane_source = vtk.vtkPlaneSource()
plane_source.SetOrigin(-10, -10, 0)
plane_source.SetPoint1(10, -10, 0)
plane_source.SetPoint2(-10, 10, 0)
plane_source.SetXResolution(20)
plane_source.SetYResolution(20)
# Create a mapper for the plane
plane_mapper = vtk.vtkPolyDataMapper()
plane_mapper.SetInputConnection(plane_source.GetOutputPort())
# Create an actor for the plane
plane_actor = vtk.vtkActor()
plane_actor.SetMapper(plane_mapper)
plane_actor.GetProperty().SetColor(0.7, 0.7, 0.7) # Gray color for the plane
self.renderer.AddActor(plane_actor)
# Create a sphere source
sphere_source = vtk.vtkSphereSource()
sphere_source.SetCenter(0, 0, 1) # Place the sphere slightly above the plane
sphere_source.SetRadius(1)
# Create a mapper for the sphere
sphere_mapper = vtk.vtkPolyDataMapper()
sphere_mapper.SetInputConnection(sphere_source.GetOutputPort())
# Create an actor for the sphere
sphere_actor = vtk.vtkActor()
sphere_actor.SetMapper(sphere_mapper)
sphere_actor.GetProperty().SetColor(1, 0, 0) # Red color for the sphere
self.renderer.AddActor(sphere_actor)
# Set up the interactor
self.interactor.Enable(1)
self.interactor.AddObserver("ExitEvent", lambda obj, event: self.Close())
# Add the interactor to the sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.interactor, 1, wx.EXPAND)
self.SetSizer(sizer)
self.Layout()
# Start the interactor
self.interactor.Initialize()
self.render_window.Render()
app = wx.App(False)
frame = VTKFrame(None, "VTK with wxPython")
frame.Show()
app.MainLoop()