Beckman Institute            University of Illinois at Urbana-Champaign             
University of Illinois at Urbana-Champaign

Syzygy Documentation: Scene Graph Tutorial

Integrated Systems Lab
12/21/2006

Documentation Table of Contents

Introduction

This tutorial will walk you through working with the Syzygy scene graph from the Python prompt and introduce you to the concept of peer-to-peer reality. To follow this tutorial, you'll need to either have compiled the szg library and the Syzygy Python bindings or have installed a Syzygy SDK as appropriate for your system.

This tutorial is complementary to the chapter describing the C++ scene graph API.

There are several scene graph examples written in Python.

  • particle-shape: A particle system using some of the built-in shapes.
  • lorenz: A visualization of the lorenz attractor.
  • cosmos: Translation of the cosmos C++ demo into Python.
  • simpleviz: Shows how to manipulate a collection of objects using a grasping tool. Also demonstrates a custom standalone mode simulator.

Myriad Scene Graph: Important Syzygy Database Parameters

The graphics database requires a few Syzygy parameters to be set for proper operation. For every computer upon which you want to run a display, you should have

    my_computer_name SZG_RENDER texture_path /the/textures/here
    my_computer_name SZG_RENDER text_path /the/text/bitmaps/here

Furthermore, it will be easier to load and save snapshots of graphics peers if you set the SZG_PEER/path on each computer upon which you run a graphics peer. Files will be automatically loaded and saved to this directory.

    my_computer_name SZG_PEER path /the/peer/files/go/here

A White Sphere

  from PySZG import *
  import time
  # We need to create a camera.
  c = arPerspectiveCamera()
  # The bounds of the near viewing frustum.
  # (-x,+x,-y,+y)
  c.setSides(-0.1,0.1,-0.1,0.1)
  # The near and far clipping planes. The ratio between
  # these should not be too large.
  c.setNearFar(0.1,100)
  # The position of the camera in space.
  c.setPosition(0,5,0)
  # The place towards which the camera looks.
  c.setTarget(0,0,0)
  # The up direction for the camera.
  c.setUp(0,1,0)
  # Our scene graph is stored in an arGraphicsDatabase.
  g = arGraphicsDatabase()
  # We will attach new nodes to the database's root.
  r = g.getRoot()
  # We need a light.
  light = arLight()
  # Each light must have a unique ID, 0-7.
  light.lightID = 0
  # If the last coordinate is 0, then this is a directional light.
  light.position = arVector4(0,0,1,0)
  # The light's color.
  light.diffuse = arVector3(1,1,1)
  # This light must be stored in a scene graph node.
  # The node is a child of the root (see above).
  l = r.new("light")
  l.setLight(light)
  # We create a material node (stores a color).
  # Since we don't specify a color, this is just the default (white).
  m = r.new("material")
  # The sphere has 20 longitudinal and latitudinal divisions. 20x20x2=800 triangles.
  s = arSphereMesh(20)
  # Attach our sphere as a child of the material node.
  s.attachMesh(m)
  # Make a window that can display our graphics.
  e = ezview()
  # To draw, specify an arGraphicsDatabase and a camera.
  e.draw(g,c)
  # Wait for 5 seconds before quitting.
  time.sleep(5)

A Red Sphere

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1,0.1,-0.1,0.1)
  c.setNearFar(0.1,100)
  c.setPosition(0,5,0)
  c.setTarget(0,0,0)
  c.setUp(0,1,0)
  g = arGraphicsDatabase()
  r = g.getRoot()
  light = arLight()
  light.lightID = 0
  light.position = arVector4(0,0,1,0)
  light.diffuse = arVector3(1,1,1)
  l = r.new("light")
  l.setLight(light)
  m = r.new("material")
  ###################
  # Make a color.
  ###################
  mat = arMaterial()
  ###################
  # It is red.
  ###################
  mat.diffuse = arVector3(1,0,0)
  #############################################################
  # Store it in the material node. The sphere will now be red.
  #############################################################
  m.set(mat)
  s = arSphereMesh(20)
  s.attachMesh(m)
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Translating the Sphere

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1,0.1,-0.1,0.1)
  c.setNearFar(0.1,100)
  c.setPosition(0,5,0)
  c.setTarget(0,0,0)
  c.setUp(0,1,0)
  c.setPosition(0,0,5)
  g = arGraphicsDatabase()
  r = g.getRoot()
  light = arLight()
  light.lightID = 0
  light.position = arVector4(0,0,1,0)
  light.diffuse = arVector3(1,1,1)
  l = r.new("light")
  l.setLight(light)
  m = r.new("material")
  mat = arMaterial()
  mat.diffuse = arVector3(1,0,0)
  m.set(mat)
  t = m.new("transform")
  ###############################################################################
  # ar_TM is an abbreviation for ar_TranslationMatrix. This creates an arMatrix4
  # that encodes the given translation (up 3 units).
  ###############################################################################
  t.set(ar_TM(0,3,0))
  s = arSphereMesh(20)
  #################################################################################
  # The sphere attaches to the transform node. This is necessary for the transform
  # to move it.
  #################################################################################
  s.attachMesh(t)
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Making the Sphere Bigger

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1,0.1,-0.1,0.1)
  c.setNearFar(0.1,100)
  c.setPosition(0,5,0)
  c.setTarget(0,0,0)
  c.setUp(0,1,0)
  g = arGraphicsDatabase()
  r = g.getRoot()
  light = arLight()
  light.lightID = 0
  light.position = arVector4(0,0,1,0)
  light.diffuse = arVector3(1,1,1)
  l = r.new("light")
  l.setLight(light)
  m = r.new("material")
  mat = arMaterial()
  mat.diffuse = arVector3(1,0,0)
  m.set(mat)
  t = m.new("transform")
  #############################################################################
  # ar_SM is an abbreviation for ar_scaleMatrix. This returns an arMatrix4 that
  # encodes the specified scaling (expand by a factor of 3, uniformly).
  #############################################################################
  t.set(ar_TM(0,3,0)*ar_SM(3,3,3))
  s = arSphereMesh(20)
  s.attachMesh(t)
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Using Textures for Objects

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  #############################################################
  # Must tell the software where the texture files are stored.
  #############################################################
  g.setTexturePath("/Users/schaeffr/Texture")
  r = g.getRoot()
  light = arLight()
  light.lightID = 0
  light.position = arVector4(0,0,1,0)
  light.diffuse = arVector3(1,1,1)
  l = r.new("light")
  l.set(light)
  t = r.new("transform")
  ####################################################################################
  # ar_RM is an abbreviation for ar_rotationMatrix. This returns an arMatrix4 that
  # encodes the specified rotation (in this case, a rotation by 20 degrees around the
  # y axis).
  ####################################################################################
  t.set(ar_TM(0,2,0)*ar_RM('y', ar_convertToRad(20))*ar_SM(3,3,3))
  ###################################################################################
  # Create a texture node. For the cube to use the stored image, it must be attached
  # below.
  ###################################################################################
  txt = t.new("texture")
  ##################
  # Load an image.
  ##################
  txt.set("WallTexture1.ppm")
  cube = arCubeMesh()
  cube.attachMesh(txt)
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Displaying .obj Files

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  dgSetGraphicsDatabase(g)
  r = g.getRoot()
  light = arLight()
  light.lightID = 0
  light.position = arVector4(0,0,1,0)
  light.diffuse = arVector3(1,1,1)
  l = r.new("light")
  l.set(light)
  t = r.new("transform","transform_node")
  t.set(ar_TM(1,1,0)*ar_RM('y', ar_convertToRad(20))*ar_SM(3,3,3))
  #########################################
  # Create an object to load the geometry.
  #########################################
  o = arOBJ()
  o.readOBJ("/Users/schaeffr/Data/OBJ/al.obj")
  #########################################################################
  # Make the model fit inside a sphere of radius 1 centered at the origin.
  #########################################################################
  o.normalizeModelSize()
  ###########################################
  # Attach the mesh nodes to the database.
  ###########################################
  o.attachMesh("al", "transform_node")
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Editing .obj Files

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  dgSetGraphicsDatabase(g)
  r = g.getRoot()
  light = arLight()
  light.lightID = 0
  light.position = arVector4(0,0,1,0)
  light.diffuse = arVector3(1,1,1)
  l = r.new("light")
  l.set(light)
  t = r.new("transform","transform_node")
  t.set(ar_TM(1,1,0)*ar_RM('y', ar_convertToRad(20))*ar_SM(3,3,3))
  o = arOBJ()
  o.readOBJ("/Users/schaeffr/Data/OBJ/al.obj")
  o.normalizeModelSize()
  o.attachMesh("al", "transform_node")
  ########################################################################
  # Find a material node inside the model. These have the standard names
  # al.default.colors1 ... al.default.colors4.
  ########################################################################
  m = g.find("al.default.colors3")
  ###########################################################
  # Retrieve the stored material, change the diffuse color.
  ###########################################################
  mat = m.get()
  mat.diffuse = arVector3(1,0,0)
  ###################################################
  # Return the edited material to the material node.
  ###################################################
  m.set(mat)
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Geometry: Points

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  r = g.getRoot()
  #################################################################################
  # Create a graphics state node. This one sets the point size (for drawable nodes
  # below it) to 20.0 pixels.
  #################################################################################
  state = r.new("graphics state")
  state.set(("point_size",20.0))
  ###################################################
  # Make a points node as a child of the state node.
  ###################################################
  p = state.new("points")
  ####################################################
  # Make a colors node as a child of the points node.
  ####################################################
  clr = p.new("color4")
  ####################################################################################
  # Make a drawable node as a child of the colors node. This is where the points
  # will actually be drawn. They will have size 20 since this node is a descendant of
  # the graphics state node.
  ####################################################################################
  d = clr.new("drawable")
  ###########################################################
  # Store the coordinates of the points in the points node.
  ###########################################################
  p.set([arVector3(0,0,0),
         arVector3(1,0,0),
         arVector3(1,1,0),
         arVector3(0,1,0)])
  #############################################
  # Store the color values in the colors node.
  #############################################
  clr.set([arVector4(1,0,0,1),
  	arVector4(0,1,0,1),
  	arVector4(0,0,1,1),
  	arVector4(1,1,1,1)])
  ###################################################################################
  # Draw 4 points. The coordinates in the ancestor points node and the colors in the
  # ancestor colors3 node are used in order.
  ###################################################################################
  d.set(("points", 4))
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Geometry: Lines

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  r = g.getRoot()
  state = r.new("graphics state")
  #################################################################
  # The graphics state here is line width instead of point size.
  #################################################################
  state.set(("line_width",10.0))
  p = state.new("points")
  clr = p.new("color4")
  ################################################################################
  # Create an index node. This controls which points the drawable node will use.
  # Instead of using them in order, you can skip through the list.
  ################################################################################
  i = clr.new("index")
  d = i.new("drawable")
  p.set([arVector3(0,0,0),
         arVector3(1,0,0),
         arVector3(1,1,0),
         arVector3(0,1,0)])
  #################################################################################
  # There is a color for each line endpoint. These are used in order. There are 12
  # colors and 6 line segments.
  #################################################################################
  clr.set([arVector4(1,0,0,1),
          arVector4(1,0,0,1),
  	arVector4(0,1,0,1),
          arVector4(0,1,0,1),
  	arVector4(0,0,1,1),
          arVector4(0,0,1,1),
  	arVector4(1,1,1,1),
          arVector4(1,1,1,1),
          arVector4(1,1,0,1),
          arVector4(1,1,0,1),
          arVector4(1,1,0,1),
          arVector4(1,1,0,1)])
  ###################################################################
  # The indices are used in order, but skip through the points list.
  ###################################################################
  i.set([0,1, 1,2, 2,3, 3,0, 0,2, 1,3])
  d.set(("lines", 6))
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Geometry: Triangle

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  r = g.getRoot()
  state = r.new("graphics state")
  ##################################################################################
  # We can use a graphics state node to turn off lighting in all descendant nodes.
  ##################################################################################
  state.set(("lighting", "false"))
  m = state.new("material")
  ##################################################################################
  # The triangle will be green. This is in contrast to using a colors node to set
  # the color of each vertex.
  ##################################################################################
  mat = arMaterial()
  mat.diffuse = arVector3(0,1,0)
  m.set(mat)
  p = m.new("points")
  i = p.new("index")
  n = i.new("normal3")
  d = n.new("drawable")
  p.set([arVector3(0,0,0),
         arVector3(3,0,0),
         arVector3(3,3,0),
         arVector3(0,3,0)])
  ###############################################################################
  # Each triangle vertex needs a normal. There will be 3 vertices, so 3 normals.
  ###############################################################################
  n.set([arVector3(0,0,1),
         arVector3(0,0,1),
         arVector3(0,0,1)])
  ################################################
  # Choose the vertices to be visited, in order.
  ################################################
  i.set([0,1,3])
  d.set(("triangles", 1))
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Geometry: Textured Square

  from PySZG import *
  import time
  c = arPerspectiveCamera()
  c.setSides(-0.1, 0.1, -0.1, 0.1)
  c.setNearFar(0.1, 100)
  c.setPosition(0, 0, 5)
  c.setTarget(0, 0, 0)
  c.setUp(0, 1, 0)
  g = arGraphicsDatabase()
  r = g.getRoot()
  state = r.new("graphics state")
  state.set(("lighting", "false"))
  m = state.new("material")
  mat = arMaterial()
  mat.diffuse = arVector3(0.8,1,0.8)
  m.set(mat)
  texture = m.new("texture")
  texture.set("WallTexture2.ppm")
  p = texture.new("points")
  i = p.new("index")
  n = i.new("normal3")
  ##########################################
  # The square needs texture coordinates.
  ##########################################
  t2 = n.new("tex2")
  d = t2.new("drawable")
  p.set([arVector3(0,0,0),
         arVector3(3,0,0),
         arVector3(3,3,0),
         arVector3(0,3,0)])
  n.set([arVector3(0,0,1),
         arVector3(0,0,1),
         arVector3(0,0,1),
         arVector3(0,0,1)])
  ##############################################################
  # Specify the texture coordinates. These are used in order.
  ##############################################################
  t2.set([arVector2(0,0),
          arVector2(1,0),
          arVector2(1,1),
          arVector2(0,1)])
  i.set([0,1,2,3])
  # This is a square.
  d.set(("quads", 1))
  e = ezview()
  e.draw(g,c)
  time.sleep(5)

Scene Graph: Saving and Reloading Your Work

You should be certain that your Syzygy parameters are set as in this section, especially the SZG_PEER/path. We assume you have worked through the section on loading objects.

First, save your database. You are writing it in binary format (which is faster to load). Note the file type: .szg.

    peer.writeDatabase("test-al.szg")

A file "test-al.szg" should now be in the directory given by SZG_PEER/path on the computer you are running the Python prompt. Next, quit the Python prompt and exit from the reality peer workspace that was displaying your work.

You will now get back to the point where you were before. Restart the workspace, as before ("szg-rp work1"). Enter a new Python prompt.

To load your previously saved scene:

    peer.readDatabase("test-al.szg")

Again, if this suceeds, it will output "1". Note that this does not look exactly the same as it did before. The difference is the translation of the peer "target" within the workspace "work1". To restore:


[Schedule] [Labs] [Beckman Meeting Rooms] [Equipment] [Projects] [CUBE Projects] [Syzygy] [VSS] [People] [Events] [Publications]