User Tools

Site Tools


public:t-vien-11-1:lab2

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

public:t-vien-11-1:lab2 [2011/05/03 11:09] (current)
hannes created
Line 1: Line 1:
 +====== Lab 2 - Making Scenes in Panda 3D ======
 +
 +===== In-Class Excercises =====
 +
 +==== Before You Start ====
 +
 +  * Download and unzip the [[http://www.ru.is/kennarar/hannes/classes/ve2010/Lab2Assets.zip|Lab 2 Asset File]] into your working directory (where you will be writing and running your python script).
 +
 +==== Making a Virtual Room in Panda 3D ====
 +
 +{{public:t-vien-07-1:ve-lab2-screenshot.jpg|}}
 +
 +  - **Loading and Posing an Object:**\\ Create a new python script called ''myscene.py'' that does the following:
 +    - Moves the **camera** to the location (-0.5, -3.5, 0.5), changes its heading by -45 degrees.
 +    - Loads and displays the **model** ''"Models/television.egg"'', placing it at location (2,-2,0).  Scale the model down to 15% and rotate it such that you can see the front of the television screen. <code python>
 +# HINT - A basic program showing a scene with one object from a fixed camera 
 +# NOTE - Numeric values are arbitrary in this example (you need to change them for your program)
 +import direct.directbase.DirectStart
 +# Disabling user controlled camera
 +base.disableMouse()
 +# Placing the camera in world space
 +base.camera.setPos(1,1,1) # Location (x, y, z)
 +base.camera.setHpr(45,45,45) # Orientation in degrees (Heading, Pitch, Roll)
 +# Loading a new ready-made model
 +model = loader.loadModel("MyModel.egg")  # Model filename
 +model.setScale(0.5)  # Uniform scaling of the model
 +model.setPos(1,1,1)  # Location (x, y, z)
 +model.setHpr(45,45,45) # Orientation in degrees (Heading, Pitch, Roll)
 +# Adding the model to the Scene Graph under the root
 +model.reparentTo(render)
 +# Start main loop
 +run()
 +</code>
 +  - **Finding a Node and Applying Texture:**\\ Add a moving image to the television screen by first finding the **NodePath** object representing the 'screen' sub-tree of the television model and then giving it (and only it) the texture ''"Models/Textures/shuttle.avi"''.  See also the section on [[http://www.panda3d.org/wiki/index.php/Searching_the_Scene_Graph|Searching the Scene Graph in the Manual]].<code python>
 +# HINT - Finding a nodepath to a named sub-node
 +nodepath = model.find("**/blah")
 +# HINT - Loading a new texture
 +mytexture = loader.loadTexture("MyTexture.png")
 +# HINT - Setting a texture property
 +model.setTexture(mytexture, 1) 
 +</code>
 +  - **Creating a World Class and Simple Navigation:**\\ Now you will place your scene inside a new Python class.  One reason to do this is that your code can be more modular, but another reason is that by making your class inherit methods and attributes from ''DirectObject'', you get a lot of cool functionality - including event handling!  
 +    - Create a new class called **World**, derived from ''DirectObject'', and move the creation of the television (but not your camera) into its constructor and then instantiate this world before calling run() in your main program.  Test this before continuing.
 +    - The example below shows how the constructor can set up event handlers for specific key-strokes (in this case the key 's').  You can check the manual pages for [[http://www.panda3d.org/wiki/index.php/Event_Handlers|EventHandlers]] to understand how this works.  This code makes you move the camera backwards as you hold down the 's' key.  Add code for moving the camera forward with the 'w' key and for rotating the camera left and right with the 'a' and 'd' keys.  You should be able to do this by accepting more events, storing more keys and adding more kinds of updates inside ''update_camera''.<code python>
 +from direct.showbase.DirectObject import DirectObject  
 +class World(DirectObject):
 +   """ An interactive scene """
 +
 +    def __init__(self):
 +        """ The constructor, which builds the scene and sets up user control """
 +
 +        # Code for building the scene could go here...
 +
 +        # Set up movement keys
 +        self.keystate = {'back':0} # Just a member variable to store the state of each key
 +        self.accept('s', self.set_keystate, ['back',1])  # Handler for 's' press
 +        self.accept('s-up', self.set_keystate, ['back',0]) # Handler for 's' release
 +        self.lasttime = 0
 +        taskMgr.add(self.update_camera, "camerathread") # Start a new thread which then will loop
 +                                                        # forever to update the camera position
 +        
 +    def set_keystate(self, key, state):
 +        """ Set a stored state (either 0 or 1) for a specified key ('back',...)"""
 +        self.keystate[key] = state # Updates the member variable holding the states of the keys
 +        
 +    def update_camera(self, task):
 +        """ 
 +        Update camera position and/or rotation for all active key states.
 +        """
 +        elapsed = task.time - self.lasttime
 +        if self.keystate['back'] is 1:   # Checks the member variable for the current state of a given key
 +            base.camera.setPos(camera,0,-0.7*elapsed,0)  # "setPos" with 4 parameters makes the translation 
 +                                                         # relative to the first parameter
 +        self.lasttime = task.time
 +        return task.cont
 +</code><code python>
 +# HINT - This might help you use a simple loop to set up the keys without having to repeat the
 +#        'accept' command 8 times!
 +key_map = (('s',['back',1]),('s-up',['back',0]),
 +           ('w',['forward',1]),('w-up',['forward',0]),
 +           ('a',['left',1]),('a-up',['left',0]),
 +           ('d',['right',1]),('d-up',['right',0]))
 +</code>
 +  - **Making a Flexible Room Generator:**\\ Add a new class called **Room** (see below) which you'll use to generate a setting like the one shown in the screenshot above.  The **Room**'s constructor expects three data lists that define the shape of the room.  The data lists describe the placement of 1x1 panels for walls, floor and ceiling.  All list items are tuples that contain the panel x and y location, but the third value in the tuple (if there is one) depends on the type of panel being created (see below).  To create a tiny room with a light in the ceiling, you would instantiate the Room class like this:<code python>
 +# Building a very small room using the Room class
 +room_pathnode = render.attachNewNode("Room") # Create an empty parent node for the Room
 +room = Room(room_pathnode,
 +            [(0,0,0),(1,0,-90),(1,-1,-180),(0,-1,-270)],  # Walls
 +            [(0,-1)],                                     # Floor
 +            [(0,0,True)])                                 # Ceiling with light
 +</code>Here is the **Room** class, only with the code to construct walls included:<code python>
 +class Room:    
 +    def __init__(self, parent_pathnode, wall_data, floor_data, ceiling_data):
 +        """
 +        Generate a room with walls, floor and a ceiling from lists of 1x1 panel
 +        locations and orientations.
 +            'parent_pathnode' = Pathnode immediately above this one in the scene graph
 +            'wall_data' = List of wall panel touples: (x loc, y loc, angle)
 +            'floor_data' = List of floor panel touples: (x loc, y loc)
 +            'ceiling_data' = List of ceiling panel touples: (x loc, y loc, has light?)
 +        """
 +        self.parent = parent_pathnode
 +        self.wall_data = wall_data
 +        self.floor_data = floor_data
 +        self.ceiling_data = ceiling_data
 +        self.panel = loader.loadModel("Model/grid.egg") # This is just a rectangular polygon mesh
 +        self.create_floor()
 +        self.create_ceiling()
 +        self.create_walls()
 +        self.create_lights()
 +    
 +    def create_walls(self):
 +        """ Create the walls according to Room data, with panel textures """
 +        wall_clear    = loader.loadTexture("Models/Textures/wall_tanned_clear.png")     
 +        for wallpanel_data in self.wall_data:
 +            wallpanel = self.parent.attachNewNode("wall panel") # Create a new node
 +            self.panel.instanceTo(wallpanel)         # Copy the geometry into place
 +            wallpanel.setPos(wallpanel_data[0],wallpanel_data[1],0)
 +            wallpanel.setHpr(wallpanel_data[2],0,0)
 +            wallpanel.setTexture(wall_clear)
 +                   
 +    def create_floor(self):
 +        """ Create the floor according to Room data """
 +        # Fill this in
 +                    
 +    def create_ceiling(self):
 +        """ Create the ceiling, with ceiling light textures, according to Room data """ 
 +        # Fill this in
 +        
 +    def create_lights(self):
 +        """ Create both the ambient light and spotlights for every ceiling light """
 +        # Leave this for a later problem.
 +
 +</code>Fill in the code for **''create_floor''** and **''create_ceiling''** (see asset names below) and test with the data set for the tiny room above.  You should instantiate the Room from within the constructor of the **World** class.<code python>
 +# USEFUL ASSETS:
 +# "Models/Textures/wall_tanned_clear.png" 
 +# "Models/Textures/floor_concrete.png"
 +# "Models/Textures/ceiling_tanned.png"
 +# "Models/Textures/ceiling_tanned_light.png"
 +</code>
 +  - **Making Randomized Panels and a Larger Room:**\\ Modify the **''create_wall''** method to pick a random texture for each panel for a greater variety (use the various wall panel assets below).  Construct a larger room now, that resembles the room in the screenshot above, by passing the right data into the Room's constructor.  The following blueprint will give you all the information you need:\\ {{public:t-vien-07-1:scene_gridview.jpg|}} \\ <code python>
 +# MORE USEFUL ASSETS:
 +# "Models/Textures/wall_tanned_clear.png" 
 +# "Models/Textures/wall_tanned_door.png"
 +# "Models/Textures/wall_tanned_window.png"
 +# "Models/Textures/wall_tanned_vent.png" 
 +</code>
 +  - **Adding Lights:**\\ Fill in the code for the **''create_lights''** method.  Create one ambient light with the color (0.4,0.4,0.4,1).  Create one spotlight with the color (0.6,0.6,1.0,1) and attenuation (0,0,0), facing down from the ceiling (starting at height 1.25). <code python>
 +# HINT - Creating lights
 +# Set up the global lighting for general illumination
 +ambient_source = AmbientLight('ambient')
 +ambient_source.setColor(Vec4(1,1,1,1))
 +ambientnp = root.attachNewNode(ambient_source)
 +root.setLight(ambientnp)
 +# Set up a spotlight for localized illumination
 +lens = PerspectiveLens()
 +lens.setNearFar(0.1, 2.0)
 +spot_source = Spotlight('spotlight')
 +spot_source.setColor(Vec4(1,1,1,1))
 +## spot_source.showFrustum() # Uncomment for great debug information
 +spot_source.setLens(lens)
 +spotnp = root.attachNewNode(spot_source)
 +spotnp.setPos(Vec3(1,1,1))
 +spotnp.setHpr(0,0,0)
 +root.setLight(spotnp)
 +</code>
 +  - **Attaching Lights to Fixtures:**\\ Modify the spotlight creation in the **''create_lights''** methods so that it creates a spotlight for each of the ceiling panels that have light fixtures in them.
 +
 +
 +
  
/var/www/ailab/WWW/wiki/data/pages/public/t-vien-11-1/lab2.txt ยท Last modified: 2011/05/03 11:09 by hannes