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>
<Menu HorizontalAlignment="Stretch" Name="menu1" VerticalAlignment="Top"
Grid.Row="0" Grid.Column="0" Focusable="True">
<MenuItem Header="_File">
<MenuItem Header="_Open" Name="mmOpen" ></MenuItem>
<MenuItem Header="_Save" Name="mmSave"></MenuItem>
<MenuItem Header="E_xit" Name="mmExit"></MenuItem>
</MenuItem>
<MenuItem Header="_Lights">
<MenuItem Header="Add _Ambient Lights" Name="mmAddAmbientLights"
></MenuItem>
<MenuItem Header="Add _Directional Lights" Name="mmAddDirectionalLights"
></MenuItem>
<MenuItem Header="_Clear Lights" Name="mmClearLights" ></MenuItem>
</MenuItem>
<MenuItem Header="_Camera">
<MenuItem Header="_Reset Camera" Name="mmResetCamera" ></MenuItem>
<MenuItem Header="_Clear Scene" Name="mmClearObjects"></MenuItem>
</MenuItem>
<MenuItem Header="_Action">
<MenuItem Header="Draw _Grid" Name="mmDrawGrid" ></MenuItem>
<MenuItem Header="Deselect _Object" Name="mmDeselectObject" ></MenuItem>
<MenuItem Header="View _Key Commands" Name="mmViewKeyCommands"
></MenuItem>
</MenuItem>
</Menu>
<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"
KeyboardNavigation.AcceptsReturn="True"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Local"
KeyboardNavigation.ControlTabNavigation="Local" />
<DockPanel Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Text=" Length " VerticalAlignment="Center" />
<TextBox Name="txtPlankLength" Width="70" Focusable="True" />
<Button Click="AddPlank" Content="Add Plank" Width="70" Focusable="True"
/>
</DockPanel>
<StatusBar Name="statusBar1" Grid.Row="3" Grid.Column="0" >
<StatusBarItem HorizontalAlignment="Left" Name="statusBarItem1"
Content="Ready" ></StatusBarItem>
</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.Loaded += new RoutedEventHandler(Window1_Loaded);
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.mmAddAmbientLights.Click += new
RoutedEventHandler(mmSceneAddAmbientLights_Click);
this.mmAddDirectionalLights.Click += new
RoutedEventHandler(mmSceneAddDirectionalLights_Click);
this.mmClearLights.Click += new RoutedEventHandler(mmClearLights_Click);
}
void Window1_Loaded(object sender, RoutedEventArgs e)
{
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
list.Add(o as GeometryModel3D);
}
}
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;
System.Diagnostics.Trace.WriteLine("Not found\n\n");
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();
tg.Children.Add(new TranslateTransform3D());
tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D()));
tg.Children.Add(new ScaleTransform3D());
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;
case Key.Add:
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
void AddPlank(object sender, EventArgs e)
{
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");
}
}
#region menu
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);
}
}
void mmSceneAddAmbientLights_Click(object sender, RoutedEventArgs e)
{
ModelVisual3D lights = new ModelVisual3D();
lights.Content = new AmbientLight(Colors.White);
this.mainViewport.Children.Add(lights);
}
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);
}
}
void mmSceneAddDirectionalLights_Click(object sender, RoutedEventArgs e)
{
ModelVisual3D lights = new ModelVisual3D();
lights.Content = new DirectionalLight(Colors.Yellow,
(this.mainViewport.Camera as PerspectiveCamera).LookDirection);
this.mainViewport.Children.Add(lights);
}
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
gridLines.Add(new Point3D(0, a, b));
gridLines.Add(new Point3D(len, a, b));
// y line
gridLines.Add(new Point3D(a, 0, b));
gridLines.Add(new Point3D(a, len, b));
// z line
gridLines.Add(new Point3D(a, b, 0));
gridLines.Add(new Point3D(a, b, len));
}
}
ssl3D.Points = gridLines;
ssl3D.Color = Colors.Red;
ssl3D.Thickness = 5;
this.mainViewport.Children.Add(ssl3D);*/
}
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.statusBarItem1.Content = "Loading file, please wait...";
this.Cursor = Cursors.Wait;
Visual3DCollection controls;
using (FileStream fs = File.OpenRead(d.FileName))
controls = XamlReader.Load(fs) as Visual3DCollection;
this.mainViewport.Children.Clear();
foreach (Visual3D v in controls)
this.mainViewport.Children.Add(v);
this.Cursor = Cursors.Arrow;
this.statusBarItem1.Content = "Ready";
}
void mmFileSave_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog d = new SaveFileDialog();
d.Filter = "XAML | *.xaml";
if (!d.ShowDialog().Value)
return;
this.statusBarItem1.Content = "Saving, please wait...";
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();
mesh.Positions.Add(p0);
mesh.Positions.Add(p1);
mesh.Positions.Add(p2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
Vector3D normal = CalculateNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
Material material = new DiffuseMaterial(new SolidColorBrush(c));
GeometryModel3D model = new GeometryModel3D(mesh, material);
Model3DGroup group = new Model3DGroup();
group.Children.Add(model);
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
cube.Children.Add(CreateTriangleModel(p3, p2, p6, c));
cube.Children.Add(CreateTriangleModel(p3, p6, p7, c));
//right side triangles
cube.Children.Add(CreateTriangleModel(p2, p1, p5, c));
cube.Children.Add(CreateTriangleModel(p2, p5, p6, c));
//back side triangles
cube.Children.Add(CreateTriangleModel(p1, p0, p4, c));
cube.Children.Add(CreateTriangleModel(p1, p4, p5, c));
//left side triangles
cube.Children.Add(CreateTriangleModel(p0, p3, p7, c));
cube.Children.Add(CreateTriangleModel(p0, p7, p4, c));
//top side triangles
cube.Children.Add(CreateTriangleModel(p7, p6, p5, c));
cube.Children.Add(CreateTriangleModel(p7, p5, p4, c));
//bottom side triangles
cube.Children.Add(CreateTriangleModel(p2, p3, p0, c));
cube.Children.Add(CreateTriangleModel(p2, p0, p1, c));
ModelVisual3D model = new ModelVisual3D();
model.Content = cube;
this.mainViewport.Children.Add(model);
}
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);
cuboid.Children.Add(CreateTriangleModel(p3, p2, p6, c));
cuboid.Children.Add(CreateTriangleModel(p3, p6, p7, c));
//right side triangles
cuboid.Children.Add(CreateTriangleModel(p2, p1, p5, c));
cuboid.Children.Add(CreateTriangleModel(p2, p5, p6, c));
//back side triangles
cuboid.Children.Add(CreateTriangleModel(p1, p0, p4, c));
cuboid.Children.Add(CreateTriangleModel(p1, p4, p5, c));
//left side triangles
cuboid.Children.Add(CreateTriangleModel(p0, p3, p7, c));
cuboid.Children.Add(CreateTriangleModel(p0, p7, p4, c));
//top side triangles
cuboid.Children.Add(CreateTriangleModel(p7, p6, p5, c));
cuboid.Children.Add(CreateTriangleModel(p7, p5, p4, c));
//bottom side triangles
cuboid.Children.Add(CreateTriangleModel(p2, p3, p0, c));
cuboid.Children.Add(CreateTriangleModel(p2, p0, p1, c));
ModelVisual3D model = new ModelVisual3D();
model.Content = cuboid;
this.mainViewport.Children.Add(model);
// add the cube to the 3d object tracker array (for grouping, hit test
etc)
this.FormObjects.Add(cuboid);
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