====== Lab 3 - Camera, Text, Sound and Outside Environment====== ===== In-Class Exercises ===== ==== Before You Start ==== * Download and unzip the [[http://www.ru.is/kennarar/hannes/classes/ve2009/Lab3Assets.zip|Lab 3 Asset File]] into your working directory (same directory you used last week) ==== Continuing with your Virtual Room ==== * You should continue working where you left off last week on the [[Lab 2 Materials|Making a Virtual Room in Panda 3D]] exercise. - **Camera Lens:**\\ Adjust your camera's //field of view// (FOV) and //near clipping distance// so that you see a bit more of the room as you move around in it. A field of view of **50** seems pretty good and a near clipping plane of **0.01**. base.camLens.setFov() base.camLens.setNear() base.camLens.setFar() - **Onscreen Text:**\\ Add a dynamic text label on your heads-up-display (HUD) simply by creating an **OnscreenText** object like this: from direct.gui.OnscreenText import OnscreenText textobject = OnscreenText(pos = (0, -0.9), fg = (1,1,1,1), bg = (0.3, 0.3, 0.3, 0.5), align = TextNode.ACenter, scale = 0.07, mayChange = True) You can look up the [[http://www.ru.is/kennarar/hannes/useful/PandaManual/OnscreenText.1.html|various creation parameters]] for **OnscreenText**. And then any time you want to display some text, just set the ''text'' property for this object. The following code sets the text to the current camera location values using a [[http://www.ibiblio.org/obp/pyBiblio/tips/wilson/stringFormat.php|python formatted string]] textobject.setText("Your location is (%2.2f,%2.2f,%2.2f)" % (base.camera.getX(), base.camera.getY(), base.camera.getZ())) Make your label show an updated camera position as you move around. - **Localized Sound:**\\ Add some sound to the television broadcast which grows louder as you approach the television set and softer as you move away from it. First you need to create an instance of an **Audio3DManager** inside the **World**. You can use the **camera** object as the reference point for calculating how far the sound is traveling and therefore how much the volume should drop. Set the drop off factor to **10**. Then load the sound **glenn_launch.wav** (from the assets file) and attach it to the television screen. Set the min distance of the sound to **1.2**. Make sure to start the sound playing. Play with different drop off factors and min distance values and see how it affects the sound in the room as you move around. Note that for a sound to get localized, the sound has to be stored in a //Mono// format. # HINT - Creating a 3D audio manager # Note that 'reference_point' could be the nodepath of a listener's location audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], ) audio3d.setDropOffFactor() # HINT - Loading a 3D sound and attaching it to an object sound = audio3d.loadSfx() sound.setVolume() audio3d.attachSoundToObject(sound, ) audio3d.setSoundMinDistance(sound, ) sound.play() - **Transparent Windows:**\\ Some of the wall panels have windows on them (namely the window and door panels). It would be nice to see through those windows to the world outside! To make the glass see-through in your panels, you need to use textures that store a transparency value for each pixel, as well as the Red/Green/Blue (RGB) information. This transparency information is stored in an image layer called an //alpha channel//. In this layer, the color white (maximum value) means a opaque surface but the color black (minimum value or 0) means fully transparent. Not all image formats can store an alpha channel along with RGB color information. A new version of the **wall_tanned_door** and **wall_tanned_window** with an alpha channel, has been created in the **tiff** format (extension *.tif). Load this version of those textures into your **Room** instead of the previous *.png ones. One more step is needed though. You will need to enable the transparency effect on the actual model that receives the texture. Call the following method on the wall panel NodePath the first time you load the model: .setTransparency(TransparencyAttrib.MAlpha) - **Terrain:**\\ Now, let's create an actual outside world. First create the terrain. You can make your own //heightmap// (512x512 grayscale texture where white is highest and black is lowest) and //colormap// (512x512 color texture) like you saw in class, or you can use the supplied maps contained in the assets file. Add a **''create_terrain''** method to your **''World''** class. Inside it, do the following: - Create a //Heightfield Tesselator// and give it the heightmap you have chosen. For the supplied heightmap, set the tesselator's vertical scale to **5.0** and horizontal scale to **0.25**. If you make your own, you may want to change these values for a better fit. Then use the tesselator to generate a terrain node that you can position anywhere you want in the world. The position **(-64,64,-0.05)** works well with the supplied heightmap. Place it directly under the root of your scene graph. #HINT - Creating a Hightfield Tesselator and a Terrain Node tess = HeightfieldTesselator() tess.setHeightfield(Filename()) tess.setVerticalScale() tess.setHorizontalScale() terrain = tess.generate() terrain.reparentTo(render) - If you call //base.toggleWireframe()// in your code, you'll see the detail of the generated mesh. If you look carefully, you'll find that at a certain place in the landscape the detail is much greater (i.e. more polygons are generated). Typically you would want to generate more detail where the user is standing. You set this location **before** you generate the mesh, like this:tess.setFocalPoint(,)Note that the coordinates are in heightmap pixels (so 256,256 would place you in the center of a 512x512 map). - Load the //colormap// texture and apply it to your terrain node. But first you must generate texture coordinates for your terrain geometry. You can generate texture coordinates for any geometry in a node by making the following call ''.setTexGen(TextureStage.getDefault(),TexGenAttrib.MWorldPosition)''. You will also have to scale the texture and center it by using the ''.setTexScale(, , )'' and ''.setTexOffset(, , )'' methods. Good uniform scale would be **1/128** (this value is 1/(*), i.e. 1/(0.25*512)), and centering just involves an offset of -0.5 for both ''u'' and ''v''. - **Skybox:**\\ The sky and the world beyond the terrain is still gray and gloomy. Surround your entire scene with a box that has textures facing the inside to replace the gray color with something interesting. A box like that, with textures depicting a sky already applied, can be found with the name **"Models/skybox.egg"**. As you can see, this sort of an object is called a //skybox//. Create a new **''create_skybox''** method in your **''World''** class. Use it to load the skybox model as the member variable **self.skybox** in your **World** class, attach it to **render** and scale it up 200 times. A //skybox// represents a horizon that the user should never be able to reach and pass through, and therefore it needs to move with the user, always keeping the user at its center. This is easy to do since **World** already has a **move** method that updates the camera position. Once the camera position has been updated in that method, give **self.skybox** the same position as the camera. Try moving outside of the room and notice how the clouds seems to stay put.\\ NOTE: The clouds textures of the //skybox// were rendered using the [[http://www.planetside.co.uk/|Terragen Tool]] with a handy [[http://www.terathon.com/wiki/index.php?title=Making_a_Skybox_Using_Terragen|skybox rendering script]]. You can create your own skies with this tool. You can replace the textures of ''Models/skybox.egg'' simply by opening the file in a text editor and changing the texture filenames to your files. - **Fog:**\\ To add a little bit of an atmosphere (and to save the rendering engine from rendering objects that are very far away), add some fog to your whole scene and play with the values. Don't make the fog too dense or you won't see much through the windows of your house. # HINT - Adding fog to a sub-tree starting at '' fog = Fog("Fog") fog.setColor(0.6,0.6,0.8) fog.setExpDensity(0.008) .setFog(fog)