Author Topic: Scripting the cam  (Read 2721 times)

MagWeb

  • Administrator
  • Hero Member
  • *****
  • Posts: 1156
    • View Profile
Scripting the cam
« on: March 28, 2016, 07:46:28 PM »
Trying to script a workflow needing a specific view of the virtual cam:

There's CameraControl_SetSpecificView in StoredCommands.h I'm trying to call.
It needs
const vec3f & eye,
const vec3f & target,
const vec3f & up

I'm a newbie to Python scripting and MM's API: So what's the right way to construct these parameters?
Anything I tried the last days failed. Does the API expect a vec3f three floats list? Some single sting/argument or some combination?
All I tried ended in some TypeError so far...

E.g. if I try this:
Code: [Select]
     cmd2 = mmapi.StoredCommands()
     e = [1.0, 1.0, 1.0] #eye     
     t = [0.0, 0.0, 0.0] #target
     u = [0.0, 1.0, 0.0] #up     
     cmd2.CameraControl_SetSpecificView(e, t, u)       
     remote.runCommand(cmd2)
I end up with:
Code: [Select]
TypeError: in method 'StoredCommands_CameraControl_SetSpecificView', argument 2 of type 'mm::vec3f const &'This is somehow clear for I miss to point to the reference. But how to do that right?

Sorry, if that's a dumb question or I missed some basic stuff.

« Last Edit: April 12, 2016, 02:00:09 PM by MagWeb »
I'm just a user as you are. Being no Autodesk employee: I do not know where this road will lead to, nor do I claim to've all stuff got right.

MagWeb

  • Administrator
  • Hero Member
  • *****
  • Posts: 1156
    • View Profile
Re: TypeError:(...)argument 2 of type 'mm::vec3f const &'
« Reply #1 on: March 31, 2016, 11:33:53 AM »
Ok, got something working. I need something like this :
   
Code: [Select]
     cmd2 = mmapi.StoredCommands()
     e = mmapi.vec3f()
     e.x = 1.0
     e.y = 1.0
     e.z = 1.0
     t = mmapi.vec3f()
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     u = mmapi.vec3f()
     u.x = 0.0
     u.y = 1.0
     u.z = 0.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     remote.runCommand(cmd2)

Most probably some shorter way to define a vec3f ?
I'm just a user as you are. Being no Autodesk employee: I do not know where this road will lead to, nor do I claim to've all stuff got right.

RMS

  • meshmixer founder
  • Administrator
  • Hero Member
  • *****
  • Posts: 1238
    • View Profile
    • gradientspace
Re: TypeError:(...)argument 2 of type 'mm::vec3f const &'
« Reply #2 on: April 12, 2016, 12:07:41 PM »
the vec3f class is auto-generated by the c++-to-python-API-generator program (SWIG), so I cannot do things like add a more sensible constructor.

The mm package should have a function for this, but I guess I have not done it yet.

(basically, the mm package should have a wrapper for the function you are trying to call, that would take a python xyz-tuple, but that hasn't been added yet either)
created meshmixer - now starting gradientspace - meshmixer consulting available http://www.gradientspace.com/consulting

MagWeb

  • Administrator
  • Hero Member
  • *****
  • Posts: 1156
    • View Profile
Re: Scripting the cam
« Reply #3 on: April 12, 2016, 03:41:05 PM »
So if my solution isn't that strange I'd like to share a script.

Running this script constructs a GUI applet based on Tkinter.
I set it to be kept the topmost window (and here on MAC rises the first issue: If the applet is the active window and you press alt to navigate in MM moves the applet behind the MM window)

There are 6 Buttons (Top, Front, Below, Rear, Left, Right) which set the cam to view the object along the XYZ axes. (Note: These standard views do not affect your view-history. You may use pan and zoom, but as soon as you rotate the view falls back to the state before hitting such a button)
The Persp/Ortho toggle button simply switches beween perspective and orthographic view as you do via menu:View)
The Screensh. button saves a screenshot of the MM window to Documents/meshmixer/screenshots. Note: You've to create a "screenshots" folder manually before using this. It will ad a new .jpg signed with a timestamp in its name: shot+timestamp+.jpg.
The Hide/ShowPiv toggle hides existing pivots to do a screenshot. Note: ShowPiv will show all pivots, also those you've hidden manually via the object browser.
The Turntable button makes the cam spin 360° around Y. Using the Stop Button you may stop the turntable. With the >>> button you can change the spinning direction.
The Time slider (seconds) and the FPS (frames per second) are meant to calculate the needed number of frames for an output movie of a certain length and framerate.
So the shortest turn consists of Time at 1 and FPS at two which will give two images one from the front, one from the rear. 30x30 will give 900 frames.
With the Save checkbox being enabled the frames are stored to Documents/meshmixer/turntable. Note: again you've to create this folder manually. Also note: Hitting Turntable flushes the turntable directory. So do not save something different within that directory. You may use the saved images to create a turntable movie in a third party app.
At the bottom is a SelectV checkbox. This mode is meant to sample up SelectVisible results while the cam is turning. Note: This needs some small selection on the object to get started. Also while turning the whole outer surface gets selected. At the actions end the selection is inverted to all not visible stuff. So you can't see the current selection. This is meant to get rid of inside, but connected to the outer visible surface. You may hit x or y to discard or separate this selection.

I'm learning by doing. So do not hesitate to point me to more efficient or cleaner coding. Thanks

Code: [Select]
from Tkinter import *
import ttk
import mmapi
from mmRemote import *
import mm
import time
import os



#create a centered "root" window object
root = Tk()
root.title("MM View")  #name window
w = 302 # width Tk root
h = 300 # height Tk root
# get screen width and height:
ws = root.winfo_screenwidth() # width
hs = root.winfo_screenheight() # height
# calculate startup x and y coordinates for Tk root:
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))  # set root window's size and position
root.attributes("-topmost", True) # keeps root window in front




# initialize connection to MM
remote = mmRemote()
remote.connect()

#############################
# fixed views stuff:
e = mmapi.vec3f()
t = mmapi.vec3f()
u = mmapi.vec3f()

def front():
     cmd2 = mmapi.StoredCommands()
     
     e.x = 0.0
     e.y = 0.0
     e.z = 1.0
     
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     
     u.x = 0.0
     u.y = 1.0
     u.z = 0.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     cmd2.CameraControl_RecenterView()
     remote.runCommand(cmd2)
     help_text.configure(text="Current View: Front")
     

def rear():
     cmd2 = mmapi.StoredCommands()
 
     e.x = 0.0
     e.y = 0.0
     e.z = -1.0
     
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     
     u.x = 0.0
     u.y = 1.0
     u.z = 0.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     cmd2.CameraControl_RecenterView()
     remote.runCommand(cmd2)
     help_text.configure(text="Current View: Rear")

def top():
     cmd2 = mmapi.StoredCommands()
     
     e.x = 0.0
     e.y = 1.0
     e.z = 0.0
     
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     
     u.x = 0.0
     u.y = 0.0
     u.z = -1.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     cmd2.CameraControl_RecenterView()
     remote.runCommand(cmd2)
     help_text.configure(text="Current View: Top")

def below():
     cmd2 = mmapi.StoredCommands()
     
     e.x = 0.0
     e.y = -1.0
     e.z = 0.0
     
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     
     u.x = 0.0
     u.y = 0.0
     u.z = 1.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     cmd2.CameraControl_RecenterView()
     remote.runCommand(cmd2)
     help_text.configure(text="Current View: Below")

def right():
     cmd2 = mmapi.StoredCommands()
     
     e.x = 1.0
     e.y = 0.0
     e.z = 0.0
     
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     
     u.x = 0.0
     u.y = 1.0
     u.z = 0.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     cmd2.CameraControl_RecenterView()
     remote.runCommand(cmd2)
     help_text.configure(text="Current View: Right")

def left():
     cmd2 = mmapi.StoredCommands()
     
     e.x = -1.0
     e.y = 0.0
     e.z = 0.0
     
     t.x = 0.0
     t.y = 0.0
     t.z = 0.0
     
     u.x = 0.0
     u.y = 1.0
     u.z = 0.0
     cmd2.CameraControl_SetSpecificView(e,t,u)
     cmd2.CameraControl_RecenterView()
     remote.runCommand(cmd2)
     help_text.configure(text="Current View: Left")


##########################     
#turntable stuff:
rec_time = DoubleVar()#target length of video
fps = DoubleVar()#video framerate
direction = IntVar()#turn direction
direction.set(-1)
save = IntVar()#save turntable to file
sample = IntVar()#sample selectVisible
stopTurn = IntVar()#to stop turntable
stopTurn.set(0)

def scrs(): #single screeshot saved to file with time stamp
    scs = mmapi.StoredCommands()
    scs.AppendSceneCommand_SaveScreenShot(os.path.expanduser("~/documents/meshmixer/screenshots/shot" + time.strftime("%d:%m:%y_%H:%M:%S") + ".jpg" ))
    remote.runCommand(scs)
    help_text.configure(text="See: Meshmixer/screenshots")


def hideP(): #sorts out and hides/shows pivots
    cur_objects = mm.list_objects(remote)
    i = len(cur_objects)
    if buttonHideP.config('text')[-1] == 'HidePiv': #hide pivots
        while (i > 0):
              mm.select_objects(remote, [cur_objects[0]])
              cmd2 = mmapi.StoredCommands()
              t_key = cmd2.AppendSceneCommand_GetObjectType(cur_objects[0])
              remote.runCommand(cmd2)
              obj_type = mmapi.any_result()
              mtype = cmd2.GetSceneCommandResult_GetObjectType(t_key,obj_type)
              remote.runCommand(cmd2)
              if obj_type.i == 3:
                  cmd2.AppendSceneCommand_SetHidden(cur_objects[0])
                  remote.runCommand(cmd2)
              cur_objects.pop(0)
              i -= 1
              buttonHideP.config(text='ShowPiv')
              help_text.configure(text="Pivots hidden")

    else: #show pivots
        while (i > 0):
              mm.select_objects(remote, [cur_objects[0]])
              cmd2 = mmapi.StoredCommands()
              t_key = cmd2.AppendSceneCommand_GetObjectType(cur_objects[0])
              remote.runCommand(cmd2)
              obj_type = mmapi.any_result()
              mtype = cmd2.GetSceneCommandResult_GetObjectType(t_key,obj_type)
              remote.runCommand(cmd2)
              if obj_type.i == 3:
                  cmd2.AppendSceneCommand_SetVisible(cur_objects[0])
                  remote.runCommand(cmd2)
              cur_objects.pop(0)
              i -= 1
              buttonHideP.config(text='HidePiv')
              help_text.configure(text="Pivots visible")

             

def ortho(): #switches perspective and orthogonal
     if buttonOrth.config('text')[-1] == 'Ortho':
        buttonOrth.config(text='Persp')
        cmd2 = mmapi.StoredCommands()
        cmd2.CameraControl_SetPerspectiveView()
        remote.runCommand(cmd2)       
        help_text.configure(text="Perspective view")

     else:
        buttonOrth.config(text='Ortho')       
        cmd2 = mmapi.StoredCommands()
        cmd2.CameraControl_SetOrthographicView()
        remote.runCommand(cmd2)
        help_text.configure(text="Orthographic view")


def turn(): #turntable
     help_text.configure(text="...Turning...")
     sa = save.get()
     if sa == 1: # prepares record mode: cleaning output directory
          path = os.path.expanduser("~/documents/meshmixer/turntable")
          fileList = os.listdir(path)
          for fileName in fileList:
               os.remove(path+"/"+fileName)
     sv = sample.get()
     if sv == 1: # prepares selectVisible sampling: ensures basic selection
          cmd2 = mmapi.StoredCommands()
          cmd2.CameraControl_SetOrthographicView()
          remote.runCommand(cmd2)
          buttonOrth.config(text='Ortho')
          cur_groups = mm.list_selected_groups(remote)
          if len(cur_groups) == 0:
              help_text.configure(text="This action needs a Selection")
              raise Exception("Selection missing")
     r = rec_time.get() # calls current values
     f = fps.get()
     d = direction.get()
     totalframes = r * f # calculate number of screenshots
     angleframe = (float(360)/totalframes)*d # calculates angle/screenshot
     i = 0
     while i < (totalframes):
          s  = stopTurn.get()
          if s == 1: # stop turntable
               stopTurn.set(0)
               sample.set(0)
               break
          cmd2 = mmapi.StoredCommands()
          cmd2.CameraControl_TurntableOrbit(angleframe, 0.0);
          if sa == 1: # saves screenshots serie
               cmd2.AppendSceneCommand_SaveScreenShot(os.path.expanduser("~/documents/meshmixer/turntable/image_%d_.png"%i))
          if sv == 1: # samples selectVisible
               cmd2.AppendSelectUtilityCommand( "selectVisible",1)
          remote.runCommand(cmd2)
          i += 1
          root.update()
     help_text.configure(text="Turntable completed")
     if sv == 1: # inverts sampled selection to be deleted or separated by user
          help_text.configure(text="Hidden selected")
          cmd2 = mmapi.StoredCommands()
          cmd2.AppendSelectUtilityCommand( "invert")
          remote.runCommand(cmd2)

               
         
def stop_turn():
     stopTurn.set(1)
     help_text.configure(text="Ready")
         

def toggle(): # switches turn direction
     if toggleDir.config('text')[-1] == '>>>':
        toggleDir.config(text='<<<')
        direction.set(1)
        help_text.configure(text="Direction : clockwise")

     else:
        toggleDir.config(text='>>>')       
        direction.set(-1)
        help_text.configure(text="Direction : anticlockwise")


############################   
#applet's GUI elements

help_text = Label(root,text = "Ready", font = ("Helvetica",14), wraplength = 200,  compound = CENTER)
help_text.grid (row = 0, columnspan = 3, padx = 2, pady = 3)

buttonFront = ttk.Button(root, text="Front", command = front)
buttonFront.grid (row = 2, column = 1, padx = 2, pady = 3)

buttonRear = ttk.Button(root, text="Rear", command = rear)
buttonRear.grid (row = 4, column = 1, padx = 2, pady = 3)

buttonTop = ttk.Button(root, text="Top", command = top)
buttonTop.grid (row = 1, column = 1, padx = 2, pady = 3)

buttonBelow = ttk.Button(root, text="Below", command = below)
buttonBelow.grid (row = 3, column = 1, padx = 2, pady = 3)

buttonRight = ttk.Button(root, text="Right", command = right)
buttonRight.grid (row = 2, column = 2, padx = 2, pady = 3)

buttonLeft = ttk.Button(root, text="Left", command = left)
buttonLeft.grid (row = 2, column = 0, padx = 2, pady = 3)


buttonShot = ttk.Button(root, text="Screensh.", command = scrs)
buttonShot.grid (row = 5, column = 0, padx = 2, pady = 3)

buttonHideP = ttk.Button(root, text="HidePiv", command = hideP)
buttonHideP.grid (row = 5, column = 1, padx = 2, pady = 3)

buttonOrth = ttk.Button(root, text="Persp", command = ortho)
buttonOrth.grid (row = 5, column = 2, padx = 2, pady = 3)


buttonTurn = ttk.Button(root, text="Turntable", command = turn)
buttonTurn.grid (row = 6, column = 0, padx = 2, pady = 3)

buttonStop = ttk.Button(root, text="Stop", command = stop_turn, compound = CENTER )
buttonStop.grid (row = 6, column = 1, padx = 2, pady = 3)

saveCheck = Checkbutton(root, text="save", variable=save)
saveCheck.grid (row = 6, column = 2, padx = 2, pady = 3)


slideTime = Scale(root, from_=1, to=60, orient=HORIZONTAL, variable = rec_time, label ="Time" )
slideTime.set(30)
slideTime.grid (row = 7, column=0, padx = 2, pady = 3)

toggleDir = ttk.Button(root, text=">>>", command=toggle)
toggleDir.grid (row = 7, column = 1, padx = 2, pady = 3)

slideFps = Scale(root, from_=2, to=60, orient=HORIZONTAL, variable = fps, label = "Fps" )
slideFps.set(30)
slideFps.grid (row = 7, column = 2, padx = 2, pady = 3)

visibCheck = Checkbutton(root, text="selectV", variable=sample)
visibCheck.grid (row = 8, column = 1, padx = 2, pady = 3)


mainloop()
I'm just a user as you are. Being no Autodesk employee: I do not know where this road will lead to, nor do I claim to've all stuff got right.

RMS

  • meshmixer founder
  • Administrator
  • Hero Member
  • *****
  • Posts: 1238
    • View Profile
    • gradientspace
Re: Scripting the cam
« Reply #4 on: April 13, 2016, 05:35:34 PM »
awesome!! That is exactly the kind of thing I added the API for =)
created meshmixer - now starting gradientspace - meshmixer consulting available http://www.gradientspace.com/consulting

Gonzae

  • Newbie
  • *
  • Posts: 2
    • View Profile
Scripting the cam
« Reply #5 on: April 24, 2016, 12:57:36 PM »
The reason I am writing to this old topic is a unaviability of the links reffering official scripting docs. Can someone give the proper ones please?
Publicaron un buen texto sobre remedios caseros contra la obesidad. De hecho, hay mas articulos sobre los remedios contra sobrepeso en el internet.

MagWeb

  • Administrator
  • Hero Member
  • *****
  • Posts: 1156
    • View Profile
Re: Scripting the cam
« Reply #6 on: April 24, 2016, 05:52:49 PM »
Docs are at:

....pathToYourMMApiInstallation.../distrib/documentation/python_html/index.html
I'm just a user as you are. Being no Autodesk employee: I do not know where this road will lead to, nor do I claim to've all stuff got right.

werks3d

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Scripting the cam
« Reply #7 on: November 17, 2016, 06:05:39 AM »
im a dumbs and on a mac, how do i use this script? thanks