pythonpython-3.xtkinterpovray

Live 3d view pov-ray and tkinter


I am trying to make a GUI in python (tkinter). I have successfully created the application such that I have a scene rendered by POV-ray. I press button "move to left" and this changes the camera location in the .pov file, re-renders the scene and shows it in the GUI(same for rotation and zoom in/out).

But I would like to make interactive. i.e use mouse to interact with the scene completely just like a matplotlib 3D graph but for ray-rendering.

How to go about solving this problem ?

The Scenes have values of location as

Img_1 location <0,0,-10>

Img_2 location <0,-10,-10>

Img_3 location <25,0,-10>

PS

I am not trying to import matplotlib plot in my GUI. It is just for refrence to share what I want to achieve with my rendered scenes.

[img1]img11

[img2]img22

[img3]img33


Solution

  • You can use mouse events <Motion> and <Button-1>, (and others) to run functions which will change content in window.


    EDIT: Examples show how to use bind() to run functions when you use mouse and how to calculate diff_x, diff_y to move objects. You have to uses own functions with bind() which will use diff_x, diff_y to move POVRay camera and render new image. And then you will have to replace image on canvas. But I will use canvas objects instead of POVRay to show how it can change when mouse is moving.


    This example moves rectangle when you move mouse, and it changes color when you click button.
    But you can run functions which move, zoom or rotate rendered image.

    import tkinter as tk
    
    # --- functions ---
    
    def move_item(event):
        canvas.coords(item, event.x-50, event.y-50, event.x+50, event.y+50)
    
    def change_item(event):
        if canvas.itemcget(item, 'fill') == 'red':
            canvas.itemconfig(item, fill='blue')
        else:        
            canvas.itemconfig(item, fill='red')
    
    # --- main ---
    
    root = tk.Tk()
    
    canvas = tk.Canvas(root, width=500, height=300)
    canvas.pack()
    
    item = canvas.create_rectangle(0, 0, 100, 100, fill='red')
    
    canvas.bind("<Button-1>", change_item)
    canvas.bind("<Motion>", move_item)
    
    root.mainloop()
    

    EDIT: Example which uses <B1-Motion>, <Shift-B1-Motion>, <Control-B1-Motion> to move objects:

    Code:

    import tkinter as tk
    
    # --- functions ---
    
    def move_item(event):
        global old_x
        global old_y    
        diff_x = event.x - old_x
        diff_y = event.y - old_y
        for item in items:
            canvas.move(item, diff_x, diff_y)
        old_x = event.x
        old_y = event.y
    
    def move_horizontal(event):
        global old_x
        diff_x = event.x - old_x
        for item in items:
            canvas.move(item, diff_x, 0)
        old_x = event.x
    
    def move_vertical(event):
        global old_y
        diff_y = event.y - old_y
        for item in items:
            canvas.move(item, 0, diff_y)
        old_y = event.y
    
    def save_position(event):
        global old_x
        global old_y    
        old_x = event.x
        old_y = event.y
        
    # --- main ---
    
    old_x = 0
    old_y = 0
    # init
    root = tk.Tk()
    
    # create canvas
    canvas = tk.Canvas(root, width=500, height=300)
    canvas.pack()
    
    # create objects
    items = [
        canvas.create_rectangle(100, 100, 130, 130, fill='red'),
        canvas.create_rectangle(200, 100, 230, 130, fill='blue'),
        canvas.create_rectangle(100, 200, 130, 230, fill='yellow'),
    ]
    
    canvas.bind("<Button-1>", save_position)
    canvas.bind("<B1-Motion>", move_item)
    canvas.bind("<Shift-B1-Motion>", move_horizontal)
    canvas.bind("<Control-B1-Motion>", move_vertical)
    # start program
    root.mainloop()