Was looking at some examples of 3D drawing and used the approach shown here to draw y = x^2 + z^2
and a plane at y=0
in Viewport3D
. Here's how it looks like:
and here's the code:
class Plot3D : FrameworkElement
{
Viewport3D viewPort;
PerspectiveCamera camera;
Model3DGroup group;
Point3DAnimationUsingKeyFrames positionAnim;
Vector3DAnimationUsingKeyFrames lookAnim;
public Plot3D() {
camera = new PerspectiveCamera() {
FieldOfView = 120,
LookDirection = new Vector3D(0, -12, 9),
Position = new Point3D(0, 12, -9),
UpDirection = new Vector3D(0, 1, 0)
};
group = new Model3DGroup() { Children = { new AmbientLight(Colors.White) } };
viewPort = new Viewport3D() {
Camera = camera,
Children = { new ModelVisual3D() { Content = group } }
};
AddVisualChild(viewPort);
addModel();
positionAnim = new Point3DAnimationUsingKeyFrames() {
KeyFrames = {
new LinearPoint3DKeyFrame(new Point3D( 0, 12,-9), TimeSpan.FromSeconds(0)),
new LinearPoint3DKeyFrame(new Point3D(-9, 12, 0), TimeSpan.FromSeconds(5)),
new LinearPoint3DKeyFrame(new Point3D( 0, 12, 9), TimeSpan.FromSeconds(10)),
new LinearPoint3DKeyFrame(new Point3D( 9, 12, 0), TimeSpan.FromSeconds(15)),
new LinearPoint3DKeyFrame(new Point3D( 0, 12,-9), TimeSpan.FromSeconds(20))
},
RepeatBehavior = RepeatBehavior.Forever
};
lookAnim = new Vector3DAnimationUsingKeyFrames() {
KeyFrames = {
new LinearVector3DKeyFrame(new Vector3D( 0, -12, 9), TimeSpan.FromSeconds(0)),
new LinearVector3DKeyFrame(new Vector3D( 9, -12, 0), TimeSpan.FromSeconds(5)),
new LinearVector3DKeyFrame(new Vector3D( 0, -12,-9), TimeSpan.FromSeconds(10)),
new LinearVector3DKeyFrame(new Vector3D(-9, -12, 0), TimeSpan.FromSeconds(15)),
new LinearVector3DKeyFrame(new Vector3D( 0, -12, 9), TimeSpan.FromSeconds(20))
},
RepeatBehavior = RepeatBehavior.Forever
};
Loaded += animate;
}
void animate(object sender, RoutedEventArgs e) {
camera.BeginAnimation(PerspectiveCamera.PositionProperty, positionAnim);
camera.BeginAnimation(PerspectiveCamera.LookDirectionProperty, lookAnim);
}
void addModel() {
var mesh = new MeshGeometry3D();
double dx, dz; dx = dz = 0.25;
for (double x = -2; x < 2; x += dx) {
for (double z = -2; z < 2; z += dz) {
var p1 = new Point3D(x, f(x, z), z);
var p2 = new Point3D(x + dx, f(x + dx, z), z);
var p3 = new Point3D(x + dx, f(x + dx, z + dz), z + dz);
var p4 = new Point3D(x, f(x, z + dz), z + dz);
addTriangle(mesh, p1, p2, p3);
addTriangle(mesh, p3, p4, p1);
}
}
var surface = new GeometryModel3D() {
Geometry = mesh,
Material = new DiffuseMaterial(Brushes.LightBlue),
BackMaterial = new DiffuseMaterial(Brushes.SkyBlue),
};
group.Children.Add(surface);
var plane = new GeometryModel3D() {
Geometry = new MeshGeometry3D() {
Positions = {
new Point3D(-3, 0, 3),
new Point3D( 3, 0, 3),
new Point3D(-3, 0,-3),
new Point3D( 3, 0,-3)
},
TriangleIndices = { 0, 1, 2, 2, 1, 3 }
},
Material = new DiffuseMaterial(Brushes.LightGray)
};
group.Children.Add(plane);
//var line = new Line() { X1 = 0, X2 = 0, Y1 = 0, Y2 = 8, Stroke = Brushes.Blue, StrokeThickness = 4 };
//var line2d = new Viewport2DVisual3D() {
// Geometry = plane.Geometry,
// Visual = line,
// Material = new DiffuseMaterial(Brushes.Blue)
//};
//line2d.Material.SetValue(Viewport2DVisual3D.IsVisualHostMaterialProperty, true);
//viewPort.Children.Add(line2d);
}
double f(double x, double z) => x * x + z * z;
void addTriangle(MeshGeometry3D mesh, Point3D p1, Point3D p2, Point3D p3) {
int index1 = addPoint(mesh.Positions, p1);
int index2 = addPoint(mesh.Positions, p2);
int index3 = addPoint(mesh.Positions, p3);
mesh.TriangleIndices.Add(index1);
mesh.TriangleIndices.Add(index2);
mesh.TriangleIndices.Add(index3);
}
int addPoint(Point3DCollection positions, Point3D point) {
for (int i = 0; i < positions.Count; i++) {
if ((point.X == positions[i].X) &&
(point.Y == positions[i].Y) &&
(point.Z == positions[i].Z))
return i;
}
positions.Add(point);
return positions.Count - 1;
}
protected override Size ArrangeOverride(Size finalSize) {
viewPort.Width = finalSize.Width;
viewPort.Height = finalSize.Height;
viewPort.Measure(finalSize);
viewPort.Arrange(new Rect(viewPort.DesiredSize));
return finalSize;
}
protected override Visual GetVisualChild(int index) => viewPort;
protected override int VisualChildrenCount => 1;
}
in MainWindow.xaml
, I've used it like:
<Grid Margin="20">
<cc:Plot3D/>
</Grid>
Wanted to draw some gridlines on the plane and the y-axis, perpendicular to the plane, BUT looks like there's is no Line3D, Ellipse3D, Path3D, etc. to draw lines, parametric curve or point in space!
How do you draw these in Viewport3D?