ShapeWaterTutorial, version = 0

Circle Water Tutorial

This tutorial will step through generating a spot using the CircleWater function.
You can cut and paste the 3DML code into a text editor. Also, all the tutorial spots are located in the directory labeled /TutorialSpots/.


The CircleWater function creates a flat disk of water parellel to the XZ plane. The center of the disk is specified by the parameters (Xcenter, Ycenter, Zcenter).   The center is specified as an offset from the blocks absolute (0, 0, 0) coordinates. The inner radius is specified by the parameter Rinner, and the outer radius is specified by the parameter Router.   The parameter Nvertices tells the function the number of vertices on one side of a water.bset or ShapeWater.bset block. All the blocks in the water.bset and ShapeWater.bset have the number of vertices listed in the name of the block. Example: Pattern15x15 is a water block with 15 vertices on a side. The parameters Xcenter, Ycenter, Zcenter, Rinner, Router are specified in pixels.
Refer to Figure 1.

Note: A block in Rover is 256 pixels on a side.

Note: A block's absolute (0,0,0) coordinate is the Lower South-West corner of the block.

Note: When using the RIPPLE style = "WAVE" the water wave will propagate from Rinner to Router. If (Rinner < Router) the wave will propagate away from the center of the disk.  If (Rinner > Router) then the wave will propagate into the center of the disk.

Function Prototype:
CircleWater( blockReference, Nvertices, Xcenter, Ycenter, Zcenter, Rinner, Router )

The Translate function moves the (0, 0, 0) coordinates of a block to the coordinates specified in the function call. The coordinates are specified in pixels.
Function Prototype:
TranslateBlockRelative( blockReference, Xcenter, Ycenter, Zcenter ) Moves the block relative to the block's (0,0,0) point.
TranslateBlockAbsolute(blockReference, Xcenter, Ycenter, Zcenter ) Moves the block to the absolute Map point (Xcenter,Ycenter,Zcenter).

Scale Factor: Figure 1. Circle Water

CicleWaterSpot1.3dml

Create a spot that places a circular disk of water at the (0,10,0) coordinates of a block. The coordinates (0,10,0) will place the disk centered over the south-west corner of the blocks current map position and 10 pixels above the floor. The disk will be made with the Circle31x31 block from the ShapeWater blockset. The inner radius of the disk will be 25 pixels and the outer radius will be 100 pixels.
The Circle31x31 block has 31 vertices on a side. The parameter Nvertices in the CircleWater( ) function call should be set to 31.
<spot>
<head>
<title name="Circle Water Spot 1"/>
<blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>

<!-- get the ShapeWater Blockset -->
<blockset href="http://www.mikejost.com/3dml/Blocksets/ShapeWater/ShapeWater.bset"/>

<debug/>
<map style="double" dimensions="(5,5,1)" /> 
<sky brightness="90%"/>
<ambient_light brightness="100%"/>
<ground texture="@basic:cement.gif"/>

</head>
<body>

<!--   Import ShapeWater Functions   -->
<import href="http://www.mikejost.com/3dml/Blocksets/ShapeWater/ShapeWater.3dml"/>

<!--  Create the Circular water block -->
<create symbol="cw" block="Circle31x31">
   <param movable="yes" origin="(0.0, 0.0, 0.0)"/> <!-- make block Movable and set origin to lower south-west corner -->
   <part name="*" texture="@ShapeWater:bluewater.jpg" style="tiled" translucency="30%" faces="2"/>
   <action trigger="start">
      <ripple style="waves" force="10.0" droprate="50%" damp="93%"/>
   </action>
</create>

<define>

   <!-- Start Function -->
   <function name="start">
      // Initialize the vertices of the water block
      // so they have an inner radius of 25, and
      // an outer radius of 100 and the block is
      // positioned at (0,10,0)
      waterBlock = map.get_block("cw");
      // CircleWater( block, Nvertices, Xcenter, Ycenter, Zcenter, Rinner, Router )
      CircleWater( waterBlock, 31, 0, 10, 0, 25.0, 100.0);
   </function>

</define>


<!--
 1  2  3  4  5  -->
<level number="1">
.. .. .. .. ..  <!--  1 -->
.. .. cw .. ..  <!--  2 -->
.. .. .. .. ..  <!--  3 -->
.. .. .. .. ..  <!--  4 -->
.. .. .. .. ..  <!--  5 -->
</level>

<entrance name="default" location="(3,4,1)" angle="340,0" />

</body>
</spot>


The disk in the spot should look like Figure 1. The wave should start in the center of the disk and flow towards the outer edge.

Make the wave flow from the outer edge to the center.

Next, let's make the water wave start at the outer edge and flow towards the center of the disk.
To do this just reverse the inner and outer radii.

Change Rinner to 100.0 and Router to 25.0 in the CircleWater( ) function.
The changed function would be:

 CircleWater( waterBlock, 31, 0, 10, 0, 100.0, 25.0 );


Make the surface of the water parallel to the west edge of the block.

Use the block.rotate_z() function to rotate the water block around the Z-axis 90 degrees so it's surface is parallel to the west edge of the block. The rotate function should be called after the call to the CircleWater function. Change the "Start" code to look like:

  waterBlock = map.get_block("cw");
  CircleWater( waterBlock, 31, 0, 10, 0, 25.0, 100.0 );
  waterBlock.rotate_z(90.0);

The modified spot should look like Figure 2.

Figure 2

Rotate water block around multiple axes.

First rotate the block around the Z axis as in the example above and then rotate the block around the Y axis by -45 degrees. To do this just call block.rotate_y() after the call to block.rotate_z(). Change the "Start" code to look like:

  waterBlock = map.get_block("cw");
  CircleWater( waterBlock, 31, 0, 10, 0, 25.0, 100.0 );
  waterBlock.rotate_z(90.0);
  waterBlock.rotate_y(-45.0);

The modified spot should look like Figure 3.

Figure 3

Experimentation:

  • Try changing the Xcenter, Ycenter, and Zcenter in the CircleWater() function.
  • Try using the other rotate function, block.rotate_x().
  • Try changing the "origin" parameter in the block definition.


    Notes:

  • The origin of the block is the center of rotations.
  • The CircleWater() center coordinates are absolute block coordinates and are not based on the origin of the block.


    Translate Functions

    The TranslateBlockRelative(block, Xcenter, Ycenter, Zcenter) function is used to move the blocks's (0,0,0) coordinate to the new coordinate (Xcenter, Ycenter, Zcenter) relative to the block's (0,0,0) coordinate.

    The TranslateBlockAbsolute(block, Xcenter, Ycenter, Zcenter) function is used to move the block's (0,0,0) coordinate to the absolute Map space coordinate (Xcenter, Ycenter, Zcenter).

    These functions are general block movement functions. These functions simplify the positioning of the rotated water blocks.

    As an example, take the water disk from above which had been rotated about the Z and Y axes. Make the final center of the disk be at (128,128,128). There are two ways to accomplish this:

    1. Center of water function and the Block origin at the final center point.

  • define the origin of the block to be (128,128,128) in the blocks CREATE tag.
  • define the (Xcenter,Ycenter,Zcenter) to be (128,128,128) in the CircleWater( ) function call.
  • call rotate_z( )
  • call rotate_y( )

    2. Center of water function and the Block origin at (0,0,0)

  • define the origin of the block to be (0,0,0) in the blocks CREATE tag.
  • define the (Xcenter,Ycenter,Zcenter) to be (0,0,0) in the CircleWater( ) function call.
  • call rotate_z( )
  • call rotate_y( )
  • call TranslateBlockRelative(128,128,128)

    In Case 2 above, if you need to reposition the water block you change only the coordinate in the TranslateBlockRelative( ) call, otherwise for Case 1 you need to change the coordinate in the water function and the Block definition.


    CircleTranslateSpot2.3dml

    Create 3 circular water disks with centers at X=0, and Z=0, and each one having a Y center 50 pixels above the last one. The first circular disks Y coordinate will be 20. The inner radius of the disks will be 25 pixels and each disk will have an outer radius of 100 pixels. Also, the 3rd disk will use the RIPPLE "raindrop" effect.
    <spot>
    <head>
    <title name="Circle Translate Spot 2"/>
    <blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
    
    <!-- get the ShapeWater Blockset -->
    <blockset href="http://www.mikejost.com/3dml/Blocksets/ShapeWater/ShapeWater.bset"/>
    
    <debug/>
    <map style="double" dimensions="(5,5,1)" /> 
    <sky brightness="90%"/>
    <ambient_light brightness="100%"/>
    <ground texture="@basic:cement.gif"/>
    
    </head>
    <body>
    
    <!--   Import ShapeWater Functions   -->
    <import href="http://www.mikejost.com/3dml/Blocksets/ShapeWater/ShapeWater.3dml"/>
    
    <!--  Create the 1st Circular water block -->
    <create symbol="w1" block="Circle31x31">
       <param movable="yes" origin="(0.0, 0.0, 0.0)"/> <!-- make block Movable and set origin to lower south-west corner -->
       <part name="*" texture="@ShapeWater:bluewater.jpg" style="tiled" translucency="30%" faces="2"/>
       <action trigger="start">
          <ripple style="waves" force="10.0" droprate="50%" damp="93%"/>
       </action>
    </create>
    
    <!--  Create the 2nd Circular water block -->
    <create symbol="w2" block="Circle31x31">
       <param movable="yes" origin="(0.0, 0.0, 0.0)"/> <!-- make block Movable and set origin to lower south-west corner -->
       <part name="*" texture="@ShapeWater:bluewater.jpg" style="tiled" translucency="30%" faces="2"/>
       <action trigger="start">
          <ripple style="waves" force="10.0" droprate="50%" damp="93%"/>
       </action>
    </create>
    
    <!--  Create the 3rd Circular water block -->
    <create symbol="w3" block="Circle31x31">
       <param movable="yes" origin="(0.0, 0.0, 0.0)"/> <!-- make block Movable and set origin to lower south-west corner -->
       <part name="*" texture="@ShapeWater:bluewater.jpg" style="tiled" translucency="30%" faces="2"/>
       <action trigger="start">
          <ripple style="raindrops" force="30.0" droprate="60%" damp="97%"/>
       </action>
    </create>
    
    <define>
    
       <!-- Start Function -->
       <function name="start">
    
          map.set_block(3,2,1,"w1"); // put 1st block on map
          waterBlock = map.get_block("w1");
          // CircleWater( block, Nvertices, Xcenter, Ycenter, Zcenter, Rinner, Router )
          CircleWater( waterBlock, 31, 0, 0, 0, 25.0, 100.0); // configure 1st block as a disk with center at (0,0,0)
          TranslateBlockRelative( waterBlock, 0, 20, 0);  // move the 1st block to Y=20
    		
          map.set_block(3,2,1,"w2"); // put 2nd block on map
          waterBlock = map.get_block("w2");
          CircleWater( waterBlock, 31, 0, 0, 0, 25.0, 100.0); // configure 2nd block as a disk with center at (0,0,0)
          TranslateBlockRelative( waterBlock, 0, 70, 0);  // move the 2nd block to Y=70
    
          map.set_block(3,2,1,"w3"); // put 3rd block on map
          waterBlock = map.get_block("w3");
          CircleWater( waterBlock, 31, 0, 0, 0, 25.0, 100.0); // configure 3rd block as a disk with center at (0,0,0)
          TranslateBlockRelative( waterBlock, 0, 120, 0);  // move the 3rd block to Y=120
    		
       </function>
    
    </define>
    
    
    <!--
     1  2  3  4  5  -->
    <level number="1">
    .. .. .. .. ..  <!--  1 -->
    .. .. .. .. ..  <!--  2 -->
    .. .. .. .. ..  <!--  3 -->
    .. .. .. .. ..  <!--  4 -->
    .. .. .. .. ..  <!--  5 -->
    </level>
    
    <entrance name="default" location="(3,4,1)" angle="340,0" />
    
    </body>
    </spot>
    


    End of CircleWater Tutorial

    Go to the TubeWater Tutorial Next.