[英]3D transformation WPF
我在3d WPF中繪制了兩個球體,它們的點如Point3D(0,0,0)和Point3D(-1.0,1.0,2.0)的半徑為0.10
現在,我想繪制一個連接這些球體的圓柱體,對此我唯一擁有的就是半徑0.02。 我想知道如何計算此圓柱的3d點,高度,方向等。
我嘗試通過找到btw球體的中點,將圓柱體放置在這兩個球體的中間,但方向不正確。 我想以直角旋轉圓柱體。 我使用Vector3D.angleBetween(v1,v2)查找給我“ NaN”的角度。 我把我正在使用的代碼放在下面。
Vector3D v1 = new Vector3D(0, 0, 0);
Vector3D v2 = new Vector3D(1.0, -1.0, 2.0);
Vector3D center = v1+ v2/2;
Vector3D axis = Vector3D.CrossProduct(v1, v2);
double angle = Vector3D.AngleBetween(v1, v2);
AxisAngleRotation3D axisAngle = new AxisAngleRotation3D(axis, angle);
RotateTransform3D myRotateTransform = new RotateTransform3D(axisAngle, center);
center.X = myRotateTransform.CenterX;
center.Y = myRotateTransform.CenterY;
center.Z = myRotateTransform.CenterZ;
[編輯]
首先非常感謝您的答復。 我在這段代碼中遇到了一些問題,它可以很好地配合您的示例。 但是有了我的觀點它並沒有在正確的方向上繪制兩個圓點,也沒有直到終點(它僅連接到第二個點)才繪制圓柱,如果Z軸的中點是(中點),那是另一回事。 Z = 0),它甚至不拉圓柱體。
我只是想知道,是因為我畫圈的方式。 請看一下
public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
{
Model3DGroup spear = new Model3DGroup();
if (u < 2 || v < 2)
return null;
Point3D[,] pts = new Point3D[u, v];
for (int i = 0; i < u; i++)
{
for (int j = 0; j < v; j++)
{
pts[i, j] = GetPosition(radius,
i * 180 / (u - 1), j * 360 / (v - 1));
pts[i, j] += (Vector3D)center;
}
}
Point3D[] p = new Point3D[4];
for (int i = 0; i < u - 1; i++)
{
for (int j = 0; j < v - 1; j++)
{
p[0] = pts[i, j];
p[1] = pts[i + 1, j];
p[2] = pts[i + 1, j + 1];
p[3] = pts[i, j + 1];
spear.Children.Add(CreateTriangleModel(p[0], p[1], p[2], color));
spear.Children.Add(CreateTriangleModel(p[2], p[3], p[0], color));
}
}
ModelVisual3D model = new ModelVisual3D();
model.Content = spear;
return model;
}
private Point3D GetPosition(double radius, double theta, double phi)
{
Point3D pt = new Point3D();
double snt = Math.Sin(theta * Math.PI / 180);
double cnt = Math.Cos(theta * Math.PI / 180);
double snp = Math.Sin(phi * Math.PI / 180);
double cnp = Math.Cos(phi * Math.PI / 180);
pt.X = radius * snt * cnp;
pt.Y = radius * cnt;
pt.Z = -radius * snt * snp;
return pt;
}
public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
{
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 = VectorHelper.CalcNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
Material material = new DiffuseMaterial(new SolidColorBrush(color));
GeometryModel3D model = new GeometryModel3D(mesh, material);
Model3DGroup group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private class VectorHelper
{
public static Vector3D CalcNormal(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);
}
}
與您的代碼幾乎相同>
my sample point are :
p1 = Point3D(0,0,0)
p2= Point3D(-1.0, 1.0, 2.0)
p3= Point3D(-1.0, 1.0, 2.0)
p4 =Point3D(1.0, -1.0, 2.0)
我想繪制圓柱體btw p1至p2,p1至p3,p1至p4 p2至p3,p2至p4
請讓我知道是否需要進一步澄清,我必須解決。 感謝您的所有寶貴時間。
我不知道這對您是否有用,但是您對我最近發布的一些類似代碼發表了評論,尋求幫助-所以我想我會將代碼轉換成兩個對象,並通過3D旋轉圓柱體進行連接空間-Init()方法獲取兩個點,在這些點處創建10x10x10立方體,然后將它們與圓柱體連接。
我認為這大致是您想要實現的目標,盡管我承認我的示例有些人為(您只能在兩個點中的每個點上更改Z軸!!!),但希望您能從中得到一些東西它!
抱歉,代碼有些混亂,但是我已經從多個類中編譯了代碼,使其成為一個易於剪切和粘貼的塊!
無論如何,希望這可以幫助...
XAML繼承人...這只是設置了ViewPort和光源...
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="300">
<Viewport3D.Camera>
<PerspectiveCamera
LookDirection="0,0,-20"
UpDirection="0,1,0"
Position="0,0,100"
/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup x:Name="group3d">
<SpotLight Position="30,30,30" x:Name="mySpotLight" Color="Yellow" InnerConeAngle="100" OuterConeAngle="1000" Range="100" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</StackPanel>
...這是背后的代碼...
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Init(new Point3D(0, 0, 30), new Point3D(0,0,-30));
}
private Timer _timer;
private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
private double _angle;
public void Init(Point3D firstPoint, Point3D secondPoint)
{
var midPoint = firstPoint - secondPoint;
var size = new Size3D(10,10,10);
_models.Add(GetCube(GetSurfaceMaterial(Colors.Green), firstPoint, size));
_models.Add(GetCube(GetSurfaceMaterial(Colors.Green), secondPoint, size));
_models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));
_models.ForEach(x => mainViewport.Children.Add(x));
_timer = new Timer(10);
_timer.Elapsed += TimerElapsed;
_timer.Enabled = true;
}
void TimerElapsed(object sender, ElapsedEventArgs e)
{
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
}
public MaterialGroup GetSurfaceMaterial(Color colour)
{
var materialGroup = new MaterialGroup();
var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
materialGroup.Children.Add(emmMat);
materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
materialGroup.Children.Add(specMat);
return materialGroup;
}
public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
{
var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));
var cube = new Model3DGroup();
var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
//front side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
//right side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
//back side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
//left side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
//top side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
//bottom side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
var model = new ModelVisual3D();
model.Content = cube;
return model;
}
private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
{
return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
}
private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
{
var 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);
var normal = CalculateNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
var model = new GeometryModel3D(mesh, material);
var group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}
void Transform(double adjustBy)
{
_angle += adjustBy;
var rotateTransform3D = new RotateTransform3D {CenterX = 0, CenterZ = 0};
var axisAngleRotation3D = new AxisAngleRotation3D {Axis = new Vector3D(1, 1, 1), Angle = _angle};
rotateTransform3D.Rotation = axisAngleRotation3D;
var myTransform3DGroup = new Transform3DGroup();
myTransform3DGroup.Children.Add(rotateTransform3D);
_models.ForEach(x => x.Transform = myTransform3DGroup);
}
public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
{
var cylinder = new Model3DGroup();
var nearCircle = new CircleAssitor();
var farCircle = new CircleAssitor();
var twoPi = Math.PI * 2;
var firstPass = true;
double x;
double y;
var increment = 0.1d;
for (double i = 0; i < twoPi + increment; i = i + increment)
{
x = (radius * Math.Cos(i));
y = (-radius * Math.Sin(i));
farCircle.CurrentTriangle.P0 = midPoint;
farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);
nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);
if (!firstPass)
{
cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));
cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
}
else
{
farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
firstPass = false;
}
farCircle.LastPoint = farCircle.CurrentTriangle.P2;
nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
}
var model = new ModelVisual3D {Content = cylinder};
return model;
}
}
public class CircleAssitor
{
public CircleAssitor()
{
CurrentTriangle = new Triangle();
}
public Point3D FirstPoint { get; set; }
public Point3D LastPoint { get; set; }
public Triangle CurrentTriangle { get; set; }
}
public class Triangle
{
public Point3D P0 { get; set; }
public Point3D P1 { get; set; }
public Point3D P2 { get; set; }
public Triangle Clone(double z, bool switchP1andP2)
{
var newTriangle = new Triangle();
newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));
var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));
if (!switchP1andP2)
{
newTriangle.P1 = point1;
newTriangle.P2 = point2;
}
else
{
newTriangle.P1 = point2;
newTriangle.P2 = point1;
}
return newTriangle;
}
private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
{
var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
return newPoint;
}
}
}
我已將您的球體代碼與示例集成在一起,並且工作正常-圓柱體連接了兩個球體。
繼承人的代碼...
干杯,安迪
與以前一樣的ViewPort ...
<Window x:Class="wpfspin.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="300">
<Viewport3D.Camera>
<PerspectiveCamera
LookDirection="0,0,-20"
UpDirection="0,1,0"
Position="0,0,100"
/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup x:Name="group3d">
<SpotLight Position="30,30,30" x:Name="mySpotLight" Color="Yellow" InnerConeAngle="100" OuterConeAngle="1000" Range="100" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</StackPanel>
...這是背后的代碼...
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Init(new Point3D(0, 0, 30), new Point3D(0, 0, -30));
}
private Timer _timer;
private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
private double _angle;
public void Init(Point3D firstPoint, Point3D secondPoint)
{
var midPoint = firstPoint - secondPoint;
_models.Add(CreateSphere(firstPoint, 10, 10, 10, Colors.AliceBlue ));
_models.Add(CreateSphere(secondPoint, 10, 10, 10, Colors.AliceBlue));
_models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), secondPoint, 2, midPoint.Z));
_models.ForEach(x => mainViewport.Children.Add(x));
_timer = new Timer(10);
_timer.Elapsed += TimerElapsed;
_timer.Enabled = true;
}
void TimerElapsed(object sender, ElapsedEventArgs e)
{
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
}
public MaterialGroup GetSurfaceMaterial(Color colour)
{
var materialGroup = new MaterialGroup();
var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
materialGroup.Children.Add(emmMat);
materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
materialGroup.Children.Add(specMat);
return materialGroup;
}
public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
{
var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));
var cube = new Model3DGroup();
var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
//front side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
//right side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
//back side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
//left side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
//top side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
//bottom side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
var model = new ModelVisual3D();
model.Content = cube;
return model;
}
private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
{
return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
}
private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
{
var 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);
var normal = CalculateNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
var model = new GeometryModel3D(mesh, material);
var group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}
void Transform(double adjustBy)
{
_angle += adjustBy;
var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
var axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
rotateTransform3D.Rotation = axisAngleRotation3D;
var myTransform3DGroup = new Transform3DGroup();
myTransform3DGroup.Children.Add(rotateTransform3D);
_models.ForEach(x => x.Transform = myTransform3DGroup);
}
public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
{
var cylinder = new Model3DGroup();
var nearCircle = new CircleAssitor();
var farCircle = new CircleAssitor();
var twoPi = Math.PI * 2;
var firstPass = true;
double x;
double y;
var increment = 0.1d;
for (double i = 0; i < twoPi + increment; i = i + increment)
{
x = (radius * Math.Cos(i));
y = (-radius * Math.Sin(i));
farCircle.CurrentTriangle.P0 = midPoint;
farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);
nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);
if (!firstPass)
{
cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));
cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
}
else
{
farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
firstPass = false;
}
farCircle.LastPoint = farCircle.CurrentTriangle.P2;
nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
}
var model = new ModelVisual3D { Content = cylinder };
return model;
}
public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
{
Model3DGroup spear = new Model3DGroup();
if (u < 2 || v < 2)
return null;
Point3D[,] pts = new Point3D[u, v];
for (int i = 0; i < u; i++)
{
for (int j = 0; j < v; j++)
{
pts[i, j] = GetPosition(radius,
i * 180 / (u - 1), j * 360 / (v - 1));
pts[i, j] += (Vector3D)center;
}
}
Point3D[] p = new Point3D[4];
for (int i = 0; i < u - 1; i++)
{
for (int j = 0; j < v - 1; j++)
{
p[0] = pts[i, j];
p[1] = pts[i + 1, j];
p[2] = pts[i + 1, j + 1];
p[3] = pts[i, j + 1];
spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
}
}
ModelVisual3D model = new ModelVisual3D();
model.Content = spear;
return model;
}
private Point3D GetPosition(double radius, double theta, double phi)
{
Point3D pt = new Point3D();
double snt = Math.Sin(theta * Math.PI / 180);
double cnt = Math.Cos(theta * Math.PI / 180);
double snp = Math.Sin(phi * Math.PI / 180);
double cnp = Math.Cos(phi * Math.PI / 180);
pt.X = radius * snt * cnp;
pt.Y = radius * cnt;
pt.Z = -radius * snt * snp;
return pt;
}
public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
{
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 = VectorHelper.CalcNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
Material material = new DiffuseMaterial(
new SolidColorBrush(color));
GeometryModel3D model = new GeometryModel3D(
mesh, material);
Model3DGroup group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private class VectorHelper
{
public static Vector3D CalcNormal(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);
}
}
}
public class CircleAssitor
{
public CircleAssitor()
{
CurrentTriangle = new Triangle();
}
public Point3D FirstPoint { get; set; }
public Point3D LastPoint { get; set; }
public Triangle CurrentTriangle { get; set; }
}
public class Triangle
{
public Point3D P0 { get; set; }
public Point3D P1 { get; set; }
public Point3D P2 { get; set; }
public Triangle Clone(double z, bool switchP1andP2)
{
var newTriangle = new Triangle();
newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));
var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));
if (!switchP1andP2)
{
newTriangle.P1 = point1;
newTriangle.P2 = point2;
}
else
{
newTriangle.P1 = point2;
newTriangle.P2 = point1;
}
return newTriangle;
}
private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
{
var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
return newPoint;
}
}
}
這是一些更多的代碼-我想我已經為您找到了解決方案...
再次,它是一個拼湊在一起的示例,您需要改進。
請注意,轉換代碼已經發生了巨大變化,我本人只是剛接觸WPF 3D,我意識到我做錯了很多事情。 我每次都在重新創建Transform3DGroup,而不僅僅是更改已經應用的Transform的角度。
看一下代碼並注意altTransform組-我正在做的是向此alt組添加額外的轉換。 然后,我在圓柱體和球體上使用了altTransform,否則它們將與其他圓柱體和球體之一處於同一位置。 我已將此圓柱體標記為綠色,以便您可以看到它是哪個。
我建議您在同一軸上創建所有球體和圓柱體,然后將它們轉換到所需的位置。
我還已將球體和圓柱體的大小更改為您在前面的評論中所要求的大小。
看一下代碼,看看您的想法?
干杯,
安迪
<Window x:Class="wpfspin.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="600" Width="600">
<StackPanel>
<Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="600">
<Viewport3D.Camera>
<PerspectiveCamera
LookDirection="0,0,-5"
UpDirection="0,1,0"
Position="0,0,10"
/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup x:Name="group3d">
<SpotLight Position="30,30,30" x:Name="mySpotLight" Color="Yellow" InnerConeAngle="100" OuterConeAngle="1000" Range="100" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</StackPanel>
</Window>
這是背后的代碼...
using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
namespace wpfspin
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Init();
}
private Timer _timer;
private readonly List<ModelVisual3D> _models = new List<ModelVisual3D>();
private double _angle;
private Transform3DGroup _transform3DGroup;
private AxisAngleRotation3D _axisAngleRotation3D;
private Transform3DGroup _altTransform;
public void Init()
{
_models.Add(CreateSphere(new Point3D(0,0,0), 0.1, 10, 10, Colors.AliceBlue));
_models.Add(CreateSphere(new Point3D(0,0,2), 0.1, 10, 10, Colors.AliceBlue));
//notice that the following two spheres are created in the same place
_models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
_models.Add(CreateSphere(new Point3D(0, 0, -2), 0.1, 10, 10, Colors.AliceBlue));
_models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0,0,0), 0.02, 2));
//notice that the following to cylinders are also created in the same place
_models.Add(GetCylinder(GetSurfaceMaterial(Colors.Red), new Point3D(0, 0, 0), 0.02, -2));
_models.Add(GetCylinder(GetSurfaceMaterial(Colors.Green), new Point3D(0, 0, 0), 0.02, -2));
_transform3DGroup = new Transform3DGroup();
_models.ForEach(x => x.Transform = _transform3DGroup);
//heres my alt transform that i'm just using for the duplicate sphere and cylinder
_altTransform = new Transform3DGroup();
_models[3].Transform = _altTransform;
_models[6].Transform = _altTransform;
var rotateTransform3D = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
_axisAngleRotation3D = new AxisAngleRotation3D { Axis = new Vector3D(1, 1, 1), Angle = _angle };
rotateTransform3D.Rotation = _axisAngleRotation3D;
//i'm adding the animation rotation to both groups so that all my models spin
_transform3DGroup.Children.Add(rotateTransform3D);
_altTransform.Children.Add(rotateTransform3D);
//but my alt transform gets an extra transformation
var altRotate = new RotateTransform3D { CenterX = 0, CenterZ = 0 };
var altAxis = new AxisAngleRotation3D { Axis = new Vector3D(0, 1, 1), Angle = 90 };
altRotate.Rotation = altAxis;
_altTransform.Children.Add(altRotate);
_models.ForEach(x => mainViewport.Children.Add(x));
_timer = new Timer(10);
_timer.Elapsed += TimerElapsed;
_timer.Enabled = true;
}
void TimerElapsed(object sender, ElapsedEventArgs e)
{
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 0.5d);
}
public MaterialGroup GetSurfaceMaterial(Color colour)
{
var materialGroup = new MaterialGroup();
var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
materialGroup.Children.Add(emmMat);
materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
materialGroup.Children.Add(specMat);
return materialGroup;
}
public ModelVisual3D GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
{
var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));
var cube = new Model3DGroup();
var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
//front side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
//right side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
//back side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
//left side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
//top side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
//bottom side triangles
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
var model = new ModelVisual3D();
model.Content = cube;
return model;
}
private Model3DGroup CreateTriangleModel(MaterialGroup materialGroup, Triangle triangle)
{
return CreateTriangleModel(materialGroup, triangle.P0, triangle.P1, triangle.P2);
}
private Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
{
var 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);
var normal = CalculateNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
var model = new GeometryModel3D(mesh, material);
var group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}
void Transform(double adjustBy)
{
_angle += adjustBy;
_axisAngleRotation3D.Angle = _angle;
}
public ModelVisual3D GetCylinder(MaterialGroup materialGroup, Point3D midPoint, double radius, double depth)
{
var cylinder = new Model3DGroup();
var nearCircle = new CircleAssitor();
var farCircle = new CircleAssitor();
var twoPi = Math.PI * 2;
var firstPass = true;
double x;
double y;
var increment = 0.1d;
for (double i = 0; i < twoPi + increment; i = i + increment)
{
x = (radius * Math.Cos(i));
y = (-radius * Math.Sin(i));
farCircle.CurrentTriangle.P0 = midPoint;
farCircle.CurrentTriangle.P1 = farCircle.LastPoint;
farCircle.CurrentTriangle.P2 = new Point3D(x + midPoint.X, y + midPoint.Y, midPoint.Z);
nearCircle.CurrentTriangle = farCircle.CurrentTriangle.Clone(depth, true);
if (!firstPass)
{
cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle));
cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle));
cylinder.Children.Add(CreateTriangleModel(materialGroup, farCircle.CurrentTriangle.P2, farCircle.CurrentTriangle.P1, nearCircle.CurrentTriangle.P2));
cylinder.Children.Add(CreateTriangleModel(materialGroup, nearCircle.CurrentTriangle.P2, nearCircle.CurrentTriangle.P1, farCircle.CurrentTriangle.P2));
}
else
{
farCircle.FirstPoint = farCircle.CurrentTriangle.P1;
nearCircle.FirstPoint = nearCircle.CurrentTriangle.P1;
firstPass = false;
}
farCircle.LastPoint = farCircle.CurrentTriangle.P2;
nearCircle.LastPoint = nearCircle.CurrentTriangle.P2;
}
var model = new ModelVisual3D { Content = cylinder };
return model;
}
public ModelVisual3D CreateSphere(Point3D center, double radius, int u, int v, Color color)
{
Model3DGroup spear = new Model3DGroup();
if (u < 2 || v < 2)
return null;
Point3D[,] pts = new Point3D[u, v];
for (int i = 0; i < u; i++)
{
for (int j = 0; j < v; j++)
{
pts[i, j] = GetPosition(radius,
i * 180 / (u - 1), j * 360 / (v - 1));
pts[i, j] += (Vector3D)center;
}
}
Point3D[] p = new Point3D[4];
for (int i = 0; i < u - 1; i++)
{
for (int j = 0; j < v - 1; j++)
{
p[0] = pts[i, j];
p[1] = pts[i + 1, j];
p[2] = pts[i + 1, j + 1];
p[3] = pts[i, j + 1];
spear.Children.Add(CreateTriangleFace(p[0], p[1], p[2], color));
spear.Children.Add(CreateTriangleFace(p[2], p[3], p[0], color));
}
}
ModelVisual3D model = new ModelVisual3D();
model.Content = spear;
return model;
}
private Point3D GetPosition(double radius, double theta, double phi)
{
Point3D pt = new Point3D();
double snt = Math.Sin(theta * Math.PI / 180);
double cnt = Math.Cos(theta * Math.PI / 180);
double snp = Math.Sin(phi * Math.PI / 180);
double cnp = Math.Cos(phi * Math.PI / 180);
pt.X = radius * snt * cnp;
pt.Y = radius * cnt;
pt.Z = -radius * snt * snp;
return pt;
}
public Model3DGroup CreateTriangleFace(Point3D p0, Point3D p1, Point3D p2, Color color)
{
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 = VectorHelper.CalcNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
Material material = new DiffuseMaterial(
new SolidColorBrush(color));
GeometryModel3D model = new GeometryModel3D(
mesh, material);
Model3DGroup group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private class VectorHelper
{
public static Vector3D CalcNormal(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);
}
}
}
public class CircleAssitor
{
public CircleAssitor()
{
CurrentTriangle = new Triangle();
}
public Point3D FirstPoint { get; set; }
public Point3D LastPoint { get; set; }
public Triangle CurrentTriangle { get; set; }
}
public class Triangle
{
public Point3D P0 { get; set; }
public Point3D P1 { get; set; }
public Point3D P2 { get; set; }
public Triangle Clone(double z, bool switchP1andP2)
{
var newTriangle = new Triangle();
newTriangle.P0 = GetPointAdjustedBy(this.P0, new Point3D(0, 0, z));
var point1 = GetPointAdjustedBy(this.P1, new Point3D(0, 0, z));
var point2 = GetPointAdjustedBy(this.P2, new Point3D(0, 0, z));
if (!switchP1andP2)
{
newTriangle.P1 = point1;
newTriangle.P2 = point2;
}
else
{
newTriangle.P1 = point2;
newTriangle.P2 = point1;
}
return newTriangle;
}
private Point3D GetPointAdjustedBy(Point3D point, Point3D adjustBy)
{
var newPoint = new Point3D { X = point.X, Y = point.Y, Z = point.Z };
newPoint.Offset(adjustBy.X, adjustBy.Y, adjustBy.Z);
return newPoint;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.