Cybertown Mall Cybertown Revival

Tutorial 2 of 10

CREATING SHAPES

CREATOR NOTEby Morning.star, published with permission

GENERAL CODING ISSUES

To begin we'll have a look at what a piece of coding looks like. Here is the code for a box :

Transform { translation X X X children [
Shape {
appearance Appearance {
material Material { diffuseColor X X X }
texture ImageTexture { url "yourpic.jpg" }}
geometry Box { size X X X }}
]}

This coding structure is basically common to all the codes you'd be writing so let's have a closer look at that basic structure. What does it all mean ?

Notice, first, the overall structure of the code. Similar to HTML, things "turned on" first are "turned off" last. So we "turn on" the nodes that define our object :

Shape {
appearance Appearance {
material Material { diffuseColor X X X }
texture ImageTexture { url "yourpic.jpg" }}

After those lines we define & "turn off" the whole shebang :

geometry Box { size X X X }}
]}

Notice that there are 3 different kinds of brackets being used: ]} the squared & curly ones; & ) the rounded one. It matters which kind of bracket you use where so be careful when you are typing out your code.

QUICK TIP

The coding for a piece will have an equal number of each kind of corresponding bracket in pairs. So, for example, if you have a { you must also have a } somewhere. Since a common error is using the wrong kind of bracket or forgetting to put one in, if that old error box comes up in 3d, check your coding by counting up your pairs of brackets.

Transform { translation X X X children [

This piece of coding (or minor variations thereof, which you'll see in more complex examples) begins each piece in an object. The word Transform is a basic alert that the parameters of a piece are about to be defined. The word children here signifies that there will be a number of nodes defined which are all part of that piece.

The translation part of the code is what will locate your object in space. So for example, if you were to code 0 0 0 for the translation ( subtituting numbers for the Xs in the example above ), your piece would fall dead center in a world.

What do these numbers represent though ?

The 1st number in the translation code locates your object left/right of the centerpoint 0. Use minus numbers for left ( eg. -1 ) & just plain ole numbers for right ( eg. 1 ). The basic unit of measurement in VRML is a metre so -1 would be 1 metre to the left of center 0, & 1 would be 1 metre to the right of center 0.

Jumping ahead for a reason, the 3rd number in the translation code locates your object front/back of the centerpoint 0. So -1 would be 1 metre behind center 0, & 1 would be 1 metre in front of center 0.

So far so good.

The 2nd number in this part of the code is the tricky one if you are creating objects for the Mall - vertical location - but it's not hard to do once you get the hang of it. Bottom line here ( a kind of VRML pun ) is that for objects you are creating for the Mall, in fact 0 ( zero ) is not used as ground level. Why? ( *coughs* ) Instead, ground zero is located at the unbelievable number of -1.75 yep, -1.75 . . . learn that number by heart for when you are creating for the Mall ... & forget it completely if you're building worlds!

And don't let those negative numbers confuse you ( ha! ha! ) or at least be patient with yourself about them. They do take a little getting used to :)

So when we assign a numeric value to those Xs in translation for simple geometries like boxes, what we are doing is defining where we want the CENTERPOINT of our piece to be located. We'll get into an example later that will help you understand how to define a piece's vertical location.

QUICK TIP

The X X X, or if you prefer, the 0 0 0 setup of numbers is a standard one that you will find in many different instances of VRML coding. Generally speaking, any time you see 3 numbers in a row, the 1st refers to side to side spacing, the 2nd to vertical, & the 3rd to front/back spacing. Except - of course, where color is concerned. For color, the 3 numbers refer to 1st-Red, 2nd-Green, 3rd-Blue. We deal with material & texture coding in separate tutorials.

  • * * * * * * * * * * * * * * * * * * *

MORE BASIC SHAPES - Sphere, Cylinder, Cone

The Sphere

The coding for a sphere goes on the same line as for that of a box - on the geometry line :

geometry Sphere { radius X }}

Calculating the vertical position of a sphere obeys the same rules as for the Box EXCEPT that you use the whole radius value for the height. So, for example, if your sphere has a radius of 0.3 you would calculate the vertical position using the radius as follows :

0.3 minus -1.75 = -1.45

So your "translation" coding then would become :

Transform { translation 0 -1.45 0 children [

Not hard at all is it ? :)

The Cylinder

Again, all the same coding except for that one geometry line, although for a cylinder the coding is a little more complex because you have to define a few more characteristics :

geometry Cylinder { radius X height X top TRUE bottom TRUE side TRUE }}

QUICK TIPS

  1. In this instance you would use the height to calculate the vertical position of your piece.
  2. The top/bottom/side definitions can be made FALSE instead of TRUE. Whatever you make FALSE will become invisible.
  3. If all 3 top/bottom/side characteristics are TRUE you can omit these lines from your code ( & thus save on the file size of your .wrl ) because the default coding for a cylinder has all 3 characteristics defined as TRUE.

The Cone

Again, a little bit of different coding in that one geometry line :

geometry Cone { height X bottomRadius X side TRUE bottom TRUE }}

QUICK TIPS

  1. Use the height number to do your vertical position calculation.
  2. You may define side and/or bottom as FALSE. Any characteristic defined as FALSE becomes invisible.
  3. You may leave out the definitions for side/bottom if both are TRUE since the default definition for a cone has both as TRUE & doing so will save some file size.
  4. You may put all of the inside definitions of a geometry on 1 line to save space as well, for example:
geometry Cylinder { height 1 radius 0.5 top FALSE }

QUICK TIP : This applies across the board to all instances of numbers - for all-purpose applications, use up to 2 decimal points in defining your numbers ( eg 0.00 ). In most instances, you won't need to use more than 1 or 2 decimal points. More decimal places than 2 are unnecessary unless you are working on a very small ( & i mean microscopic ) object & need an incredible level of fine tuning, or the pieces you are trying to fit together require fussy fitting.

  • * * * * * * * * * * * * * * * * * * *

THE EXTRUSION

Remember when using the more complex kinds of shapes that the more points you define in the shape, the more processing power it's going to take to render it, so KEEP IT SIMPLE. Before getting into an example, there are a number of things to be aware of regarding the Extrusion :

  1. Textures apply differently to the sides than to the bottom ( beginCap ) & top ( endCap ) of an extruded shape.
  2. Extrusion coding is extremely efficient & if used rationally can make creating a very easy logical exercise. They also optimize & reduce ( what happens to your file size when you gzip your work ) well.
  3. The vertical centering for an Extrusion is NOT the same as for the Basic Shapes ( Box, Cylinder, Sphere, Cone where the center is defined by the MIDPOINT on the VERTICAL axis ). For an Extrusion, when you define the BOTTOM ( spine ) at 0, the rest of its vertical height will appear ABOVE 0. If you want the midpoint to occur in the middle of an Extrusion you'll have to code the spine at equal distances above & below 0.
  4. Extrusion BOTTOMS ( beginCap ) & TOPS ( endCap ) - not the sides however - do not tolerate concave angles & will 'fill in' the space where a concave is defined UNLESS you begin your definition of points at the cojoining point where the shape becomes concave. You can only do that once per shape though.
  5. Generally, the Extrusion's crossSection points are coded in a CLOCKWISE direction. The exception would be when one wishes to use Solid TRUE coding to make one side of a plane transparent - a useful method of eliminating smashing & sheering planes. Depending on which side you want to make transparent, you might have to reverse the crossSection coding direction & make it counter-clockwise.
  6. Make 0 0 the left/right/front/back CENTERPOINT of a circular Extrusion you wish to apply gradations of scale to, otherwise the scaling will not apply correctly to all sides.
  7. Make certain you close your shape when coding the crossSection points by using the FIRST point you began your coding with as the LAST point you code in as well.
  8. Also make certain you code in the same number of spine triplets as you code scale couplets as these two parts of the code work together to create your shape. The exception is where your scale is the same throughout. In that case you can simply use 2 instances of scale like this : scale [ 1 1, 1 1, ]. The number of points you specify in the crossSection can be any number unrelated to spine or scale. If you want to make odd shapes or specially contoured shapes you can manipulate the spine coding by varying the X X Xs to make vertical, horizontal & front to back nodes going in any direction you wish. See the 'Extrusion spine' section below. My Daemonic objects are examples of using this technique to create zig-zagged shapes.

Here is an example of Extrusion coding 10 x 10 meters, suitable for a carpet :

geometry Extrusion { creaseAngle 1 beginCap TRUE endCap TRUE solid FALSE
crossSection [ -5 5, -5 -5, 5 -5, 5 5, -5 5, ]
spine [ 0 0 0, 0 0 0, ]
scale [ 1 1, 1 1, ]}}

If you want to make a carpet however, it's best to separate the bottom & sides from the top where you would want your full texture to display. In that case you would code the bottom/side piece spine 0 0 0, 0 0.1 0 with the beginCap TRUE endCap FALSE solid FALSE ( see below ) & the top's spine at 0 0.1 0, 0 0.1 0 with its beginCap FALSE endCap TRUE solid FALSE. Myself, I use 0.05 for the height of my carpets & find that sufficient.

  1. If your texture doesn't display the way you want it to you may need to rotate the texture or begin your Extrusion coding somewhere else along the clockwise-coded line.

Extrusion Attributes

The primary attributes for Extrusion coding are creaseAngle, beginCap, endCap, & solid.

creaseAngle

Manipulating the creaseAngle coding will produce a more or less acute APPEARANCE of the facets of an Extrusion. The lower the number, the more acute the appearance, the higher the number, the smoother the appearance. The number range is generally 0 - 3.

beginCap & endCAP

The coding for these is similar to the top, side & bottom of the Cylinder & Cone shapes. These are attributes you can code as TRUE or FALSE. What you make TRUE will be visible & what you make FALSE will be invisible.

solid

The solid coding is a little different kind of attribute. Coded as FALSE it is going to make the planes involved in the shape visible on both sides ( inside & outside ). Coded as TRUE it is going to make the planes visible on just one side ( the inside ).

Extrusion crossSection

The crossSection area of coding is the place where you define the points that will describe the perimeter of the object or piece of it. As mentionned earlier, you must code your points in a CLOCKWISE direction, begin & end with the SAME point if you wish to have a closed piece, & use 0 0 as the CENTERPOINT around which you plot your points so that any scale you apply will apply evenly all the way around. After you create it, you can translate it into position.

Here's is what just the crossSection part of the coding looks like :

crossSection [ -5 5, -5 -5, 5 -5, 5 5, -5 5, ]

Extrusion spine

The spine coding area expresses the height of the object. You may use any number of triplet sets as required ( bearing in mind that excessive coding causes lag ). Here's what the spine part of the coding looks like :

spine [ X X X, X X X, ]

2 sets of triplets would be the minimum number required. But what do the Xs refer to?

The 1st X in spine represents a number which you can use to make the crossSection points deviate + or - HORIZONTALLY LEFT & RIGHT. In most instances ( especially for flat surfaces ), this X will = 0.

The 2nd X in spine is the one you use to define the height of your object AT EACH POINT DEFINED in the scale part of the coding.

The 3rd X in spine represents a number you use to make the crossSection points deviate + or - HORIZONTALLY to the FRONT & REAR. Also for this X in most instances ( especially for flat surfaces ), this X will = 0.

The coding in this area of an Extrusion object is very rational. The 1st set of triplets defines the level of the bottom of your object, the last set defines the level at the top. Here is what spine would look like if you wanted a 0.05 meter thick floor or rug that bottoms at 0 :

spine [ 0 0 0, 0 0.05 0, ]

If you wanted to make two steps up, you might code the spine like this :

spine [ 0 0 0, 0 0.5 0, 0 0.5 0, 0 1 0, 0 1 0, ]

Extrusion scale

scale represents a PERCENTAGE of the area defined by your crossSection points, horizontally left/right & horizontally front/back.

There are 2 Xs in scale ( the couplet ). The 1st X represents the left/right size of the object; the 2nd X represents the front/back size of the object at a point defined in our spine coding. Both Xs are typically coded with THE SAME number in order to maintain the circularity of the object but that can be played with.

If we have a 10 x 10 meter piece & code scale at 0.5 0.5 then our object will be 5 x 5 meters because the numbers for scale run from 0 - 1 to decrease the size of a piece & from 1 up to increase its size.

Likewise, if we code our scale at 2, our object will be twice as big at the corresponding spine node.

Here's what we have for the complete Extrusion coding then ( in this example the Extrusion is beginning at -0.5 below ground & ending level at 0 ) :

Transform { translation 0 0 0 children [
Shape { appearance Appearance { material Material {}
texture ImageTexture { url "ground.jpg" }
textureTransform TextureTransform { scale X X }}
geometry Extrusion {
creaseAngle 1.6 beginCap TRUE endCap TRUE solid FALSE
crossSection [
125 250, -125 250, -250 125, -250 -125, -125 -250,
125 -250, 250 -125, 250 125, 125 250, ]
spine [ 0 -0.5 0, 0 0 0, ]
scale [ 1 1, 1 1, ] }}
]}
  • * * * * * * * * * * * * * * * * * * *

ELEVATION GRID

Well, if you managed to absorb everything about the Extrusion coding, the ElevationGrid will be easy because some of the same issues are involved. Basically what we are doing when we are creating an ElevationGrid is developing a 3d topography in a square shape - a single, one-ply plane with height variations throughout. Here's what a simple piece of ElevationGrid coding looks like ( it's placed at -5 0 -10 to center it since eGrids are a wee bit wonky in that regard ). This one is the grid I used to create my 'Rough Ground' object ( although I've stripped the bumps out of it so you can copy/paste & experiment with it yourself ). It conforms to Mall requirements re. size & positioning, & contains 21 rows & 21 columns, each measuring 0.5 meters. For Mall purposes you would need to add a 0.1 high bottom piece to it to finish it off. That's the reason you would keep all of the perimenter nodes at 0 - so that your finishing piece neatly meets with the top. It might even be necessary to keep the outer 2 nodes at 0.

Transform { translation -5 -1.65 -10 children [
Shape { appearance Appearance { material Material {}
texture ImageTexture { url "yourtexture.jpg" }}
geometry ElevationGrid { xDimension 21 xSpacing 0.5 zDimension 21 zSpacing 0.5
height [
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ]
creaseAngle 2 solid TRUE }}
]}

Here we have a perfectly flat ElevationGrid for a 10 x 10 meter square.

In the above example, each COLUMN ( the xDimension attribute ) represents the left to right points on the terrain map, are 21 in number, & are defined as 0.5 meters apart in the xSpacing attribute. ( I know, 21 divided by 2 = 10.5 ... trust me, these numbers are correct because we start counting at the 2nd number, not the 1st )

And each ROW ( the zDimension attribute ) represents the front to back points on the terrain map ( the front being at the bottom of the map & the back being at the top ), are 21 in number, & are defined as 0.5 meter apart in the zSpacing attribute.

creaseAngle

The same rules apply here as for Extrusion coding - 0 will render sharp angles & 3 will render very smooth angles.

solid TRUE or solid FALSE

If you code solid as TRUE just the topside of the grid will be visible. TRUE can be useful when using multiple grids to create a layered topography & you need to make sure the planes aren't arguing.

If you code solid as FALSE, both the topside & underside of the grid will be visible.

  • * * * * * * * * * * * * * * * * * * *

General Discussion Regarding eGrids

The ElevationGrid is a useful piece of coding & can be used for groundwork & objects such as bathtubs, sinks & pools. When coding in the numbers that take the place of the 0s in the coding example above, it may take some practice to achieve a result that will satisfy you. Remember, however, that although you can generate very smooth & elegant topographies using special software programmes, the number of points those programmes generate to create those grids will cause a considerable amount of lag ie. require noticeable processing power to render. Unfortunately, the name of the game in VRML - especially where it concerns creating worlds that others will use in their homes & clubs is ... COMPROMISE.

QUICK TIPS

  1. ElevationGrid positioning left/right & front/back is a little tricky in that if you put it in at 0 0 it will appear off to the right & behind you. For that reason in the example above, I adjusted the positioning for the grid to -5 to the left ( 1/2 of 10 meters ) & -10 towards the rear ( also 1/2 of 10 meters ) in the Transform { translation part of the coding in order for it to appear centered.
  2. Material color & its attributes on an ElevationGrid will create shifting color & light values on the piece, which may not be what you want. Use PixelTexture or a texture to lessen these effects. Also, the higher the creaseAngle the more the variation in light to dark values there will be.
  3. Applying texture follows the same rules as for the other shapes - use textureTransform TextureTransform { scale X X }} coding to apply multiple instances of a tiling texture to achieve a smoother, non-pixellated effect.
  4. There is an almost physical tension present in an ElevationGrid - pull in one direction on one node & it will impact on another. This tension will in some circumstances cause some of the nodes on your grid to skew. It's hard to think of plain numbers as having the capacity for elasticity, but where the eGrid is concerned they certainly do. Sometimes it can be plain annoying; but at other times, the effects created by the skewing can be quite interesting.
  • * * * * * * * * * * * * * * * * * * *

IndexedFaceSet Coding

Here's what very basic IFS coding looks like - this is a plain red 2-dimensional square :

Transform { translation 0 -1.75 0 children [
Shape { appearance Appearance { material Material { diffuseColor 1 0 0 shininess 0 }}
geometry IndexedFaceSet { coord Coordinate {
point [ -1 0 0, 1 0 0, 1 2 0, -1 2 0 ]}
coordIndex [ 0 1 2 3 ]
solid FALSE }}
]}

And here's a red 2-dimensional square lying flat :

Transform { translation 0 -1.75 0 children [
Shape { appearance Appearance { material Material { diffuseColor 1 0 0 shininess 0 }}
geometry IndexedFaceSet { coord Coordinate {
point [ -1 0 0, -1 0 -2, 1 0 -2, 1 0 0 ]}
coordIndex [ 0 1 2 3 ]
solid FALSE }}
]}
  • * * * * * * * * * * * * * * * * * * *

MAKE a STAR!

Stars are a complex shape which are made flat on the ground then rotated upright. The example below can be made larger or smaller using scale coding & rotated on the Transform { translation line.
Transform { translation 0 1 0 scale 1 1 1 rotation 1.75 0 0 1.57 children [
Shape { appearance Appearance {
material Material { transparency 0.2 }
texture ImageTexture { url "yourtex.jpg" }}
geometry Extrusion { beginCap TRUE endCap TRUE solid FALSE
crossSection [
0 0, -0.15 0.05, -0.3 -0.1, -0.1 -0.1, 0 0, -0.1 -0.1, 0 -0.3, 0.1 -0.1, 0 0, 0.1 -0.1,
0.3 -0.1, 0.15 0.05, 0 0, 0.15 0.05, 0.2 0.3, 0 0.15, 0 0, 0 0.15, -0.2 0.3, -0.15 0.05, 0 0, ]
spine [ 0 -0.01 0, 0 0.01 0, ]
scale [ 1 1, 1 1, ] }}
]}

Apart from adjusting scale if you so wish, the only other changes you need make here would be placing it in the position you desire, coloring it with material colors instead of texture, & adjusting the thickness of the star using the spine area of the coding. A note with regard to this though - if you are wanting to adjust the thickness, make certain you adjust it around 0 as in the example coding above which is set at -0.01 to 0.01. Doing this will ensure that the object is centered back to front correctly when you are translating it into position. See the star in my 'Santa with Star' object in the club.

You may use this star coding for objects you upload in CTR provided you credit me ( Morning.star ) in your WorldInfo.

  • * * * * * * * * * * * * * * * * * * *

MAKE a HEART!

Transform { translation 0 -1.75 0 children [
Shape { appearance Appearance { material Material { diffuseColor 1 0 0 }}
geometry Extrusion { creaseAngle 2 beginCap FALSE endCap TRUE solid FALSE
crossSection [
0 -0.6, 0.05 -0.65, 0.1 -0.69, 0.15 -0.73, 0.2 -0.76, 0.25 -0.78, 0.3 -0.79,
0.35 -0.795, 0.4 -0.8, 0.45 -0.8, 0.5 -0.79, 0.55 -0.78, 0.6 -0.76, 0.65 -0.74,
0.7 -0.715, 0.75 -0.675, 0.8 -0.62, 0.835 -0.55, 0.855 -0.5, 0.865 -0.45, 0.875 -0.4,
0.875 -0.35, 0.868 -0.3, 0.86 -0.25, 0.84 -0.2, 0.825 -0.149, 0.8 -0.09, 0.75 0,
0.7 0.08, 0.6 0.22, 0.49 0.35, 0 0.85, -0.49 0.35, -0.6 0.22, -0.7 0.08,
-0.75 0, -0.8 -0.09, -0.825 -0.149, -0.84 -0.2, -0.86 -0.25, -0.868 -0.3, -0.875 -0.35,
-0.875 -0.4, -0.865 -0.45, -0.855 -0.5, -0.835 -0.55, -0.8 -0.62, -0.75 -0.675, -0.7 -0.715,
-0.65 -0.74, -0.6 -0.76, -0.55 -0.78, -0.5 -0.79, -0.45 -0.8, -0.4 -0.8, -0.35 -0.795,
-0.3 -0.79, -0.25 -0.78, -0.2 -0.76, -0.15 -0.73, -0.1 -0.69, -0.05 -0.65, 0 -0.6, ]
spine [ 0 0 0, 0 0 0, ]
scale [ 1 1, 1 1, ]}}
]}

You may use this heart coding for objects you upload in CTR provided you credit me ( Morning.star ) in your WorldInfo. See the 'Lucky Shamrock' object in the club for an example a four-leaf clover using a rotated configuration of 4 heart shapes.

Back to top

Written by Morning.star, reproduced unedited and published with her permission. Eleven documents. Morning.star has written many more and they will be added over time; this is not the complete set and does not claim to be.