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