12,952,124 members (57,978 online)
alternative version

#### Stats

114.8K views
45 bookmarked
Posted 11 Jun 2006

# Generating a sphere-mesh in XAML

, 11 Jun 2006
 Rate this:
This article shows a way how to create a 3D sphere in C# and XAML

## Introduction

A few days ago, I thought it would be funny to play around with WPF's new 3D capabilities. By then, I had only looked at 2D graphics and animations with XAML. Of course, my starting point was MSDN. You can find quite a good introduction in 3D graphics with XAML at MSDN. There is also another article on CodeProject: 3D in XAML, that gives you a good start for 3D in XAML. I will not go into the basics of cameras, meshes, lights, etc. in my article.

I was surprised when I read in MSDN that WPF "does not currently support predefined 3-D primitives like spheres and cubic forms". It gives you the `MeshGeometry3D` class which allows to build any geometry as a list of triangles. Therefore, I decided that my first 3D mini-project in WPF will be an algorithm that generates a mesh that represents a sphere.

Unfortunately, I am no specialist in writing 3D graphics code. Therefore, I decided to implement quite a simple algorithm that generates a sphere from a mesh of triangles: I do quite what the open-source 3D modeler Blender does with its UVSphere mesh:

(Source: Wiki: Grundkörper)

As you can see from the picture above, I split the sphere into segments and rings. The result is a list of squares (that can easily be split into two triangles), and triangles at the top and the bottom. Blender's Icosphere (see Wiki: Ikosaeder (German) for more details) would have been even more suitable for XAML meshes. However, I decided to start with UVSphere.

A sphere is not the only round mesh that can be generated by splitting a circle into segments. Therefore, I decided to write an abstract base class that can also be used for, e.g., a disc (a circle in 3D space):

```using System;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Sphere3D
{
abstract class RoundMesh3D
{
protected int n = 10;
protected int r = 20;
protected Point3DCollection points;
protected Int32Collection triangleIndices;

{
get { return r; }
set { r = value; CalculateGeometry(); }
}

public virtual int Separators
{
get { return n; }
set { n = value; CalculateGeometry(); }
}

public Point3DCollection Points
{
get { return points; }
}

public Int32Collection TriangleIndices
{
get { return triangleIndices; }
}

protected abstract void CalculateGeometry();
}
}```

`r` stands for the radius of the mesh, and `n` stands for the number of segments into which I split the circle (4*n+4 is the number of points that I equally distribute on the circle).

My first test was the implementation of a disc. Here is the code. It is not very complex, just some trigonometric functions:

```using System;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Diagnostics;

namespace Sphere3D
{
class DiscGeometry3D : RoundMesh3D
{
protected override void  CalculateGeometry()
{
int numberOfSeparators = 4 * n + 4;

points = new Point3DCollection(numberOfSeparators + 1);
triangleIndices = new Int32Collection((numberOfSeparators + 1) * 3);

for (int divider = 0; divider < numberOfSeparators; divider++)
{
double alpha = Math.PI / 2 / (n + 1) * divider;
0, -1 * r * Math.Sin(alpha)));

(numberOfSeparators-1)) ? 1 : (divider + 2));
}
}

public DiscGeometry3D()
{ }
}
}```

The code for generating the sphere is a little bit longer. Distributing the points on the sphere is the simple part. I found it harder to generate the triangles correctly:

```using System;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Diagnostics;

namespace Sphere3D
{
class SphereGeometry3D : RoundMesh3D
{
protected override void CalculateGeometry()
{
int e;
double segmentRad = Math.PI / 2 / (n + 1);
int numberOfSeparators = 4 * n + 4;

points = new Point3DCollection();
triangleIndices = new Int32Collection();

for (e = -n; e <= n; e++)
{
double r_e = r * Math.Cos(segmentRad * e);
double y_e = r * Math.Sin(segmentRad * e);

for (int s = 0; s <= (numberOfSeparators - 1); s++)
{
double z_s = r_e * Math.Sin(segmentRad * s) * (-1);
double x_s = r_e * Math.Cos(segmentRad * s);
}
}
points.Add(new Point3D(0, -1 * r, 0));

for (e = 0; e < 2 * n; e++)
{
for (int i = 0; i < numberOfSeparators; i++)
{
triangleIndices.Add(e * numberOfSeparators + i +
numberOfSeparators);
triangleIndices.Add(e * numberOfSeparators + (i + 1) %
numberOfSeparators + numberOfSeparators);

triangleIndices.Add(e * numberOfSeparators + (i + 1) %
numberOfSeparators + numberOfSeparators);
(i + 1) % numberOfSeparators);
}
}

for (int i = 0; i < numberOfSeparators; i++)
{
triangleIndices.Add(e * numberOfSeparators + (i + 1) %
numberOfSeparators);
triangleIndices.Add(numberOfSeparators * (2 * n + 1));
}

for (int i = 0; i < numberOfSeparators; i++)
{
triangleIndices.Add(numberOfSeparators * (2 * n + 1) + 1);
}
}

public SphereGeometry3D()
{ }
}
}```

For my sample, I wanted to display two spheres and a nice picture in the background (see the image at the top of the article). Therefore, I decided to create two descendent classes from `SphereGeometry3D`:

```namespace Sphere3D
{
class BigPlanet : SphereGeometry3D
{
BigPlanet()
{
Separators = 5;
}
}

class SmallPlanet : SphereGeometry3D
{
SmallPlanet()
{
Separators = 5;
}
}
}```

Finally, I used XAML's data binding mechanisms to bind the properties `Positions` and `TriangleIndices` of `MeshGeometry3D` to the algorithms shown above:

```<Window x:Class="Sphere3D.Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:Sphere3D"

Title="Labyrinth3d" Height="600" Width="600"

>
<Window.Background>
<ImageBrush Stretch="UniformToFill"

</Window.Background>
<Grid VerticalAlignment="Stretch"

HorizontalAlignment="Stretch" x:Name="Grid1">
<Grid.Resources>
<local:BigPlanet x:Key="SphereGeometrySource1"/>
<local:SmallPlanet x:Key="SphereGeometrySource2"/>
<MeshGeometry3D x:Key="SphereGeometry1"

Positions="{Binding Source={StaticResource
SphereGeometrySource1}, Path=Points}"

TriangleIndices="{Binding Source={StaticResource
SphereGeometrySource1},
Path=TriangleIndices}"/>
<MeshGeometry3D x:Key="SphereGeometry2"

Positions="{Binding Source={StaticResource
SphereGeometrySource2}, Path=Points}"

TriangleIndices="{Binding Source={StaticResource
SphereGeometrySource2},
Path=TriangleIndices}"/>
</Grid.Resources>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>

<Viewport3D Grid.Column="1" Grid.Row="1"

VerticalAlignment="Stretch"

HorizontalAlignment="Stretch" Name="Viewport1">

<Viewport3D.Camera>
<PerspectiveCamera x:Name="myCamera" Position="100 30 0"

LookDirection="-50 -33 0"

UpDirection="0,1,0" FieldOfView="90"/>
<!--<OrthographicCamera x:Name="myCamera"
Position="200 0 0" LookDirection="-1 0 0"
Width="180" UpDirection="0,1,0"/>-->
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<DirectionalLight Color="#FFFFFF"

Direction="0 -30 0" />
<DirectionalLight Color="#FFFFFF"

Direction="0 +30 0" />
<GeometryModel3D

Geometry="{StaticResource SphereGeometry1}">
<GeometryModel3D.Material>
<MaterialGroup>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Orange"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</MaterialGroup>
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D

Geometry="{StaticResource SphereGeometry2}">
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Yellow"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.Transform>
<TranslateTransform3D

x:Name="Sphere2Translation" OffsetZ="50" />
</GeometryModel3D.Transform>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</Window>```

If my implementation of the 3D sphere for XAML is helpful for you, I would be happy if you could vote for my article here at CodeProject. If you have questions, feel free to send me an email.

A list of licenses authors might use can be found here

## Share

 software architects Austria
Hi, my name is Rainer Stropek. I am living a small city named Traun in Austria. Since 1993 I have worked as a developer and IT consultant focusing on building database oriented solutions. After being a freelancer for more than six years I founded a small IT consulting company together with some partners in 1999. In 2007 my friend Karin and I decided that we wanted to build a business based on COTS (component off-the-shelf) software. As a result we founded "software architects" and developed the time tracking software "time cockpit" (http://www.timecockpit.com). If you want to know more about our companies check out my blogs at http://www.software-architects.com and http://www.timecockpit.com or take a look at my profile in XING (http://www.openbc.com/hp/Rainer_Stropek2/).

I graduated the Higher Technical School for MIS at Leonding (A) in 1993. After that I started to study MIS at the Johannes Kepler University Linz (A). Unfortunately I had to stop my study because at that time it was incompatible with my work. In 2005 I finally finished my BSc (Hons) in Computing at the University of Derby (UK). Currently I focus on IT consulting, development, training and giving speeches in the area of .NET and WPF, SQL Server and Data Warehousing.

## You may also be interested in...

 First Prev Next
 How to add the sphere dynamically? Kronass21-Oct-10 9:47 Kronass 21-Oct-10 9:47
 Smooth ? Xmen W.K.23-Jun-10 14:35 Xmen W.K. 23-Jun-10 14:35
 License icetea9412-May-09 7:53 icetea94 12-May-09 7:53
 Re: License Zlotto11-Sep-09 5:35 Zlotto 11-Sep-09 5:35
 Re: License icetea9411-Sep-09 7:12 icetea94 11-Sep-09 7:12
 Yes, I know. An for this reason I tried to contact the autor via the "discussion board below". - icetea
 Backface culling bug GuinnessKMF8-May-09 9:13 GuinnessKMF 8-May-09 9:13
 Wishing I paid more attention in geometry class.... dosborn2783-Mar-09 14:51 dosborn278 3-Mar-09 14:51
 Re: Wishing I paid more attention in geometry class.... GuinnessKMF8-May-09 5:40 GuinnessKMF 8-May-09 5:40
 Great Josh Smith30-Aug-06 6:05 Josh Smith 30-Aug-06 6:05
 Re: Great PaulC197217-Nov-06 11:52 PaulC1972 17-Nov-06 11:52
 Cannot compile Claton13-Jun-06 4:07 Claton 13-Jun-06 4:07
 Re: Cannot compile r.stropek13-Jun-06 4:12 r.stropek 13-Jun-06 4:12
 Re: Cannot compile Claton13-Jun-06 4:15 Claton 13-Jun-06 4:15
 Re: Cannot compile r.stropek13-Jun-06 4:37 r.stropek 13-Jun-06 4:37
 Re: Cannot compile Behind The Scene18-Nov-06 2:53 Behind The Scene 18-Nov-06 2:53
 Last Visit: 31-Dec-99 18:00     Last Update: 26-May-17 15:37 Refresh 1