WPF 3D變換應用
阿新 • • 發佈:2018-08-30
offsetx 開發效率 容易 right avi style string mouse port 原文:WPF 3D變換應用
{
Vector3D postion = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);
Vector3D rotateAxis = Vector3D.CrossProduct(postion, camera.UpDirection);
RotateTransform3D rt3d = new RotateTransform3D();
AxisAngleRotation3D rotate = new AxisAngleRotation3D(rotateAxis, angleDeltaFactor * (upDown ? -1 : 1));
rt3d.Rotation = rotate;
Matrix3D matrix = rt3d.Value;
Point3D newPostition = matrix.Transform(camera.Position);
camera.Position = newPostition;
camera.LookDirection = new Vector3D(-newPostition.X, -newPostition.Y, -newPostition.Z);
//update the up direction
Vector3D newUpDirection = Vector3D.CrossProduct(camera.LookDirection, rotateAxis);
newUpDirection.Normalize();
camera.UpDirection = newUpDirection;
} 水平變換:
private void HorizontalTransform(bool leftRight, double angleDeltaFactor)
{
Vector3D postion = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);
Vector3D rotateAxis = camera.UpDirection;
RotateTransform3D rt3d = new RotateTransform3D();
AxisAngleRotation3D rotate = new AxisAngleRotation3D(rotateAxis, angleDeltaFactor * (leftRight ? -1 : 1));
rt3d.Rotation = rotate;
Matrix3D matrix = rt3d.Value;
Point3D newPostition = matrix.Transform(camera.Position);
camera.Position = newPostition;
camera.LookDirection = new Vector3D(-newPostition.X, -newPostition.Y, -newPostition.Z);
}
{
double scaleFactor = 3;
//120 near , -120 far
System.Diagnostics.Debug.WriteLine(e.Delta.ToString());
Point3D currentPosition = camera.Position;
Vector3D lookDirection = camera.LookDirection;//new Vector3D(camera.LookDirection.X, camera.LookDirection.Y, camera.LookDirection.Z);
lookDirection.Normalize();
lookDirection *= scaleFactor;
if (e.Delta == 120)//getting near
{
if ((currentPosition.X + lookDirection.X) * currentPosition.X > 0)
{
currentPosition += lookDirection;
}
}
if (e.Delta == -120)//getting far
{
currentPosition -= lookDirection;
}
Point3DAnimation positionAnimation = new Point3DAnimation();
positionAnimation.BeginTime = new TimeSpan(0, 0, 0);
positionAnimation.Duration = TimeSpan.FromMilliseconds(100);
positionAnimation.To = currentPosition;
positionAnimation.From = camera.Position;
positionAnimation.Completed += new EventHandler(positionAnimation_Completed);
camera.BeginAnimation(PerspectiveCamera.PositionProperty, positionAnimation, HandoffBehavior.Compose);
}
WPF可以提供的3D模型使我們可以輕松地創建3D實體,雖然目前來看還很有一些性能上的問題,不過對於一些簡單的3D應用應該是可取的,畢竟其開發效率高,而且也容易上手。
下面給大家演示的是使用在WPF 3D上實現視角變換,通過鼠標拖動來變換觀察視角,通過滾輪來放縮視距。
首先創建一個3D立方體,立方體是由六個面構成(F1, F2 ....F6)其XAML代碼如下:
<Viewport3D> <Viewport3D.Camera> <!--<camera Position="15,15,15" LookDirection="-1,-1,-1" Width="15"></camera>--> <!--<camera Position="-5,-5,-5" LookDirection="1,1,1" Width="10" x:Name="camera"></camera>--> <!--<PerspectiveCamera Position="-5,-5,-5" LookDirection="1 1 1" FieldOfView="90"></PerspectiveCamera>--> <!--<PerspectiveCamera Position="-4,-4,-4" LookDirection="1 1 1" FieldOfView="75" x:Name="camera"></PerspectiveCamera>--> <PerspectiveCamera Position="8,8,8" LookDirection="-1 -1 -1" FieldOfView="75" UpDirection="-1 1 -1" x:Name="camera"></PerspectiveCamera> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D x:Name="light"> <ModelVisual3D.Content> <AmbientLight /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D x:Name="magicCube"> <ModelVisual3D.Content> <!-- 0: 0,0,0 1: 0,0,2 2: 2,0,2 3: 2,0,0 4: 2,2,0 5: 0,2,0 6: 0,2,2 7: 2,2,2 --> <Model3DGroup x:Name="cube"> <Model3DGroup.Transform> <TranslateTransform3D OffsetX="-1" OffsetY="-1" OffsetZ="-1" /> </Model3DGroup.Transform> <!--F1: 0,3,2,1--> <GeometryModel3D x:Name="F1"> <GeometryModel3D.Material> <DiffuseMaterial Brush="Blue"/> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="0,0,0 2,0,0 2,0,2 0,0,2" TriangleIndices="0,1,2 0,2,3"></MeshGeometry3D> </GeometryModel3D.Geometry> </GeometryModel3D> <!--F2: 0,1,6,5--> <GeometryModel3D x:Name="F2"> <GeometryModel3D.Material> <DiffuseMaterial Brush="Green"/> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="0,0,0 0,0,2 0,2,2 0,2,0" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D> </GeometryModel3D.Geometry> </GeometryModel3D> <!--F3: 4,5,6,7--> <GeometryModel3D x:Name="F3"> <GeometryModel3D.Material> <DiffuseMaterial Brush="Red"/> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="2,2,0 0,2,0 0,2,2 2,2,2" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D> </GeometryModel3D.Geometry> </GeometryModel3D> <!--F4: 2,3,4,7--> <GeometryModel3D x:Name="F4"> <GeometryModel3D.Material> <!--<DiffuseMaterial> <DiffuseMaterial.Brush> <VisualBrush> <VisualBrush.Visual> <Image Source="cubesurface.jpg"> <Image.Style> <Style> <Setter Property="Image.Opacity" Value="0.6"></Setter> </Style> </Image.Style> </Image> </VisualBrush.Visual> </VisualBrush> </DiffuseMaterial.Brush> </DiffuseMaterial>--> <DiffuseMaterial Brush="Yellow"/> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="2,0,2 2,0,0 2,2,0 2,2,2" TriangleIndices="0 1 2 0 2 3" TextureCoordinates="0,0 0,1 1,1 1,0"> </MeshGeometry3D> </GeometryModel3D.Geometry> </GeometryModel3D> <!--F5: 1,2,7,6--> <GeometryModel3D x:Name="F5"> <GeometryModel3D.Material> <DiffuseMaterial Brush="White"/> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions=" 0,0,2 2,0,2 2,2,2 0,2,2" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D> </GeometryModel3D.Geometry> </GeometryModel3D> <!--F6: 0,5,4,3--> <GeometryModel3D x:Name="F6"> <GeometryModel3D.Material> <DiffuseMaterial Brush="Orange"/> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions=" 0,0,0 0,2,0 2,2,0 2,0,0" TriangleIndices="0 1 2 0 2 3"></MeshGeometry3D> </GeometryModel3D.Geometry> </GeometryModel3D> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D>
在Viewport中用六個面構成一個立方體, 每一個面都是一個GeometryModel3D。
下面就是如何來實現通過鼠標拖動來變換視角的功能。首先給Window對象添加幾個有關的鼠標的事件:MouseMove、MouseLeftButtonDown和MouseWheel。
<Window x:Class="MagicCube.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="295" Width="525" Background="Black" MouseMove="Viewport3D_MouseMove" MouseLeftButtonDown="Viewport3D_MouseLeftButtonDown" MouseWheel="Viewport3D_MouseWheel" KeyDown="Window_KeyDown"> <Viewport3D …> </Window>
說明一下使用到的幾個變量:
其中MouseLeftButtonDown是用來獲取鼠標在進入拖動狀態之前的位置,這樣我們就可以根據鼠標位置的改變類變換視角。
Point mouseLastPosition;
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mouseLastPosition = e.GetPosition(this); }
下面是MouseMove事件,實現視角的變換。首先鼠標在拖動的過程中,可能發生水平方向上的變化和垂直方向上的變化,所以,我們將對不同的變化方向進行不同的變換。這裏我將水平變換和垂直變換已經分別封裝至兩個方法中:HorizontalTransform(水平變換)和VerticalTransform(垂直變換)
private void Viewport3D_MouseMove(object sender, MouseEventArgs e) { if (Mouse.LeftButton == MouseButtonState.Pressed) { Point newMousePosition = e.GetPosition(this); if (mouseLastPosition.X != newMousePosition.X) { HorizontalTransform(mouseLastPosition.X < newMousePosition.X, mouseDeltaFactor);//水平變換 } if (mouseLastPosition.Y != newMousePosition.Y)// change position in the horizontal direction { VerticalTransform(mouseLastPosition.Y > newMousePosition.Y, mouseDeltaFactor);//垂直變換 } mouseLastPosition = newMousePosition; } }
接下來我們就來看一下這兩個變換方法的具體實現:
垂直變換:
private void VerticalTransform(bool upDown, double angleDeltaFactor){
Vector3D postion = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);
Vector3D rotateAxis = Vector3D.CrossProduct(postion, camera.UpDirection);
RotateTransform3D rt3d = new RotateTransform3D();
AxisAngleRotation3D rotate = new AxisAngleRotation3D(rotateAxis, angleDeltaFactor * (upDown ? -1 : 1));
rt3d.Rotation = rotate;
Matrix3D matrix = rt3d.Value;
Point3D newPostition = matrix.Transform(camera.Position);
camera.Position = newPostition;
camera.LookDirection = new Vector3D(-newPostition.X, -newPostition.Y, -newPostition.Z);
//update the up direction
Vector3D newUpDirection = Vector3D.CrossProduct(camera.LookDirection, rotateAxis);
newUpDirection.Normalize();
camera.UpDirection = newUpDirection;
} 水平變換:
private void HorizontalTransform(bool leftRight, double angleDeltaFactor)
{
Vector3D postion = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);
Vector3D rotateAxis = camera.UpDirection;
RotateTransform3D rt3d = new RotateTransform3D();
AxisAngleRotation3D rotate = new AxisAngleRotation3D(rotateAxis, angleDeltaFactor * (leftRight ? -1 : 1));
rt3d.Rotation = rotate;
Matrix3D matrix = rt3d.Value;
Point3D newPostition = matrix.Transform(camera.Position);
camera.Position = newPostition;
camera.LookDirection = new Vector3D(-newPostition.X, -newPostition.Y, -newPostition.Z);
}
最後還有一個鼠標滾輪調節視距的變換,如下:
private void Viewport3D_MouseWheel(object sender, MouseWheelEventArgs e)
{
double scaleFactor = 3;
//120 near , -120 far
System.Diagnostics.Debug.WriteLine(e.Delta.ToString());
Point3D currentPosition = camera.Position;
Vector3D lookDirection = camera.LookDirection;//new Vector3D(camera.LookDirection.X, camera.LookDirection.Y, camera.LookDirection.Z);
lookDirection.Normalize();
lookDirection *= scaleFactor;
if (e.Delta == 120)//getting near
{
if ((currentPosition.X + lookDirection.X) * currentPosition.X > 0)
{
currentPosition += lookDirection;
}
}
if (e.Delta == -120)//getting far
{
currentPosition -= lookDirection;
}
Point3DAnimation positionAnimation = new Point3DAnimation();
positionAnimation.BeginTime = new TimeSpan(0, 0, 0);
positionAnimation.Duration = TimeSpan.FromMilliseconds(100);
positionAnimation.To = currentPosition;
positionAnimation.From = camera.Position;
positionAnimation.Completed += new EventHandler(positionAnimation_Completed);
camera.BeginAnimation(PerspectiveCamera.PositionProperty, positionAnimation, HandoffBehavior.Compose);
}
有了這個小程序之後,我們以後如果需要制作WPF 3D實體,也可以通過它來360度全方位地觀測構建的3D實體。
演示程序 源代碼
WPF 3D變換應用