Simple Grid Rendering

1. ## Simple Grid Rendering

Hi there, I need to render a simple 50x50 grid / table, each cell in the
table should highlight when the mouse is hovering over it.
The hard part is: I really need to be able to tilt the grid, within the 3D
world.... I hear the Viewport would support the 3D view - but how can I
render the grid within the Viewport?

Kristan

My System Specs

2. ## Re: Simple Grid Rendering

Hi Kristan,
i ran into a similar problem. since everything is triangles in 3D, there is
no 'line' as such. there is a class called ScreenSpaceLine3D which you can
find online, but it didn't really work for me so i rolled my own.
essentially i created a very long and thin cuboid, to effect a grid. here
is a bunch of code i use in my hobby app attempting to create a 3d modelling
tool to help with construction projects. i use the TrackBall class to allow
3d fly/zoom around the world. there are a few helper methods to help with
the 3d objects. i can mail you the whole thing if you want.
good luck
tim

double scale = .05; // i use mm measurements and this is a useful scale,
e.g. to render a 1500mm square on screen
void mmSceneDrawGrid_Click(object sender, RoutedEventArgs e)
{
double thick = .03;
double outsideThickFactor = 5;
double len = 2000 * scale;
double size = 5; // number of parellel lines in one side of the
grid
Color c = Colors.Red;
double interval = len / size;

for (int i = 0; i <= size; i++)
{
for (int j = 0; j <= size; j++)
{
// convert the loop iterators into the required grid cell size
interval, relative to len
double a = i * interval;
double b = j * interval;

// draw all the lines in the x-direction, size x size all starting at
0x, moving to 'len' for each y, for each z
this.CreateLine(new Point3D(0, a, b), new Point3D(len, a, b), thick *
((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
c);
// draw all the lines in the y-direction, size x size all starting at
0y, moving to 'len' for each x, for each z
this.CreateLine(new Point3D(a, 0, b), new Point3D(a, len, b), thick *
((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
c);
// draw all the lines in the z-direction, size x size all starting at
0z, moving to 'len' for each x, for each y
this.CreateLine(new Point3D(a, b, 0), new Point3D(a, b, len), thick *
((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
c);
}
}
}

private Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D p2,
Color c)
{
MeshGeometry3D mesh = new MeshGeometry3D();
Vector3D normal = CalculateNormal(p0, p1, p2);
Material material = new DiffuseMaterial(new SolidColorBrush(c));
GeometryModel3D model = new GeometryModel3D(mesh, material);
Model3DGroup group = new Model3DGroup();

return group;
}

private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
Vector3D v0 = new Vector3D(
p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
Vector3D v1 = new Vector3D(
p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}

private void CreateLine(Point3D a, Point3D b, double t, Color c)
{
Model3DGroup cube = new Model3DGroup();
Point3D p0 = new Point3D(a.X, a.Y, a.Z);
Point3D p1 = new Point3D(a.X + t, a.Y, a.Z);
Point3D p2 = new Point3D(b.X + t, b.Y, b.Z);
Point3D p3 = new Point3D(b.X, b.Y, b.Z);
Point3D p4 = new Point3D(a.X, a.Y + t, a.Z);
Point3D p5 = new Point3D(a.X + t, a.Y + t, a.Z);
Point3D p6 = new Point3D(b.X + t, b.Y + t, b.Z);
Point3D p7 = new Point3D(b.X, b.Y + t, b.Z);
//front side triangles
//right side triangles
//back side triangles
//left side triangles
//top side triangles
//bottom side triangles

ModelVisual3D model = new ModelVisual3D();
model.Content = cube;
}

"Kristan" <kristan@NOSPAMhotmail.co.uk> wrote in message
news:484580AC-A26F-45F2-8698-5A5D9AEE3F01@microsoft.com...
> Hi there, I need to render a simple 50x50 grid / table, each cell in the
> table should highlight when the mouse is hovering over it.
> The hard part is: I really need to be able to tilt the grid, within the
> 3D world.... I hear the Viewport would support the 3D view - but how can I
> render the grid within the Viewport?
>
> Any advice would be great!
> Kristan
>

My System Specs

3. ## Re: Simple Grid Rendering

Hi there, I had a go at using the code, with the following XAML

<Window x:Class="WindowsApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication4" Height="418" Width="626"
>

<Grid>
<Button Width="100" Height="100" Name="mmSceneDrawGrid"
Click="mmSceneDrawGrid_Click" HorizontalAlignment="Left"
Margin="86,44.5,0,0" VerticalAlignment="Top">Hello, XAML!</Button>
<Viewport3D Name="mainViewport"></Viewport3D>
</Grid>

</Window>

The mmSceneDrawGrid_Click() handler does execute, but nothing is rendered
onto the screen... hmmmm any ideas what I might be doing wrong?

It would be good to get something showing up - then it'll be easier to play
with it and work everything out!

thanks,
Kristan

"Tim Mackey" <tim.mackey@community.nospam> wrote in message
news:4EA9968D-61E1-4E45-808E-4AE8E95A92F5@microsoft.com...
> Hi Kristan,
> i ran into a similar problem. since everything is triangles in 3D, there
> is no 'line' as such. there is a class called ScreenSpaceLine3D which you
> can find online, but it didn't really work for me so i rolled my own.
> essentially i created a very long and thin cuboid, to effect a grid. here
> is a bunch of code i use in my hobby app attempting to create a 3d
> modelling tool to help with construction projects. i use the TrackBall
> class to allow 3d fly/zoom around the world. there are a few helper
> methods to help with the 3d objects. i can mail you the whole thing if
> you want.
> good luck
> tim
>
> double scale = .05; // i use mm measurements and this is a useful scale,
> e.g. to render a 1500mm square on screen
> void mmSceneDrawGrid_Click(object sender, RoutedEventArgs e)
> {
> double thick = .03;
> double outsideThickFactor = 5;
> double len = 2000 * scale;
> double size = 5; // number of parellel lines in one side of the
> grid
> Color c = Colors.Red;
> double interval = len / size;
>
> for (int i = 0; i <= size; i++)
> {
> for (int j = 0; j <= size; j++)
> {
> // convert the loop iterators into the required grid cell size
> interval, relative to len
> double a = i * interval;
> double b = j * interval;
>
> // draw all the lines in the x-direction, size x size all starting at
> 0x, moving to 'len' for each y, for each z
> this.CreateLine(new Point3D(0, a, b), new Point3D(len, a, b), thick *
> ((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
> c);
> // draw all the lines in the y-direction, size x size all starting at
> 0y, moving to 'len' for each x, for each z
> this.CreateLine(new Point3D(a, 0, b), new Point3D(a, len, b), thick *
> ((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
> c);
> // draw all the lines in the z-direction, size x size all starting at
> 0z, moving to 'len' for each x, for each y
> this.CreateLine(new Point3D(a, b, 0), new Point3D(a, b, len), thick *
> ((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
> c);
> }
> }
> }
>
>
> private Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D
> p2, Color c)
> {
> MeshGeometry3D mesh = new MeshGeometry3D();
> Vector3D normal = CalculateNormal(p0, p1, p2);
> Material material = new DiffuseMaterial(new SolidColorBrush(c));
> GeometryModel3D model = new GeometryModel3D(mesh, material);
> Model3DGroup group = new Model3DGroup();
>
> return group;
> }
>
> private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
> {
> Vector3D v0 = new Vector3D(
> p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
> Vector3D v1 = new Vector3D(
> p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
> return Vector3D.CrossProduct(v0, v1);
> }
>
> private void CreateLine(Point3D a, Point3D b, double t, Color c)
> {
> Model3DGroup cube = new Model3DGroup();
> Point3D p0 = new Point3D(a.X, a.Y, a.Z);
> Point3D p1 = new Point3D(a.X + t, a.Y, a.Z);
> Point3D p2 = new Point3D(b.X + t, b.Y, b.Z);
> Point3D p3 = new Point3D(b.X, b.Y, b.Z);
> Point3D p4 = new Point3D(a.X, a.Y + t, a.Z);
> Point3D p5 = new Point3D(a.X + t, a.Y + t, a.Z);
> Point3D p6 = new Point3D(b.X + t, b.Y + t, b.Z);
> Point3D p7 = new Point3D(b.X, b.Y + t, b.Z);
> //front side triangles
> //right side triangles
> //back side triangles
> //left side triangles
> //top side triangles
> //bottom side triangles
>
> ModelVisual3D model = new ModelVisual3D();
> model.Content = cube;
> }
>
> "Kristan" <kristan@NOSPAMhotmail.co.uk> wrote in message
> news:484580AC-A26F-45F2-8698-5A5D9AEE3F01@microsoft.com...
>> Hi there, I need to render a simple 50x50 grid / table, each cell in the
>> table should highlight when the mouse is hovering over it.
>> The hard part is: I really need to be able to tilt the grid, within the
>> 3D world.... I hear the Viewport would support the 3D view - but how can
>> I render the grid within the Viewport?
>>
>> Any advice would be great!
>> Kristan
>>

>

My System Specs

4. ## Re: Simple Grid Rendering

hi kristan. here is the full code i'm using. hopefully it will work for
you. sorry i don't have time to trim it down to a minimal solution, there
is a lot of stuff that may not interest you. it's poorly commented (if at
all) and the object rotations don't work well, but it's my first wpf
application so i'm just using it as a learning tool.

here's the xaml:

<?Mapping XmlNamespace="local" ClrNamespace="WPF_Test" ?>
<Window x:Class="WPF_Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF_Test" WindowState="Maximized"
xmlns:my="clr-namespace:System;assembly=mscorlib" Height="336" Width="351">
<Grid Name="WorldGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
Grid.Row="0" Grid.Column="0" Focusable="True">

<Viewport3D Name="mainViewport" ClipToBounds="True" Grid.Row="1"
Grid.Column="0" >
<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="100"
NearPlaneDistance="0"
LookDirection="0,0,-1"
UpDirection="0,1,0"
Position="5,5,75"
FieldOfView="70"
/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight
Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
<Border Name="Border1" Background="Transparent" Grid.Row="1"
Grid.Column="0" Focusable="True" ForceCursor="True"
<DockPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Text=" Length " VerticalAlignment="Center" />
<TextBox Name="txtPlankLength" Width="70" Focusable="True" />
/>
</DockPanel>
<StatusBar Name="statusBar1" Grid.Row="3" Grid.Column="0" >
<StatusBarItem HorizontalAlignment="Left" Name="statusBarItem1"
</StatusBar>
</Grid>
</Window>

and, the lengthy code behind.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Markup;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Xml;
using System.Xml.Serialization;

using _3DTools;
using Microsoft.Win32;

namespace WPF_Test
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>

public partial class Window1 : System.Windows.Window
{
private List<Model3DGroup> FormObjects = new List<Model3DGroup>(); // a
list of all 3d objects added to the viewport
private Material previousMaterial;
private Model3DGroup currentModel;
double scale = .05; // 1mm : screen
private Trackball trackball = new Trackball();

public Window1()
{
InitializeComponent();

this.KeyDown += new KeyEventHandler(Window1_KeyDown);
this.Border1.MouseDown += new
MouseButtonEventHandler(ViewPort_MouseDown);

this.mmOpen.Click += new RoutedEventHandler(mmFileOpen_Click);
this.mmSave.Click += new RoutedEventHandler(mmFileSave_Click);
this.mmExit.Click += new RoutedEventHandler(mmFileExit_Click);

this.mmClearObjects.Click += new
RoutedEventHandler(mmSceneClearObjects_Click);
this.mmResetCamera.Click += new
RoutedEventHandler(mmSceneResetCamera_Click);

this.mmDrawGrid.Click += new RoutedEventHandler(mmSceneDrawGrid_Click);
this.mmViewKeyCommands.Click += new
RoutedEventHandler(mmSceneViewKeyCommands_Click);
this.mmDeselectObject.Click += new
RoutedEventHandler(mmSceneDeselect_Click);

this.mmClearLights.Click += new RoutedEventHandler(mmClearLights_Click);
}

{
this.mmSceneResetCamera_Click(sender, e);
this.mmSceneDrawGrid_Click(sender, e);
}

#region util shape grouping methods
private List<GeometryModel3D> GetChildGeometryModels(Model3DGroup parent)
{
List<GeometryModel3D> list = new List<GeometryModel3D>();
Queue<Model3DGroup> q = new Queue<Model3DGroup>();
foreach (object o in parent.Children)
if (o is Model3DGroup)
q.Enqueue(o as Model3DGroup);

while (q.Count > 0)
{
Model3DGroup m = q.Dequeue();
foreach (object o in m.Children)
{
if (o is Model3DGroup)
q.Enqueue(o as Model3DGroup);
else
}
}
return list;
}

private Model3DGroup FindParentModel(object find)
{
int hash = find.GetHashCode();
System.Diagnostics.Trace.WriteLine("Searching for " + hash);

// iterative approach to recursively scan child objects of the parent
model
foreach (Model3DGroup mod in FormObjects)
foreach (GeometryModel3D geo in GetChildGeometryModels(mod))
if (geo.GetHashCode() == hash)
return mod;
return null;
}

private void HighlightObject(Model3DGroup parent, Color c)
{
this.mmSceneDeselect_Click(null, new RoutedEventArgs());

Material m = new DiffuseMaterial(new SolidColorBrush(c));
foreach (GeometryModel3D geo in GetChildGeometryModels(parent))
{
previousMaterial = geo.Material.Clone(); // overwritten but that
doesn't matter.
geo.Material = m;
}

// save the current Material to and Model for later reverting back
currentModel = parent;

// set local transformation variable
if(!(currentModel.Transform is Transform3DGroup))
{
tg = new Transform3DGroup();
this.currentModel.Transform = tg;
}
else
tg = currentModel.Transform as Transform3DGroup;
}
#endregion

#region keyboard events
private Transform3DGroup tg;
void Window1_KeyDown(object sender, KeyEventArgs e)
{
PerspectiveCamera cam = (this.mainViewport.Camera as PerspectiveCamera);

// TODO: bullet-time-cam, slide and look.

if (Keyboard.Modifiers == ModifierKeys.Control)
{
// control the look direction via Ctrl-arrows / pg Up/down
switch (e.Key)
{
case Key.Left:
cam.LookDirection = new Vector3D(cam.LookDirection.X - .1,
cam.LookDirection.Y, cam.LookDirection.Z);
break;
case Key.Right:
cam.LookDirection = new Vector3D(cam.LookDirection.X + .1,
cam.LookDirection.Y, cam.LookDirection.Z);
break;
case Key.Up:
cam.LookDirection = new Vector3D(cam.LookDirection.X,
cam.LookDirection.Y + .1, cam.LookDirection.Z);
break;
case Key.Down:
cam.LookDirection = new Vector3D(cam.LookDirection.X,
cam.LookDirection.Y - .1, cam.LookDirection.Z);
break;
case Key.PageDown:
cam.LookDirection = new Vector3D(cam.LookDirection.X,
cam.LookDirection.Y, cam.LookDirection.Z + .1);
break;
case Key.PageUp:
cam.LookDirection = new Vector3D(cam.LookDirection.X,
cam.LookDirection.Y, cam.LookDirection.Z - .1);
break;
default:
return;
}
e.Handled = true;
}
else if (Keyboard.Modifiers == ModifierKeys.Shift)
{
if (this.currentModel == null)
{
this.statusBarItem1.Content = "No object selected!";
return;
}

// shift moves the object via Ctrl-arrows / pg Up/down
TranslateTransform3D t = tg.Children[0] as TranslateTransform3D;
switch (e.Key)
{
case Key.Left:
t.OffsetX--;
break;
case Key.Right:
t.OffsetX++;
break;
case Key.Up:
t.OffsetY++;
break;
case Key.Down:
t.OffsetY--;
break;
case Key.PageDown:
t.OffsetZ--;
break;
case Key.PageUp:
t.OffsetZ++;
break;
default:
return;
}
e.Handled = true;
}
else if (Keyboard.Modifiers == (ModifierKeys.Shift |
ModifierKeys.Control))
{
// shift+control = rotate
if (this.currentModel == null)
{
this.statusBarItem1.Content = "No object selected!";
return;
}
RotateTransform3D t = tg.Children[1] as RotateTransform3D;
AxisAngleRotation3D a = t.Rotation as AxisAngleRotation3D;
switch (e.Key)
{
case Key.Left:
a.Angle--;
break;
case Key.Right:
a.Angle++;
break;
default:
return;
}
e.Handled = true;
}
else // no modifiers, just move the camera
{
switch (e.Key)
{
case Key.Left:
cam.Position = new Point3D(cam.Position.X - 1, cam.Position.Y,
cam.Position.Z);
break;
case Key.Right:
cam.Position = new Point3D(cam.Position.X + 1, cam.Position.Y,
cam.Position.Z);
break;
case Key.Up:
cam.Position = new Point3D(cam.Position.X, cam.Position.Y + 1,
cam.Position.Z);
break;
case Key.Down:
cam.Position = new Point3D(cam.Position.X, cam.Position.Y - 1,
cam.Position.Z);
break;
case Key.PageDown:
cam.Position = new Point3D(cam.Position.X, cam.Position.Y,
cam.Position.Z + 1);
break;
case Key.PageUp:
cam.Position = new Point3D(cam.Position.X, cam.Position.Y,
cam.Position.Z - 1);
break;
cam.FieldOfView++;
break;
case Key.Subtract:
cam.FieldOfView--;
break;
default:
return;
}
e.Handled = true;
}
this.statusBarItem1.Content = String.Format("Camera: x{0:0}, y{1:0},
z{2:0}. Look: x{3:0.0}, y{4:0.0}, z{5:0.0}. Field of view: {6}",
cam.Position.X, cam.Position.Y, cam.Position.Z,
this.trackball.CameraLookDirection.X, this.trackball.CameraLookDirection.Y,
this.trackball.CameraLookDirection.Z, cam.FieldOfView);
}
#endregion

{
try
{
double length = Convert.ToDouble(this.txtPlankLength.Text)*scale;
this.CreateCuboid(new Point3D(0,0,0), 140*scale, length, 30*scale,
Colors.Brown);
}
catch
{
MessageBox.Show("Please enter a milimetre measurement, decimal points
are allowed, no letters etc. ", "Not a number");
}
}

void mmSceneResetCamera_Click(object sender, RoutedEventArgs e)
{
this.mainViewport.Camera.Transform = null; // remove the trackball

(this.mainViewport.Camera as PerspectiveCamera).Position = new Point3D(5,
5, 75);
(this.mainViewport.Camera as PerspectiveCamera).LookDirection = new
Vector3D(0, 0, -1);

trackball = new Trackball();
trackball.EventSource = this.Border1;
this.mainViewport.Camera.Transform = trackball.Transform;
}

void mmSceneClearObjects_Click(object sender, RoutedEventArgs e)
{
for(int i=this.mainViewport.Children.Count-1; i>=0; i--)
{
ModelVisual3D m = this.mainViewport.Children[i] as ModelVisual3D;
if(m is Model3DGroup)
this.mainViewport.Children.RemoveAt(i);
}
}

{
ModelVisual3D lights = new ModelVisual3D();
lights.Content = new AmbientLight(Colors.White);
}

void mmClearLights_Click(object sender, RoutedEventArgs e)
{
for(int i=this.mainViewport.Children.Count-1; i>=0; i--)
{
ModelVisual3D m = this.mainViewport.Children[i] as ModelVisual3D;
if(m.Content.GetType().Name.EndsWith("Light"))
this.mainViewport.Children.RemoveAt(i);
}
}

{
ModelVisual3D lights = new ModelVisual3D();
lights.Content = new DirectionalLight(Colors.Yellow,
(this.mainViewport.Camera as PerspectiveCamera).LookDirection);
}

void mmSceneDeselect_Click(object sender, RoutedEventArgs e)
{
if (this.currentModel != null)
{
// restore previous material
foreach (GeometryModel3D geo in GetChildGeometryModels(currentModel))
geo.Material = previousMaterial;
}
this.currentModel = null;
this.previousMaterial = null;
}

void mmSceneDrawGrid_Click(object sender, RoutedEventArgs e)
{
double thick = .03;
double outsideThickFactor = 5;
double len = 2000 * scale;
double size = 5;
Color c = Colors.Red; //.FromRgb(220, 220, 220);

double interval = len / size;

for (int i = 0; i <= size; i++)
{
for (int j = 0; j <= size; j++)
{
// convert the loop iterators into the required grid cell size
interval, relative to len
double a = i * interval;
double b = j * interval;

// draw all the lines in the x-direction, size x size all starting at
0x, moving to 'len' for each y, for each z
this.CreateLine(new Point3D(0, a, b), new Point3D(len, a, b), thick *
((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
c);
// draw all the lines in the y-direction, size x size all starting at
0y, moving to 'len' for each x, for each z
this.CreateLine(new Point3D(a, 0, b), new Point3D(a, len, b), thick *
((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
c);
// draw all the lines in the z-direction, size x size all starting at
0z, moving to 'len' for each x, for each y
this.CreateLine(new Point3D(a, b, 0), new Point3D(a, b, len), thick *
((a % len) / size == 0 && (b % len) / size == 0 ? outsideThickFactor : 1),
c);
}
}

/* 3dLine class not working....
*
* ScreenSpaceLines3D ssl3D = new ScreenSpaceLines3D();
Point3DCollection gridLines = new Point3DCollection();

for (int i = 0; i <= size; i++)
{
for (int j = 0; j <= size; j++)
{
// convert the loop iterators into the required grid cell size
interval, relative to len
double a = i * interval;
double b = j * interval;

// x line

// y line

// z line
}
}
ssl3D.Points = gridLines;
ssl3D.Color = Colors.Red;
ssl3D.Thickness = 5;
}

void mmSceneViewKeyCommands_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(@"Use arrows to move camera in x and y directions.
Page up/down to move camera in/out in z direction.
Ctrl+Arrow keys to change camera look vector in x and y direction.
Ctrl+Page up/down to change camera look vector in z direction.
+ Increase Field of View
- Decrease Field of View
Click on an object to select
Shift+Arrow keys to move the selected object
Ctrl+Shift+Arrow left/right to rotate", "Key Commands");
}

void mmFileExit_Click(object sender, RoutedEventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

void mmFileOpen_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog d = new OpenFileDialog();
if (!d.ShowDialog().Value)
return;

this.Cursor = Cursors.Wait;
Visual3DCollection controls;

this.mainViewport.Children.Clear();
foreach (Visual3D v in controls)
this.Cursor = Cursors.Arrow;
}

void mmFileSave_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog d = new SaveFileDialog();
d.Filter = "XAML | *.xaml";
if (!d.ShowDialog().Value)
return;

this.Cursor = Cursors.Wait;
using (FileStream fs = File.OpenWrite(d.SafeFileName))
XamlWriter.Save(this.mainViewport.Children, fs);
this.Cursor = Cursors.Arrow;
this.statusBarItem1.Content = "Saved";
}
#endregion

#region create shape methods
private Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D
p2, Color c)
{
MeshGeometry3D mesh = new MeshGeometry3D();
Vector3D normal = CalculateNormal(p0, p1, p2);
Material material = new DiffuseMaterial(new SolidColorBrush(c));
GeometryModel3D model = new GeometryModel3D(mesh, material);
Model3DGroup group = new Model3DGroup();

return group;
}

private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
Vector3D v0 = new Vector3D(
p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
Vector3D v1 = new Vector3D(
p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}

private void CreateLine(Point3D a, Point3D b, double t, Color c)
{
Model3DGroup cube = new Model3DGroup();
Point3D p0 = new Point3D(a.X, a.Y, a.Z);
Point3D p1 = new Point3D(a.X + t, a.Y, a.Z);
Point3D p2 = new Point3D(b.X + t, b.Y, b.Z);
Point3D p3 = new Point3D(b.X, b.Y, b.Z);
Point3D p4 = new Point3D(a.X, a.Y + t, a.Z);
Point3D p5 = new Point3D(a.X + t, a.Y + t, a.Z);
Point3D p6 = new Point3D(b.X + t, b.Y + t, b.Z);
Point3D p7 = new Point3D(b.X, b.Y + t, b.Z);
//front side triangles
//right side triangles
//back side triangles
//left side triangles
//top side triangles
//bottom side triangles

ModelVisual3D model = new ModelVisual3D();
model.Content = cube;
}

private Model3DGroup CreateCuboid(Point3D pos, double w, double l, double
d, Color c)
{
Model3DGroup cuboid = new Model3DGroup();

Point3D p0 = new Point3D(pos.X, pos.Y, pos.Z);
Point3D p1 = new Point3D(pos.X + w, pos.Y, pos.Z);
Point3D p2 = new Point3D(pos.X + w, pos.Y, pos.Z + d);
Point3D p3 = new Point3D(pos.X, pos.Y, pos.Z + d);
Point3D p4 = new Point3D(pos.X, pos.Y + l, pos.Z);
Point3D p5 = new Point3D(pos.X + w, pos.Y + l, pos.Z + 0);
Point3D p6 = new Point3D(pos.X + w, pos.Y + l, pos.Z + d);
Point3D p7 = new Point3D(pos.X, pos.Y + l, pos.Z + d);

//right side triangles
//back side triangles
//left side triangles
//top side triangles
//bottom side triangles

ModelVisual3D model = new ModelVisual3D();
model.Content = cuboid;

// add the cube to the 3d object tracker array (for grouping, hit test
etc)
return cuboid;
}
#endregion

#region hit test
public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult
rawresult)
{
RayHitTestResult rayResult = rawresult as RayHitTestResult;
if (rayResult != null)
{
RayMeshGeometry3DHitTestResult rayMeshResult = rayResult as
RayMeshGeometry3DHitTestResult;
if (rayMeshResult != null)
{
GeometryModel3D hitGeo = rayMeshResult.ModelHit as GeometryModel3D;

// currentModel is just a triangle, try to identify the parent group
and select the entire group
Model3DGroup parent = FindParentModel(hitGeo);
if (parent != null)
HighlightObject(parent, Colors.Yellow);
}
}
return HitTestResultBehavior.Stop;
}
void ViewPort_MouseDown(object sender, MouseButtonEventArgs e)
{
Point mouseposition = e.GetPosition(mainViewport);
Point3D testpoint3D = new Point3D(mouseposition.X, mouseposition.Y, 0);
Vector3D testdirection = new Vector3D(mouseposition.X, mouseposition.Y,
10);
PointHitTestParameters pointparams = new
PointHitTestParameters(mouseposition);
RayHitTestParameters rayparams = new RayHitTestParameters(testpoint3D,
testdirection);

//test for a result in the Viewport3D
VisualTreeHelper.HitTest(mainViewport, null, HTResult, pointparams);
}
#endregion
}
}

i also made a slight modification to the TrackBall class, to provide access
to the look direction of the camera. but you could use the existing 3dTools
dll and just remove the bit of code that uses this new property.

public Vector3D CameraLookDirection
{
get
{
return this._rotation.Axis;
}
}

any q's give me a shout!
tim

My System Specs

Simple Grid Rendering

 Similar Threads Thread Thread Starter Forum Replies Last Post mikadee Vista Games 5 10 May 2008 wrobes21 Vista General 3 06 Apr 2008 REE Vista mail 0 11 Dec 2007 Rodrigo Vista installation & setup 1 06 Nov 2007 craig kelly-soens www.XpectWorld.com Avalon 0 10 Jan 2006