Wie man im Code sehen kann besteht der Hauptteil des Programms aus der Funktion
Tank(),
welche daraus besteht, dass ich alle Objekte von Hand baue. Das geht
prinzipiell auch viel einfacher mit 3D-Editoren oder aus XML-Dateien,
für den ersten Test werde ich es aber mal so belassen.Ansonsten gibt es da noch den
moveThread, welcher den Panzer bewegt und dann noch die Funktion RefreshEverything, welche die Position des Panzers verändert. Falls es Fragen zu irgendwas gibt stehe ich gerne Rede und Antwort.Hier nun mein Code von 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);
}
}
}
Und hier noch der entsprechende Code für 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>
Keine Kommentare:
Kommentar veröffentlichen