Making 3D Scenery3D scenes are models which the user may enter, move around, and view from different angles. An example is the castle in the test2.obj landscape, as seen in Figures 27-1 and 27-14. Figure 27-14. The castle in the test2.obj terrain
The placement of models and the user's initial position in the terrain are specified in a text file with the same name as the landscape's OBJ file; for this example, the text file is test2.txt in the directory models/: start 3960 1800 255.64 Castle.cob 4100 4230 220 70 bldg4.3ds 6780 3840 780 90 hand1.obj 1830 570 781.98 120 The file format is: start x y z <model file> x y z scale <model file> x y z scale // more model file lines A start line must be included in the file because specifies where the user is initially placed in the landscape, but the scenery objects are optional. The (x, y, z) values are in landscape coordinates, and the scale value is used to adjust the model's size in the terrain. Each scenery object is loaded with a PropManager object (introduced back in Chapter 16); the code assumes the existence of coords datafiles for the models. A difficult task is deciding on suitable (x, y, z) and scale values. One approach is to jot down likely coordinates while running Terragen. Another technique is to move over the loaded terrain in Terra3D and print out the current position by pressing the w button (w for "where"). This functionality is supported by KeyBehavior, described later. Yet another possibility is to open the OBJ file with a text editor, and search through the v lines for likely looking coordinates. None of these approaches help with scale factors, which are mostly estimates. The scenery models are attached to landBG, so will be translated, rotated, and scaled in the same way as the landscape. The scale factor for the terrain is stored in scaleLen (it's 0.0078125 in the test2 example). Thus, to render the model at the same size as it was created, the scaling must be undone by enlarging it by 1/scaleLen (scaleLen is 128 in test2). Another consideration is the height of the user's viewpoint. In KeyBehavior, the user's height above the XZ plane is set to the USER_HEIGHT constant (0.5 world units), which is equivalent to 0.5/0.0078125, or 64 landscape units. In practice, it's a good idea to start with a scale factor between 64 and 128; 90 seems like a good value. Landscape's constructor calls makeScenery( ) to add scenery to landBG: makeScenery(landBG, fname); fname is the filename supplied on the command line (e.g., test2). makeScenery( ) parses the scenery file, storing the user's starting position in originVec, and calls placeScenery( ) to place each model in the terrain. originVec is used by KeyBehavior, so must be specified in world coordinates. However, the input from the scenery file is in terrain coordinates. The translation between the two coordinate systems is done through a call to landToWorld( ): // called in makeScenery( ) originVec = landToWorld(xCoord, yCoord, zCoord); private Vector3d landToWorld(double xCoord, double yCoord, double zCoord) { double x = (xCoord * scaleLen) - LAND_LEN/2; double y = zCoord * scaleLen; // z-axis -> y-axis double z = (-yCoord * scaleLen) + LAND_LEN/2; // y- -> z-axis return new Vector3d(x, y, z); } landToWorld( ) applies the rotation, scaling, and translation utilized when the terrain is connected to the world, as illustrated in Figure 27-12. The rotation is achieved by swapping the terrain (z, y) values to become world (y, z) coordinates. The scaling must be done before the translation to mimic the ordering of the transforms in Figure 27-12. Placing the ModelsplaceScenery( ) attaches a model to landBG. However, some additional transformations must be applied, as shown in Figure 27-15. Figure 27-15. A Model subgraph below landBGThe translation and scaling values are supplied for the model in the scenery file. These are given in terms of terrain coordinates because the model is being added to landBG. The rotation is harder to fathom. The landscape is rotated -90 degrees around the x-axis, and this is applied to the model as well. However, the model is correctly oriented to rest on the XZ plane, so the terrain rotation must be undone by rotating the model +90 degrees back around the x-axis: private void placeScenery(BranchGroup landBG, TransformGroup modelTG, double x, double y, double z, double scale) { modelTG.setPickable(false); // so not pickable in scene Transform3D t3d = new Transform3D( ); t3d.rotX( Math.PI/2.0 ); // to counter the -ve land rotation t3d.setScale( new Vector3d(scale, scale, scale) ); // scaled TransformGroup scaleTG = new TransformGroup(t3d); scaleTG.addChild( modelTG ); Transform3D t3d1 = new Transform3D( ); t3d1.set( new Vector3d(x,y,z)); // translated TransformGroup posTG = new TransformGroup(t3d1); posTG.addChild( scaleTG ); landBG.addChild( posTG ); }
|