Simulink 3D Animation

Terrain Visualization Example

This example shows how to convert generally available Digital Elevation Models into VRML format for use in virtual reality scenes.

We use the South San Francisco DEM file included in Mapping Toolbox has been used as a source of the sample data. A simple precreated Boeing 747 model is included in the scene to show the technique of creating virtual scenes from several sources on-the-fly.

The example uses Mapping Toolbox functions for working with DEM data. The example uses Image Processing Toolbox functions as well.

Contents

Reading DEM Data

We start by unzipping the South San Francisco DEM file to a temporary directory.

filenames = gunzip('sanfranciscos.dem.gz', tempdir);
demFilename = filenames{1};

We now use Mapping Toolbox to read the 1:24,000 DEM file; lat, lon, Z are 2D arrays containing latitude, longitude, and altitude of DEM data repectively.

[lat, lon, Z] = usgs24kdem(demFilename, 1);
disp(size(Z))
   464   371

We can use the mesh function to plot the data.

mesh(lat,lon,Z);

Preparing Data

We now use the data to prepare it for creating a virtual world.

demdata=Z;
[xdim zdim] = size(demdata);
xspace = 30; % scaling in meters for x dimension
zspace = 30; % scaling in meters for z dimension

We reshape the data into a one-dimensional array.

demdata = demdata(:);
disp(size(demdata));
      172144           1

Creating a Virtual World from the Template

This code opens a template.

myworld = vrworld('vr_template_terrain.wrl');

Now we open the virtual world.

open(myworld);

We create a handle to a node VRTerrain. This node that will contain the DEM data.

Terrain_node = vrnode(myworld,'VRTerrain');

We can view the nodes of the virtual world.

nodes(myworld)
	VRTerrain (Transform) [VR Terrain Template]
	View_5 (Viewpoint) [VR Terrain Template]
	VP5 (Transform) [VR Terrain Template]
	View_4 (Viewpoint) [VR Terrain Template]
	VP4 (Transform) [VR Terrain Template]
	View_3 (Viewpoint) [VR Terrain Template]
	View_2 (Viewpoint) [VR Terrain Template]
	View_1 (Viewpoint) [VR Terrain Template]
	World_Info (WorldInfo) [VR Terrain Template]

Creating Terrain Node Fields (Shape, Appearance, Material)

This code creates a child of VRTerrain, shape.

newShape = vrnode(Terrain_node, 'children', 'Terrain_Shape', 'Shape');

This code creates the appearance field for the shape.

newAppear = vrnode(newShape, 'appearance', 'Terrain_Appearance', 'Appearance');

This code creates the material field for the apperance.

newMat = vrnode(newAppear, 'material', 'Terrain_Material','Material');

This code assign properties for the material field.

newMat.ambientIntensity = 0.25;
newMat.diffuseColor = [0.9 0.6 0.6];
newMat.shininess = 0.078125;
newMat.specularColor = [0.0955906 0.0955906 0.0955906];

This code creates geometry field for the shape.

newEGrid = vrnode(newShape, 'geometry', 'DEM_EGrid','ElevationGrid');

This code assigns properties for the geometry field, using DEM data.

newEGrid.creaseAngle = 3.14;
newEGrid.xDimension = xdim;
newEGrid.zDimension = zdim;
newEGrid.xSpacing = xspace;
newEGrid.zSpacing = zspace;
newEGrid.height = demdata;
newEGrid.ccw = 'TRUE';

This setting makes the terrain surface visible from both sides.

newEGrid.solid = 'FALSE';

The virtual scene can be captured using the vrfigure capture method to make a screenshot and put it into a bitmap image.

Before capturing,we will hide the navigation panel from the virtual scene.

F=vrfigure(myworld);
set(F,'NavPanel','none');
vrdrawnow;
img_capture = capture(F);
img = image(img_capture);

Creating the Terrain Texture

For coloring the terrain texture we use the demcmap function available in Mapping Toolbox. Terrain elevation is used to color the image.

cmap = demcmap(Z, 256);

We create a texture subdirectory in the current directory. Output arguments are used only to avoid warning message when the directory already exists.

[ok, mess, id] = mkdir('texture');

We scale the height values to use the full colormap range. Scaling relies on the fact that this terrain begins at zero height.

Zscaled = Z .* (size(cmap,1)-1) ./ max(Z(:));

We now save the texture into a PNG image in the texture subdirectory. We rotate the image to the left to match the image orientation needed in the VRML model. Elements of Zscaled represent indices into cmap.

imwrite(rot90(Zscaled), cmap, 'texture/sanfrancisco_elev.png');

This is how the saved image looks:

image(rot90(Zscaled));
colormap(cmap)

Assigning Texture to the VRTerrain Appearance Field

We now include the texture image created above into the VRML scene, as a texture field of the terrain Appearance node.

newTexture = vrnode(newAppear, 'texture', 'Terrain_texture','ImageTexture');
newTexture.url = 'texture/sanfrancisco_elev.png';

This is a screenshot of our virtual scene.

F=vrfigure(myworld);
set(F,'NavPanel','none');
vrdrawnow;
img_capture = capture(F);
img = image(img_capture);

Adding the Airplane to the Virtual Scene

This code creates a new Transform node, called Boeing.

plane = vrnode(myworld, 'Boeing', 'Transform');
plane_inline = vrnode(plane, 'children', 'Boeing_Inline', 'Inline');

We use a simple precreated VRML model of a Boeing 747.

plane_inline.url='b747.wrl';

We can now see the node we just created in the list of nodes.

nodes(myworld)
	Boeing_Inline (Inline) [VR Terrain Template]
	Boeing (Transform) [VR Terrain Template]
	Terrain_texture (ImageTexture) [VR Terrain Template]
	DEM_EGrid (ElevationGrid) [VR Terrain Template]
	Terrain_Material (Material) [VR Terrain Template]
	Terrain_Appearance (Appearance) [VR Terrain Template]
	Terrain_Shape (Shape) [VR Terrain Template]
	VRTerrain (Transform) [VR Terrain Template]
	View_5 (Viewpoint) [VR Terrain Template]
	VP5 (Transform) [VR Terrain Template]
	View_4 (Viewpoint) [VR Terrain Template]
	VP4 (Transform) [VR Terrain Template]
	View_3 (Viewpoint) [VR Terrain Template]
	View_2 (Viewpoint) [VR Terrain Template]
	View_1 (Viewpoint) [VR Terrain Template]
	World_Info (WorldInfo) [VR Terrain Template]

Determining the Highest Peak in the Terrain Data

We now determine the highest elevation point in our terrain data.

ypeak = max(Z(:));
[xmax zmax] = find(Z==ypeak);

If more than one vertices have the same maximum height,we use the first peak. We convert matrix indices to meters in x and z directions in VRML.

xpeak=xspace*(xmax(1)-1);
zpeak=zspace*(zmax(1)-1);
disp(xpeak);
disp(zpeak);
        6960

        5820

Positioning the Airplane 200 Meters Above the Peak

We now position the airplane 200 meters above the peak we just found.

plane.translation = [xpeak ypeak+200 zpeak];

We scale the size of the airplane by a factor of 20, so that it is visible in the virtual scene without any extra zooming.

plane.scale = [20 20 20];

This is a screenshot of our virtual scene.

F=vrfigure(myworld);
set(F,'NavPanel','none');
vrdrawnow;
img_capture = capture(F);
img = image(img_capture);

Adding the Coordinate System Triad to the Virtual Scene

It is sometimes useful to temporarily include in the scene a triad that can help with the orientation of objects added to the scene. We precreated triad.wrl file for this purpose. We can now include this file in our model.

The triad consists of three lines (1 meter long) running from one vertex along the x, y and z directions. The lines are colored as follows:

+x - red

%+y - green
%
% +z - blue
%
% If the triad is included in the scene at the top level of the scene
% hierarchy, it denotes the global scene coordinates.
% If it is included as a child of a transform node, it denotes the local
% coordinate system (orientation) of that node in the scene.
%
% We add the triad to the scene at the top level of the hierarchy.
triad = vrnode(myworld, 'Triad1', 'Transform');
triad_inline = vrnode(triad, 'children', 'Triad_Inline', 'Inline');
triad_inline.url='triad.wrl';

We scale the size of the triad so that it is visible in the virtual scene without any extra zooming.

triad.scale = [xdim*xspace/8 min(xdim*xspace/8, zdim*zspace/8) zdim*zspace/8];

We position the triad at the center of the Boeing 747.

triad.translation=[xpeak ypeak+200 zpeak];

This is a screenshot of our virtual scene.

F=vrfigure(myworld);
set(F,'NavPanel','none');
vrdrawnow;
img_capture = capture(F);
img = image(img_capture);

Saving the Created World to a New WRL File

This code saves the virtual scene we created into a file.

save (myworld, 'vrterrain_sanfrancisco.wrl');

Closing and Deleting the Virtual World Used to Create the Scene

This code closes and deletes the virtual world from the workspace.

close(myworld);
delete(myworld);

Opening and Viewing the Virtual World File

We now open and view the virtual scene we just created

createdworld = vrview('vrterrain_sanfrancisco.wrl');

This code sets antialiasing on to smooth the terrain texture.

myfig = get(createdworld,'Figures');
set(myfig, 'Antialiasing', 'on');

Showing Virtual Scene

This code takes a screenshot of our virtual scene.

set(myfig,'NavPanel','none');
vrdrawnow;
img_capture = capture(myfig);
img = image(img_capture);

Set the title of the Axes object that is parent of the image object.

set(get(get(img, 'Parent'),'Title'),'String',...
    'Screenshot of B747 Flying over the San Francisco Area');

This code changes the viewpoint to "Side view" and takes a screenshot of our virtual scene.

set(vrgcf,'Viewpoint','Side view');
vrdrawnow;
img_capture = capture(myfig);
img = image(img_capture);

This code changes viewpoint to the "Above the scene" and takes a screenshot of our virtual scene.

set(vrgcf,'Viewpoint','Above the scene');
vrdrawnow;
img_capture = capture(myfig);
img = image(img_capture);

If you have a VRML plug-in installed in your web browser, you can view the virtual scene created in this example at this link:

View the virtual scene.