Fly through

Normal 3D views

You can do view manipulation manually on "ViewAttributes" objects, but, alternatively, you can use the built in function EvalCubicSpline to smoothly interpolate many view control points. This section shows how to use the interpolation functions to interpolate normal View3DAttributes objects. If you want to actually move the camera to locations of your choosing then see the next section.

Here's how:

  • Find views that you like interactively in the GUI.
    • Have the CLI running and enter:
 >>> v = GetView3D()
 >>> v
 # gives the current view
 viewNormal = (0, 0, 1)
 focus = (0, 0, 0)
 viewUp = (0, 1, 0)
 viewAngle = 30
 parallelScale = 0.5
 nearPlane = -0.5
 farPlane = 0.5
 imagePan = (0, 0)
 imageZoom = 1
 perspective = 1
 eyeAngle = 2
 centerOfRotationSet = 0
 centerOfRotation = (0, 0, 0)
  • You must have at least four views because cubic functions require at least 4 coefficients. (The one below has six.)
  • Then employ a function like fly() to animat the view:
 def fly():
    # Do a pseudocolor plot of u.
    OpenDatabase('../../data/globe.silo')
    AddPlot('Pseudocolor', 'u')
    DrawPlots()
    
    # Create the control points for the views.
    c0 = View3DAttributes()
    c0.viewNormal = (0, 0, 1)
    c0.focus = (0, 0, 0)
    c0.viewUp = (0, 1, 0)
    c0.viewAngle = 30
    c0.parallelScale = 17.3205
    c0.nearPlane = 17.3205
    c0.farPlane = 81.9615
    c0.perspective = 1
    
    c1 = View3DAttributes()
    c1.viewNormal = (-0.499159, 0.475135, 0.724629)
    c1.focus = (0, 0, 0)
    c1.viewUp = (0.196284, 0.876524, -0.439521)
    c1.viewAngle = 30
    c1.parallelScale = 14.0932
    c1.nearPlane = 15.276
    c1.farPlane = 69.917
    c1.perspective = 1
    
    c2 = View3DAttributes()
    c2.viewNormal = (-0.522881, 0.831168, -0.189092)
    c2.focus = (0, 0, 0)
    c2.viewUp = (0.783763, 0.556011, 0.27671)
    c2.viewAngle = 30
    c2.parallelScale = 11.3107
    c2.nearPlane = 14.8914
    c2.farPlane = 59.5324
    c2.perspective = 1
    
    c3 = View3DAttributes()
    c3.viewNormal = (-0.438771, 0.523661, -0.730246)
    c3.focus = (0, 0, 0)
    c3.viewUp = (-0.0199911, 0.80676, 0.590541)
    c3.viewAngle = 30
    c3.parallelScale = 8.28257
    c3.nearPlane = 3.5905
    c3.farPlane = 48.2315
    c3.perspective = 1
    
    c4 = View3DAttributes()
    c4.viewNormal = (0.286142, -0.342802, -0.894768)
    c4.focus = (0, 0, 0)
    c4.viewUp = (-0.0382056, 0.928989, -0.36813)
    c4.viewAngle = 30
    c4.parallelScale = 10.4152
    c4.nearPlane = 1.5495
    c4.farPlane = 56.1905
    c4.perspective = 1
    
    c5 = View3DAttributes()
    c5.viewNormal = (0.974296, -0.223599, -0.0274086)
    c5.focus = (0, 0, 0)
    c5.viewUp = (0.222245, 0.97394, -0.0452541)
    c5.viewAngle = 30
    c5.parallelScale = 1.1052
    c5.nearPlane = 24.1248
    c5.farPlane = 58.7658
    c5.perspective = 1
    
    c6 = c0
    
    # Create a tuple of camera values and x values. The x values are weights
    # that help to determine where in [0,1] the control points occur.
    cpts = (c0, c1, c2, c3, c4, c5, c6)
    x=[]
    for i in range(7):
        x = x + [float(i) / float(6.)]
    
    # Animate the camera. Note that we use the new built-in EvalCubicSpline
    # function which takes a t value from [0,1] a tuple of t values and a tuple
    # of control points. In this case, the control points are View3DAttributes
    # objects that we are using to animate the camera but they can be any object
    # that supports +, * operators.
    nsteps = 100
    for i in range(nsteps):
        t = float(i) / float(nsteps - 1)
        c = EvalCubicSpline(t, x, cpts)
        c.nearPlane = -34.461
        c.farPlane = 34.461
        SetView3D(c)

Setting the camera position

With normal 3D views, VisIt takes care of setting the camera position based on some distance and orientation from the plots being viewed. You can override this behavior by turning on Flythrough interaction in the Options->Interactors window. When the flythrough interaction method is used, you must provide the camera location, up vector, and view direction that will be used.

Here is a script that shows how to use the EvalCubicBezier function to build up a smooth camera path, consisting of: camera position, camera up vector, and camera direction (or focus). You can model your camera, thinking of these parameters and then set them into the View3DAttributes object such that VisIt will use them for the view.

import math

#
# Vector functions
#
def vec_magnitude(vec):
    return math.sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])
 
def vec_normalize(vec):
    R = vec_magnitude(vec)
    return (vec[0] / R, vec[1] / R, vec[2] / R)
 
def vec_add(a, b):
    return (a[0] + b[0], a[1] + b[1], a[2] + b[2])
 
def vec_mult_float(vec, f):
    return (vec[0] * f, vec[1] * f, vec[2] * f)
 
def vec_cross(a, b):
    return (a[1]*b[2] - a[2]*b[1],
            a[2]*b[0] - a[0]*b[2],
            a[0]*b[1] - a[1]*b[0])

def setup():
    OpenDatabase("globe.silo")
    AddPlot("Pseudocolor", "u")
    DrawPlots()

    ia = GetInteractorAttributes()
    ia.navigationMode = ia.Flythrough
    SetInteractorAttributes(ia)

def animate(nts):
    # Here is where the control points for the camera position and up vector are determined.
    positions = ((0,0,30), (0,0,15),         (-8,0,10),       (-11,0,0),  (-7.7,0,-7.77),      (0,0,-11), (7.77, 0, -7.77), (11,0,0))
    up =        ((0,1,0),  (-0.2, 0.7, 0.2), (-.707,0,0.707), (-1, 0, 0), (-0.707, 0, -0.707), (0,0,-1),  (0.707, 0, -0.707), (1,0,0))

    x=[]
    px = []
    py = []
    pz = []
    ux = []
    uy = []
    uz = []
    for i in range(len(positions)):
        x = x + [float(i) / float(len(positions)-1)]
        px = px + [positions[i][0]]
        py = py + [positions[i][1]]
        pz = pz + [positions[i][2]]
        ux = ux + [up[i][0]]
        uy = uy + [up[i][1]]
        uz = uz + [up[i][2]]

    smooth_positions = []
    for i in xrange(nts+1):
        t = float(i) / float(nts)
        print t
        sx = EvalCubicSpline(t, x, px)
        sy = EvalCubicSpline(t, x, py)
        sz = EvalCubicSpline(t, x, pz)
        smooth_positions = smooth_positions + [(sx,sy,sz)]

    # Let's write the positions of these paths to files that we can plot in VisIt
    f1 = open("pos.lines", "wt")
    f2 = open("up.lines", "wt")
    f3 = open("right.lines", "wt")

    v = GetView3D()
    for i in xrange(nts):
        t = float(i) / float(nts)
        # Make the camera position be the values that we already made.
        camera_position = smooth_positions[i]

        # Make the camera view along the path that we're following.
        # We could be looking at anything, however.
        dx = smooth_positions[i+1][0] - smooth_positions[i][0]
        dy = smooth_positions[i+1][1] - smooth_positions[i][1]
        dz = smooth_positions[i+1][2] - smooth_positions[i][2]
        camera_direction = vec_normalize((dx, dy, dz))

        # Make a smooth up vector
        sux = EvalCubicSpline(t, x, ux)
        suy = EvalCubicSpline(t, x, uy)
        suz = EvalCubicSpline(t, x, uz)
        camera_up = vec_normalize((sux,suy,suz))

        # Now, map the camera into VisIt's flythrough view
        v.viewNormal = camera_direction
        v.focus = camera_position
        v.viewUp = camera_up
        v.parallelScale = 1
        v.nearPlane = -50
        v.farPlane = 50
        SetView3D(v)
        SaveWindow()

        # Write out the position, etc for debugging.
        f1.write("%g, %g, %g\n" % camera_position)
        f2.write("%g, %g, %g\n" % (camera_position[0] + camera_up[0], camera_position[1] + camera_up[1], camera_position[2] + camera_up[2]))
        right = vec_normalize(vec_cross(camera_direction, camera_up))
        f3.write("%g, %g, %g\n" % (camera_position[0] + right[0], camera_position[1] + right[1], camera_position[2] + right[2]))

    f1.close()
    f2.close()
    f3.close()

def main():
    setup()
    animate(50)

main()
Show the camera path, up vector, and right vector