Now, with a some ScreenSpaceLines3D in the drawing the Plane and Parabolic surface looks like this:

So the Back and Front materials are messed up because I couldn't figure out how TextureCoordinates work on the MeshGeometry3D! I wanted Red to start from the origin (x = y = z = 0), Blue at end and transition in between.
Here's the code and the Radial material part is in void addParabolicSurface() method:
class Plot3D : FrameworkElement
{
Viewport3D viewPort;
PerspectiveCamera camera;
Model3DGroup models;
Point3DAnimationUsingKeyFrames positionAnim;
Vector3DAnimationUsingKeyFrames lookAnim;
public Plot3D() {
camera = new PerspectiveCamera() {
FieldOfView = 80,
LookDirection = new Vector3D(0, -12, 9),
Position = new Point3D(0, 12, -9),
UpDirection = new Vector3D(0, 1, 0)
};
camera.LookDirection.Normalize();
models = new Model3DGroup() { Children = { new AmbientLight(Colors.White) } };
viewPort = new Viewport3D() {
Camera = camera,
Children = { new ModelVisual3D() { Content = models } }
};
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 addAxis() {
var xAxis = new ScreenSpaceLines3D() { Thickness = 1, Color = Colors.Green };
var zAxis = new ScreenSpaceLines3D() { Thickness = 1, Color = Colors.Red };
for (int i = -3; i < 4; i++) {
xAxis.Points.Add(new Point3D(i, 0, -3));
xAxis.Points.Add(new Point3D(i, 0, 3));
zAxis.Points.Add(new Point3D(-3, 0, i));
zAxis.Points.Add(new Point3D(3, 0, i));
}
var yAxis = new ScreenSpaceLines3D() {
Points = new Point3DCollection() {
new Point3D(0, 0, 0),
new Point3D(0, 8, 0)
},
Thickness = 1,
Color = Colors.Green
};
viewPort.Children.Add(xAxis);
viewPort.Children.Add(yAxis);
viewPort.Children.Add(zAxis);
}
void animate(object sender, RoutedEventArgs e) {
camera.BeginAnimation(PerspectiveCamera.PositionProperty, positionAnim);
camera.BeginAnimation(PerspectiveCamera.LookDirectionProperty, lookAnim);
}
void addModel() {
addParabolicSurface();
addPlane();
addAxis();
}
void addPlane() {
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)
};
models.Children.Add(plane);
}
void addParabolicSurface() {
var mesh = new MeshGeometry3D();
//mesh.TextureCoordinates.Add(new Point(0,1));
//mesh.TextureCoordinates.Add(new Point(1,1));
//mesh.TextureCoordinates.Add(new Point(1,0));
//mesh.TextureCoordinates.Add(new Point(0,0));
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);
mesh.TextureCoordinates.Add(new Point(p1.X, p1.Z));
mesh.TextureCoordinates.Add(new Point(p2.X, p2.Z));
mesh.TextureCoordinates.Add(new Point(p3.X, p3.Z));
mesh.TextureCoordinates.Add(new Point(p4.X, p4.Z));
addWires(p1, p2, p3, p4);
}
}
var radialBrush = new RadialGradientBrush() {
Center = new Point(0.5, 0.5),
GradientOrigin = new Point(0.5, 0.5),
GradientStops = {
new GradientStop(Colors.Red, 0),
new GradientStop(Colors.Blue, 1),
}
};
var surface = new GeometryModel3D() {
Geometry = mesh,
Material = new DiffuseMaterial(radialBrush),
BackMaterial = new DiffuseMaterial(radialBrush),
};
models.Children.Add(surface);
}
void addWires(Point3D p1, Point3D p2, Point3D p3, Point3D p4) {
var line = new ScreenSpaceLines3D() { Color = Colors.Gray, Thickness = 1 };
line.Points.Add(p1);
line.Points.Add(p2);
line.Points.Add(p2);
line.Points.Add(p3);
line.Points.Add(p3);
line.Points.Add(p4);
line.Points.Add(p4);
line.Points.Add(p1);
viewPort.Children.Add(line);
}
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;
}