myscene.py
that does the following:“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. # 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(<x>,<y>,<z>) # Location in world coordinates base.camera.setHpr(<heading>,<pitch>,<roll>) # Orientation in degrees # Loading a new ready-made model model = loader.loadModel(<model filename>) # 3D model to load from disk, e.g. "MyModel.egg" model.setScale(<scale factor>) # Uniform scaling of the model, e.g. 0.7 model.setPos(<x>,<y>,<z>) # Location in world coordinates model.setHpr(<heading>,<pitch>,<roll>) # Orientation in degrees # Adding the model to the Scene Graph under the root called 'render' model.reparentTo(render) # Start main loop run()
“Models/Textures/shuttle.avi”
. See also the section on Searching the Scene Graph in the Manual.# HINT - Finding a nodepath to a named sub-node nodepath = model.find("**/<name>") # HINT - Loading a new texture mytexture = loader.loadTexture(<filename>) # E.g. "MyTexture.png" # HINT - Setting a texture property model.setTexture(mytexture, 1) # Places the textur on a model
DirectObject
, you get a lot of cool functionality - including event handling! 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.update_camera
.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
# 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]))
# 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
Here is the Room class, only with the code to construct walls included:
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.
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.
# USEFUL ASSETS: # "Models/Textures/wall_tanned_clear.png" # "Models/Textures/floor_concrete.png" # "Models/Textures/ceiling_tanned.png" # "Models/Textures/ceiling_tanned_light.png"
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:# 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"
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). # 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)
create_lights
methods so that it creates a spotlight for each of the ceiling panels that have light fixtures in them.