As you can see in the code, the main part of the program is the function
Tank()
, which creates all objects by hand. Basically, it is much easier to do these things with a 3D editor but for the moment, this will do fine.Other functions I use are
moveThread
, this function moves the the tank and the function RefreshEverything
which changes the position of the displayed tank. Here is the code for MainWindow.xaml.cs:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
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.Media.Media3D;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Wpf3dTest1
{
public partial class MainWindow : Window
{
Dictionary<Key, Boolean> pressedKeys = new Dictionary<Key, Boolean>();
bool quit = false;
public MainWindow()
{
InitializeComponent();
pressedKeys.Add(Key.Left, false);
pressedKeys.Add(Key.Right, false);
pressedKeys.Add(Key.Up, false);
pressedKeys.Add(Key.Down, false);
this.KeyDown += MainWindow_KeyDown;
this.KeyUp += MainWindow_KeyUp;
this.Closing += OnWindowClosing;
//create a Tank object and add to viewport
mod = Tank(new Point3D(xPos, 0, 0), 2.2, 1.8, 0.7, 0.3, 0.25, 0.5, 0.25, new DiffuseMaterial(Brushes.Green), new DiffuseMaterial(Brushes.Black));
viewport3D.Children.Add(mod);
//start a Thread which moves the object
Thread thread = new Thread(moveThread);
thread.Start();
}
void MainWindow_KeyUp(object sender, KeyEventArgs e)
{
if (pressedKeys.ContainsKey(e.Key))
{
pressedKeys[e.Key] = false;
}
}
void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (pressedKeys.ContainsKey(e.Key))
{
pressedKeys[e.Key] = true;
}
}
ModelVisual3D mod;
private delegate void RefreshEverythingDelegate();
private void RefreshEverything()
{
TranslateTransform3D translate = new TranslateTransform3D();
translate.OffsetX = xPos;
translate.OffsetZ = zPos;
RotateTransform3D rotate = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1,0),angle));
rotate.CenterX = xPos;
rotate.CenterZ = zPos;
Transform3DGroup transform = new Transform3DGroup();
transform.Children.Add(translate);
transform.Children.Add(rotate);
mod.Transform = transform;
}
//Parameters for turn and move
private double posIncrementor = 0.02;
private double xPos = 0;
private double zPos = 0;
private double angle = 0;
private double angleIncrementor = 0.4;
private void moveThread()
{
while (!quit)
{
if (pressedKeys[Key.Up])
{
xPos += posIncrementor * Math.Cos(angle * Math.PI/180) ;
zPos -= posIncrementor * Math.Sin(angle * Math.PI / 180);
}
if (pressedKeys[Key.Down])
{
xPos -= posIncrementor * Math.Cos(angle * Math.PI / 180);
zPos += posIncrementor * Math.Sin(angle * Math.PI / 180);
}
if (pressedKeys[Key.Left])
{
angle += angleIncrementor;
}
if (pressedKeys[Key.Right])
{
angle -= angleIncrementor;
}
DispatcherOperation dispOp = this.viewport3D.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new RefreshEverythingDelegate(RefreshEverything));
Thread.Sleep(10);
}
}
public void OnWindowClosing(object sender, CancelEventArgs e)
{
quit = true;
}
private ModelVisual3D Tank(Point3D position, double length, double width, double height, double chainWidth, double chainHeight1, double chainHeight2, double chainNotLength, Material bodyMaterial, Material chainMaterial)
{
//Tank Body
MeshGeometry3D bodyMesh = new MeshGeometry3D();
Point3D a = new Point3D(position.X - length / 2, 0, position.Z + width / 2);
Point3D b = new Point3D(position.X + length / 2, 0, position.Z + width / 2);
Point3D c = new Point3D(position.X + length / 2, 0, position.Z - width / 2);
Point3D d = new Point3D(position.X - length / 2, 0, position.Z - width / 2);
Point3D e = new Point3D(position.X - length / 2, position.Y + height, position.Z + width / 2);
Point3D f = new Point3D(position.X + length / 2, position.Y + height, position.Z + width / 2);
Point3D g = new Point3D(position.X + length / 2, position.Y + height, position.Z - width / 2);
Point3D h = new Point3D(position.X - length / 2, position.Y + height, position.Z - width / 2);
BuildRectangle(bodyMesh, a, b, f, e, new Vector3D(0, 0, 1));
BuildRectangle(bodyMesh, b, c, g, f, new Vector3D(1, 0, 0));
BuildRectangle(bodyMesh, c, d, h, g, new Vector3D(0, 0, -1));
BuildRectangle(bodyMesh, d, a, e, h, new Vector3D(-1, 0, 0));
BuildRectangle(bodyMesh, e, f, g, h, new Vector3D(0, 1, 0));
BuildRectangle(bodyMesh, a, d, c, b, new Vector3D(0, -1, 0));
//Build the model object
GeometryModel3D BodyModel = new GeometryModel3D(
bodyMesh,
bodyMaterial);
//Chain 1
MeshGeometry3D chain1Mesh = new MeshGeometry3D();//links, also -width
a = new Point3D(position.X - length / 2 + chainNotLength, 0, position.Z - width / 2 - chainWidth);
b = new Point3D(position.X - length / 2 + chainNotLength, 0, position.Z - width / 2);
c = new Point3D(position.X + length / 2 - chainNotLength, 0, position.Z - width / 2 - chainWidth);
d = new Point3D(position.X + length / 2 - chainNotLength, 0, position.Z - width / 2);
e = new Point3D(position.X - length / 2, position.Y + chainHeight1, position.Z - width / 2 - chainWidth);
f = new Point3D(position.X - length / 2, position.Y + chainHeight1, position.Z - width / 2);
g = new Point3D(position.X + length / 2, position.Y + chainHeight1, position.Z - width / 2 - chainWidth);
h = new Point3D(position.X + length / 2, position.Y + chainHeight1, position.Z - width / 2);
Point3D i = new Point3D(position.X - length / 2, position.Y + chainHeight2, position.Z - width / 2 - chainWidth);
Point3D j = new Point3D(position.X - length / 2, position.Y + chainHeight2, position.Z - width / 2);
Point3D k = new Point3D(position.X + length / 2, position.Y + chainHeight2, position.Z - width / 2 - chainWidth);
Point3D l = new Point3D(position.X + length / 2, position.Y + chainHeight2, position.Z - width / 2);
BuildRectangle(chain1Mesh, a, b, d, c, new Vector3D(0, -1, 0));
BuildRectangle(chain1Mesh, a, e, f, b, new Vector3D(-1, -1, 0));
BuildRectangle(chain1Mesh, c, d, h, g, new Vector3D(1, -1, 0));
BuildRectangle(chain1Mesh, a,c,g,e, new Vector3D(0, 0, -1));
BuildRectangle(chain1Mesh, i, j, f, e, new Vector3D(-1, 0, 0));
BuildRectangle(chain1Mesh, k, g, h, l, new Vector3D(1, 0, 0));
BuildRectangle(chain1Mesh, e,g,k,i, new Vector3D(0, 0, -1));
BuildRectangle(chain1Mesh, i, k, l, j, new Vector3D(0, 1, 0));
//Build the model object
GeometryModel3D Chain1Model = new GeometryModel3D(
chain1Mesh,
chainMaterial);
//Chain 2
MeshGeometry3D chain2Mesh = new MeshGeometry3D();//rechts, also +width
a = new Point3D(position.X - length / 2 + chainNotLength, 0, position.Z + width / 2);
b = new Point3D(position.X - length / 2 + chainNotLength, 0, position.Z + width / 2 + chainWidth);
c = new Point3D(position.X + length / 2 - chainNotLength, 0, position.Z + width / 2);
d = new Point3D(position.X + length / 2 - chainNotLength, 0, position.Z + width / 2 + chainWidth);
e = new Point3D(position.X - length / 2, position.Y + chainHeight1, position.Z + width / 2);
f = new Point3D(position.X - length / 2, position.Y + chainHeight1, position.Z + width / 2 + chainWidth);
g = new Point3D(position.X + length / 2, position.Y + chainHeight1, position.Z + width / 2);
h = new Point3D(position.X + length / 2, position.Y + chainHeight1, position.Z + width / 2 + chainWidth);
i = new Point3D(position.X - length / 2, position.Y + chainHeight2, position.Z + width / 2);
j = new Point3D(position.X - length / 2, position.Y + chainHeight2, position.Z + width / 2 + chainWidth);
k = new Point3D(position.X + length / 2, position.Y + chainHeight2, position.Z + width / 2);
l = new Point3D(position.X + length / 2, position.Y + chainHeight2, position.Z + width / 2 + chainWidth);
BuildRectangle(chain2Mesh, a, b, d, c, new Vector3D(0, -1, 0));
BuildRectangle(chain2Mesh, a, e, f, b, new Vector3D(-1, -1, 0));
BuildRectangle(chain2Mesh, c, d, h, g, new Vector3D(1, -1, 0));
BuildRectangle(chain2Mesh, b, f, h, d, new Vector3D(0, 0, 1));
BuildRectangle(chain2Mesh, i, j, f, e, new Vector3D(-1, 0, 0));
BuildRectangle(chain2Mesh, k, g, h, l, new Vector3D(1, 0, 0));
BuildRectangle(chain2Mesh, f, j, l, h, new Vector3D(0, 0, 1));
BuildRectangle(chain2Mesh, i, k, l, j, new Vector3D(0, 1, 0));
//Build the model object
GeometryModel3D Chain2Model = new GeometryModel3D(
chain2Mesh,
chainMaterial);
//Build the whole object
Model3DGroup model3DGroup = new Model3DGroup();
model3DGroup.Children.Add(BodyModel);
model3DGroup.Children.Add(Chain1Model);
model3DGroup.Children.Add(Chain2Model);
ModelVisual3D model = new ModelVisual3D();
model.Content = model3DGroup;
return model;
}
//Funktioniert auch mit nicht-Rechtecken, also wenn nicht alle Innenwinkel 90° sind.
private void BuildRectangle(MeshGeometry3D geometry,Point3D a, Point3D b, Point3D c, Point3D d,Vector3D normal)
{
int baseIndex = geometry.Positions.Count;
//Add vertices
geometry.Positions.Add(a);
geometry.Positions.Add(b);
geometry.Positions.Add(c);
geometry.Positions.Add(d);
//Add normals
geometry.Normals.Add(normal);
geometry.Normals.Add(normal);
geometry.Normals.Add(normal);
geometry.Normals.Add(normal);
//Add indices
geometry.TriangleIndices.Add(baseIndex + 0);
geometry.TriangleIndices.Add(baseIndex + 2);
geometry.TriangleIndices.Add(baseIndex + 1);
geometry.TriangleIndices.Add(baseIndex + 2);
geometry.TriangleIndices.Add(baseIndex + 0);
geometry.TriangleIndices.Add(baseIndex + 3);
}
}
}
And here the code for MainWindow.xaml:
<Window x:Class="Wpf3dTest1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Viewport3D Name="viewport3D">
<Viewport3D.Camera>
<PerspectiveCamera Position="20,10,10"
LookDirection="-20,-10,-10"
UpDirection="0,1,0"
FieldOfView="45"
NearPlaneDistance="1"
FarPlaneDistance="100"></PerspectiveCamera>
</Viewport3D.Camera>
<ModelUIElement3D>
<AmbientLight Color="White"></AmbientLight>
</ModelUIElement3D>
</Viewport3D>
</Grid>
</Window>
No comments:
Post a Comment