# Building A Cylinder

First a bit of theory (First I am going to bore you to death and then I am going to give you the code )

You can generate any geometric primitive or surface that can be mathematically
described (cube, cone, pyramid, torus, cylinder, sphere ... ). If the shape you want
can not be parameterized (i.e. Doom 3 character) you’ll need something like 3DMax
or Milkshape (or even better, create your own 3D modeler ).

## Primitive Types

With TV3D / DirectX you can create several different primitive types

• TV_TRIANGLESTRIP
• TV_TRIANGLELIST
• TV_LINELIST
• TV_LINESTRIP
• TV_POINTLIST
• TRIANGLE_FAN - Not available in TV6.2 (You’ll have to wait for TV6.5)

First two are obviously good for solid geometry creation.

TV_TRIANGLELIST is good for creating faceted surfaces
since each triangle has 3 unique vertices and 3 unique normal vectors.

TV_TRIANGLESTRIP is good for creating smooth surfaces since DirectX treats
triangle list as one large polygon with multiple triangles.
It also uses fewer vertices.

There are benefits to using one over another, but I am not going to get into that.

## Building The Geometry

Look at the cylinder below. If you cut it along the red line and open it up,
you get a very simple rectangle. That rectangle/polygon is very similar to
above definition of triangle strip. A third picture below applies the triangle
strip to the rectangle.

Just make sure vertices are added in a clockwise order (i.e. V1 → V2 → V3).
Now, the tricky part is to do all this while going in a circle. This is where cylinder
parametric equations come in handy.

Cylinder Parametric equations:

X=R*COS(Theta)
Y=Y
Z=R*SIN(Theta)

Or in our case:

X=R*COS(Theta)
Y=H
Z=R*SIN(Theta)

H - Height
Theta - Angular increment (from 0 - 360 deg or 0 - 2PI rad)

### The Code (Visual Basic 6)

```Public Sub Cylinder(Radius As Single, Height As Single, Sides As Single)

Dim Theta As Single 'Current Angle
Dim Inc As Single 'Angular increment
Dim x As Single 'x coord
Dim y As Single 'y coord
Dim z As Single 'z coord
Dim i As Integer

Mesh.SetPrimitiveType TV_TRIANGLESTRIP

'Cylinder Precision
Inc = 2 * PI_ / Sides 'where each side has two triangles

Theta = 0

For i = 0 To Sides

'Calculate Vertices
y = Height

'Vertex at the top of the cylinder
Mesh.AddVertex x, 0, z, 0, 0, 0
'Vertex at the bottom of the cylinder
Mesh.AddVertex x, y, z, 0, 0, 0

Theta = Theta + Inc

Next

End Sub```

Run the above code using the following parameters
Cylinder (40, 40, 30)
30 sides give us 30*2 triangles and 30*2 + 2 vertices

This is what you get:

You can not really see anything since we did not generate any normals.
Switch to wireframe to get a better view ( Scene.SetRenderMode TV_LINE )

## Calculating Normals

Normals are unit vectors that define the angle between the surface and the light.
Look at the picture below for the cylinder normals.
First drawing shows the side view.
To get a nice light on your cylinders surface normals should be perpendicular
to that surface. Second drawing shows the top view.
If you want the edges to disappear you have to tell your light to bounce
directly off the edge(s).

Keep in mind one thing, vertex normals are not really on the vertex like the
image above shows.In the image below there are 3 identical vectors where
the blue one is the “real" normal vector.

Obviously, normal vectors (normals) for vertices on top of the cylinder
are identical to the ones at the bottom (you cut normals calculations by 50%).

The same deal for the top view. Red normal vectors are just representations
of real normal vectors (blue).

Back to coding.
As you can see in the above images normals have exactly the same
cords as the vertices (minus the y coord).

N.x = X = R*COS(Theta)
N.y = Y = 0
N.z = Z = R*SIN(Theta)

### The Code (Visual Basic 6)

```Public Sub Cylinder(Radius As Single, Height As Single, Sides As Single)

Dim Theta As Single 'Current Angle
Dim Inc As Single 'Angular increment
Dim x As Single 'x coord
Dim y As Single 'y coord
Dim z As Single 'z coord
Dim i As Integer
Dim n As D3DVECTOR 'vertex normal

Mesh.SetPrimitiveType TV_TRIANGLESTRIP

'Cylinder Precision
Inc = 2 * PI_ / Sides 'where each side has two triangles

Theta = 0

For i = 0 To Sides

'Calculate Vertices
y = Height

'Make sure you normalize vertex cords to get proper normals
TVVec3Normalize n, Vector(x, 0, z)

'Vertex at the top of the cylinder
Mesh.AddVertex x, 0, z, 0, 0, 0, n.x, n.y, n.z
'Vertex at the bottom of the cylinder
Mesh.AddVertex x, y, z, 0, 0, 0, n.x, n.y, n.z

Theta = Theta + Inc

Next

End Sub```

Run the above code using the same parameters again
Cylinder (40, 40, 30)

This is what you get:

There is lot of different ways to calculate vertex normals. This one
seems to be good for the cylinder.
My explanations here are not particularly good nor in depth. You have
2 links below, where people did a much better job.

## Applying Texture

Now that you have a “good looking” cylinder it is time to apply
a texture to it (to make it even better looking ).
To apply texture you’ll have to figure out the UV coordinates.

```U and V coordinates are just a way to talk about which pixel should be used in a
texture map, independent of how big the texture map finally turns out to be.
If U and V are 0.25 and 0.5 for a given vertex in your model, and the texture
map is 512 by 512, the pixel at 128,256 will be applied to the vertex
```

In general, UV coordinates range between 0 and 1.
See the sample image below.

What UV (1, 1) really means is UV (100% of texture width, 100% of texture height)
or UV (0.5, 1) really means is UV (50% of texture width, 100% of texture height).

So, in the case of cylinder we open it up again to get a rectangle.

UV1=UV(0,0)
UV2=UV(0,1)
UV3=UV(1,1)
UV4=UV(1,0)

This is fine except we have applied UV cords to corner vertices only.
Next image shows triangle strip applied to textured rectangle.
There are 12 vertices (6 on top and 6 on bottom),
10 triangles and 5 sides (2 triangles per side).
6 vertices (top and bottom) are evenly spaced,
so the step between U cords is 1/Sides = 1/5.

...and once again the code:

### The Code (Visual Basic 6)

```Public Sub Cylinder(Radius As Single, Height As Single, Sides As Single)

Dim Theta As Single 'Current Angle
Dim Inc As Single 'Angular increment
Dim x As Single 'x coord
Dim y As Single 'y coord
Dim z As Single 'z coord
Dim i As Integer
Dim n As D3DVECTOR 'vertex normal
Dim tu As Single 'U coord
Dim tv As Single 'V coord
Dim UStep As Single 'step between U coords

Mesh.SetPrimitiveType TV_TRIANGLESTRIP

'Cylinder Precision
Inc = 2 * PI_ / Sides 'where each side has two triangles

Theta = 0 'Initial value

UStep = 1 / Sides

tu = 0 'Initial value

For i = 0 To Sides

'Calculate Vertices
y = Height

'Make sure you normalize vertex cords to get proper normals
TVVec3Normalize n, Vector(x, 0, z)

'Vertex at the top of the cylinder
'tv value is always 1for top vertices
Mesh.AddVertex x, 0, z, 0, tu, 1, n.x, n.y, n.z

'Vertex at the bottom of the cylinder
'tv value is always 0 for bottom vertices
Mesh.AddVertex x, y, z, 0, tu, 0, n.x, n.y, n.z

Theta = Theta + Inc

tu = tu + UStep

Next

End Sub```

Run the above code (once again) using the same parameters Cylinder (40, 40, 30)

This is what you get:

It is good idea to use checkered texture to verify texture coordinates, since it would be very easy to spot deformed squares.

## Tweaking Texture(UV) Coordinates

There is one problem with texture we applied in previous chapter.
Texture looks blurry and stretched.
The reason for is that we applied perfectly square texture to a rectangle.

Modify the previous code by replacing

`tu = tu + UStep`

with

`tu = tu + UStep*2`

and run it again.

The end result:

It looks a lot better then before.

By multiplying UStep by two you have doubled UV coordinates of
the rectangle (cylinder) and effectively forced tiling of your texture.

The same way, if you use

`tu = tu + UStep*4`

you will force 4 texture tiling in U direction.

New result:

Checkered texture is nice to verify texture coordinates,
but it can not show effect of tiling.
Use this texture to see UV manipulation effects.

With Original code:
One texture wrapped around

With

`tu = tu + UStep*4`

Four textures wrapped around

You are not limited to just one dimensional tiling
Do these modifications

`tu = tu + UStep*10`

and (replace tv value of 1 with 2)

`Mesh.AddVertex x, 0, z, 0, tu, 2, n.x, n.y, n.z`

This results in 2×10 texture tiling:

To make this cylinder complete it would be good idea to close it up or add
caps to top and bottom.

## Building The Geometry

Ok, it is time to cut the cylinder along the red lines and open it up.
This time cut results in two circles and the rectangle.
Last picture below applies the triangle strip to the rectangle and circles.

Vertex numbers are added to the triangle strip just to show how vertices are
shared between two circles and the rectangle.
The mesh is divided into three regions Bottom Cap, Cylinder and Top Cap,
and these regions are going to be rendered in that order.
As usual we have to make sure vertices are added in clockwise order.
Parametric equations stay unchanged as well, since both, top and bottom
caps share cylindrical mesh vertices.

X=R*COS(Theta)
Y=H
Z=R*SIN(Theta)

At this point its a good idea to look at the Bottom Cap triangle strip
and figure out the algorithm.
The image shows Bottom cap in terms of angular increment theta.
There are two approaches

1. Theta 0 to 360 deg
2. Theta -180 to 0 to 180 deg

First approach algorithm would look something like this:

``` V1 @   0 deg
V2 @  45 deg
V8 @ 315 deg
V3 @  90 deg
V7 @ 270 deg
...```

Second approach algorithm:

``` V1 @   0 deg
V2 @  45 deg
V8 @ -45 deg
V3 @  90 deg
V7 @ -90 deg
...```

Both approaches are mathematically identical
i.e.

``` For V8 @ 315 deg COS(315) = 0.707
For V8 @ -45 deg COS(-45) = 0.707```

Second one looks more manageable (just a personal preference), feel free to play with different approaches.

Time to code ### The Code (Visual Basic 6)

```Public Sub Cylinder(Radius As Single, Height As Single, Sides As Single)

Dim Theta As Single 'Current Angle
Dim Inc As Single 'Angular increment
Dim x As Single 'x coord
Dim y As Single 'y coord
Dim z As Single 'z coord
Dim i As Integer
Dim n As D3DVECTOR 'vertex normal
Dim tu As Single 'U coord
Dim tv As Single 'V coord
Dim UStep As Single 'step between U coords
Dim Sign As Integer 'a flag to indicate theta sign change

Mesh.SetPrimitiveType TV_TRIANGLESTRIP

'Cylinder Precision
Inc = 2 * PI_ / Sides 'where each side has two triangles

Theta = 0 'Initial value

UStep = 1 / Sides

tu = 0 'Initial value

'Bottom Cap

Sign = -1

For i = 1 To Sides 'Draw The Bottom Cap Loop

'Calculate vertices
x = Radius * Cos(Sign * Theta)
y = 0
z = Radius * Sin(Sign * Theta)

Mesh.AddVertex x, 0, z, 0, 0, 0, 0, 0, 0

If Sign = 1 Then

'Change the sign
Sign = -1

ElseIf Sign = -1 Then

'Change the sign
Sign = 1

'Increment theta for the next loop
Theta = Theta + Inc

End If

Next

'The Cylinder

'At this point it is important not to reset theta to zero
'even though at the end of the following loop accumulated theta
'will equal 3PI
'See the "NOTE 1" below

'Original code from "Building A Cylinder"
'Including vertex normals and texture coordinates

tu = 0 'Initial value

For i = 0 To Sides 'Draw The Cylinder Loop

'Calculate Vertices
y = Height

'Make sure you normalize vertex cords to get proper normals
TVVec3Normalize n, Vector(x, 0, z)

'Vertex at the top of the cylinder
Mesh.AddVertex x, 0, z, 0, tu, 2, n.x, n.y, n.z

'Vertex at the bottom of the cylinder
Mesh.AddVertex x, y, z, 0, tu, 0, n.x, n.y, n.z

Theta = Theta + Inc

tu = tu + UStep * 10

Next

End Sub```
```NOTE 1:
Look at FIGURE No.3. When drawing the Bottom Cap triangle strip, last vertex
drawn is vertex V5 (V1->V2->V8->V3->V7->V4->V6->V5).
This last vertex V5 is drawn at the angle Theta = 180 deg.
To keep the triangle strip flow continuous it is necessary to start the "Cylindrical"
triangle strip where the "Bottom Cap" triangle strip left off, at Theta = 180 deg.
Nothing changes mathematically. It is absolutely the same to go from 0 to 2PI
(as in previous tutorial) or from PI to 3PI (as long as you complete the full
circle of 360 deg or 2PI rad).
The same way, we will have to start drawing the "Top Cap" triangle strip where
"Cylindrical" triangle strip stopped ... but more on that later.
```

Run the above code as Cylinder (40, 40, 30)

This is what we get:

Of course, bottom cap is black because we have no vertex normals defined.

## Calculating Normals

Look at the cylinder side view image below. To get proper light for
Top and Bottom caps it is important that normals are perpendicular
to their surface.
It is obvious from the image below that all normals for the Top cap
are identical. The same goes for the Bottom cap.
Top Cap normals point in positive Y Axis direction and Bottom Cap
normals point in negative Y Axis direction.

FIGURE No. 5

There is no need for normal calculations and normalization here.
Top cap normals are all unit vectors:

`Vector(0,1,0)`

and Bottom cap normals are all unit vectors:

`Vector(0,-1,0)`

By replacing (in Draw The Bottom Cap Loop )

`Mesh.AddVertex x, 0, z, 0, 0, 0, 0, 0, 0`

with

`Mesh.AddVertex x, 0, z, 0, 0, 0, 0, -1, 0`

we get:

## Back To Geometry

Ok, at this point we have Bottom Cap and the Cylindrical body.
Its time for the Top Cap So far the code did something like this (in simplified pseudocode):

Program Start
Theta = 0
Calculate Bottom Cap Vertices (Start at Theta=0)
Theta = PI (180 deg)
Calculate Cylindrical Body Vertices (Start at Theta=PI)
Theta = 3*PI (540 deg)

Based on previous logic (Note 1) we would expect to continue like this

Calculate Top Cap Vertices (Start at Theta=3*PI)
Program End

Well ... starting Top Cap from 540 deg (3PI) just does not sound
very nice or clean (see FIGURE No. 7).

This looks quite ugly Since we are dealing with circles and angles here its time to use
trigonometry to our advantage As far as a full circle is concerned trigonometry does not care for
how many times we went around that circle.
Simply put, we start removing full circles (360 deg) from our starting 540 deg

we ended up with:

540-360=180

this is where we stop since 180 deg is half a circle
(no more full circles to remove)

Same calculation in terms of radians where 2PI is a full circle:

3PI-2PI=PI

we stop again since PI is half circle.

Now, to see that in world of Trigonometry 540⇔180 are “equivalent”
we can do this:

COS(540)=-1
COS(180)=-1

Well, looks the same to me So, we have removed one full circle from our starting 540 deg Theta
and ended up with a new staring angle Theta=180 deg.
We do the same thing for all incremental Thetas in FIGURE No. 7

This is what we end up with:

I am going to make a leap of faith here and replace V8 theta of
495 with -225. Quick check:

COS(495)=-0.707
COS(-255)=0.707

Looks fine Following the same logic we get this:

Another way to look at it:

FIGURE No. 9 is the one I like (just a matter of personal preference).
FIgures 7, 8, 10 are also valid, as long as you figure out the proper algorithm.

There is really only one important thing here:
How we go around the circle from that point is up to us.

Enough BS, its time to code again ### The Code (Visual Basic 6)

```Public Sub Cylinder(Radius As Single, Height As Single, Sides As Single)

Dim Theta As Single 'Current Angle
Dim Inc As Single 'Angular increment
Dim x As Single 'x coord
Dim y As Single 'y coord
Dim z As Single 'z coord
Dim i As Integer
Dim n As D3DVECTOR 'vertex normal
Dim tu As Single 'U coord
Dim tv As Single 'V coord
Dim UStep As Single 'step between U coords
Dim Sign As Integer 'a flag to indicate theta sign change

Mesh.SetPrimitiveType TV_TRIANGLESTRIP

'Cylinder Precision
Inc = 2 * PI_ / Sides 'where each side has two triangles

Theta = 0 'Initial value

UStep = 1 / Sides

tu = 0 'Initial value

'Bottom Cap

Sign = -1

For i = 1 To Sides 'Draw The Bottom Cap Loop

'Calculate vertices
x = Radius * Cos(Sign * Theta)
y = 0
z = Radius * Sin(Sign * Theta)

Mesh.AddVertex x, 0, z, 0, 0, 0, 0, -1, 0

If Sign = 1 Then

'Change the sign
Sign = -1

ElseIf Sign = -1 Then

'Change the sign
Sign = 1

'Increment theta for the next loop
Theta = Theta + Inc

End If

Next

'The Cylinder

'At this point it is important not to reset theta to zero
'even though at the end of the following loop accumulated theta
'will equal 3PI
'See the "NOTE 1" below

'Original code from "Building A Cylinder"
'Including vertex normals and texture coordinates

tu = 0 'Initial value

For i = 0 To Sides 'Draw The Cylinder Loop

'Calculate Vertices
y = Height

'Make sure you normalize vertex cords to get proper normals
TVVec3Normalize n, Vector(x, 0, z)

'Vertex at the top of the cylinder
Mesh.AddVertex x, 0, z, 0, tu, 2, n.x, n.y, n.z

'Vertex at the bottom of the cylinder
Mesh.AddVertex x, y, z, 0, tu, 0, n.x, n.y, n.z

Theta = Theta + Inc

tu = tu + UStep * 10

Next

'The Top Cap

Theta = PI_
Sign = 1

For i = 1 To Sides 'Draw The Top Cap Loop

'Calculate vertices
x = Radius * Cos(Sign * Theta)
y = Height
z = Radius * Sin(Sign * Theta)

'All Vertex Normals equal to +1 in Y axis direction

Mesh.AddVertex x, y, z, 0, 0, 0, 0, 1, 0

If Sign = 1 Then

'Change the sign
Sign = -1

'Increment theta for the next loop
Theta = Theta + Inc

ElseIf Sign = -1 Then

'Change the sign
Sign = 1

End If

Next

End Sub```

Run the above code as Cylinder (40, 40, 30)

This is what we get:

With checkered Texture FIGURE No. 11

One thing we are missing here are cap textures.

## Applying Cap Texture

Bottom and Top Caps are basically a 2D circle.
Parametric equation of circle in a Cartesian coordinate system is (Circle):

X=R*COS (Theta)
Y=R*SIN (Theta)

for a circle with center in origin x=0 and y=0.

Similarly, parametric equation of circle in a “texture world”
or UV coordinate system is :

U=R*COS (Theta)
V=R*SIN (Theta)

for a circle with center in origin U=0 and V=0.

Knowing that UV coordinates range between 0 and 1
we need a “unit circle” (Circle with diameter D=1).

Next image shows the inscribed Unit Circle (D=1 and R=D/2=0.5).

Now, if we want our caps to show the texture exactly as it appears
in FIGURE No. 14 we need to adjust the above equations.
The problem is that our circle center is not in the origin (0,0).
Circle center is offset by R in U and V direction (see NOTE 2).

The problem is solved by rewriting the equations as:

U=R*COS(Theta)+R
V=R*SIN(Theta)+R

or

U=0.5*COS(Theta)+0.5
V=0.5*SIN(Theta)+0.5

or in code

```tu = 0.5 * Cos(Sign * Theta) + 0.5
tv = 0.5 * Sin(Sign * Theta) + 0.5```
```NOTE 2:
Even without adding these offsets, the texture would be applied nicely.
Its just that we would not get the desired effect (FIGURE No.14).
```

### The Code (Visual Basic 6)

```Public Sub Cylinder(Radius As Single, Height As Single, Sides As Single)

Dim Theta As Single 'Current Angle
Dim Inc As Single 'Angular increment
Dim x As Single 'x coord
Dim y As Single 'y coord
Dim z As Single 'z coord
Dim i As Integer
Dim n As D3DVECTOR 'vertex normal
Dim tu As Single 'U coord
Dim tv As Single 'V coord
Dim UStep As Single 'step between U coords
Dim Sign As Integer 'a flag to indicate theta sign change

Mesh.SetPrimitiveType TV_TRIANGLESTRIP

'Cylinder Precision
Inc = 2 * PI_ / Sides 'where each side has two triangles

Theta = 0 'Initial value

UStep = 1 / Sides

tu = 0 'Initial value

'Bottom Cap

Sign = -1

For i = 1 To Sides 'Draw The Bottom Cap Loop

'Calculate vertices
x = Radius * Cos(Sign * Theta)
y = 0
z = Radius * Sin(Sign * Theta)

tu = 0.5 * Cos(Sign * Theta) + 0.5
tv = 0.5 * Sin(Sign * Theta) + 0.5

Mesh.AddVertex x, 0, z, 0, tu, tv, 0, -1, 0

If Sign = 1 Then

'Change the sign
Sign = -1

ElseIf Sign = -1 Then

'Change the sign
Sign = 1

'Increment theta for the next loop
Theta = Theta + Inc

End If

Next

'The Cylinder

'At this point it is important not to reset theta to zero
'even though at the end of the following loop accumulated theta
'will equal 3PI
'See the "NOTE 1" bellow

'Original code from "Building A Cylinder"
'Including vertex normals and texture coordinates

tu = 0 'Initial value

For i = 0 To Sides 'Draw The Cylinder Loop

'Calculate Vertices
y = Height

'Make sure you normalize vertex cords to get proper normals
TVVec3Normalize n, Vector(x, 0, z)

'Vertex at the top of the cylinder
Mesh.AddVertex x, 0, z, 0, tu, 2, n.x, n.y, n.z

'Vertex at the bottom of the cylinder
Mesh.AddVertex x, y, z, 0, tu, 0, n.x, n.y, n.z

Theta = Theta + Inc

tu = tu + UStep * 10

Next

'The Top Cap

Theta = PI_
Sign = 1

For i = 1 To Sides 'Draw The Top Cap Loop

'Calculate vertices
x = Radius * Cos(Sign * Theta)
y = Height
z = Radius * Sin(Sign * Theta)

tu = 0.5 * Cos(Sign * Theta) + 0.5
tv = 0.5 * Sin(Sign * Theta) + 0.5

'All Vertex Normals equal to +1 in Y axis direction
Mesh.AddVertex x, y, z, 0, tu, tv, 0, 1, 0

If Sign = 1 Then

'Change the sign
Sign = -1

'Increment theta for the next loop
Theta = Theta + Inc

ElseIf Sign = -1 Then

'Change the sign
Sign = 1

End If

Next

End Sub```

As usual, run the code as Cylinder(40,40,30).

Bottom Cap result:

Bottom cap looks fine.

Top Cap result:

Well, Top cap is “fine” but mirrored.
There is a reason for a mirrored texture (believe it or not )

The main reason is the identical code we use for both, the bottom cap and the top cap.

```tu = 0.5 * Cos(Sign * Theta) + 0.5
tv = 0.5 * Sin(Sign * Theta) + 0.5```

Look at the three steps in FIGURE No. 17 (Bottom Cap View) .
Second step shows texture applied to the bottom cap, and that looks fine.
Now, if you use the same code for the top cap, you basically take the bottom
cap texture and “translate” it to the top cap along the cylinder height(step 3).

To make this even more clear, look at the same three steps from a different
perspective (Top Cap View FIGURE No. 18).

There is your mirrored texture view, right there at step 3.

Ok, hopefully this last explanation made sense .

Fixing this mirrored/flipped texture is quite easy.
All you have to do is make your U OR V coordinate negative.
Make sure you do not change both coordinates to negative values.
Changing U=-U and V=-V will still give you mirrored texture.

New code for Top Cap:

```tu = -(0.5 * Cos(Sign * Theta) + 0.5)
tv = 0.5 * Sin(Sign * Theta) + 0.5```

Make this change and run the code.

Everything should work fine now, except I do not like that
single large texture applied to top and bottom cap .

Its time to tile the texture .
Tiling is very easy:
All you have to do is increase the size of the Unit Circle.
You increase the circle size by increasing its radius.
Lets say we want 3×3 tiling:

For Bottom Cap:

```tu = 0.5 * 3 * Cos(Sign * Theta) + 0.5
tv = 0.5 * 3 * Sin(Sign * Theta) + 0.5```

For Top Cap:

```tu = -(0.5 * 3 * Cos(Sign * Theta) + 0.5)
tv = 0.5 * 3 * Sin(Sign * Theta) + 0.5```

Insert this code to get:

Or for better view:

## The End

Keep in mind that this is far from “good” and “optimized” code.
This code will work if you have your application setup correctly
Textures, materials, lights ... (see Getting Started Tutorials)

If you have questions, suggestions, comments ... etc, you can PM me (Vuli)
on TrueVision3D forum TrueVision3D Forum

Have fun 