Problems with 3D WPF - wpf

I started to learn some 3D in WPF today and I copied some simple examples (planes) into my XAML, and they all worked. However, when I adjusted the camera's and the plane's coordinates to meet my needs, I always see nothing.
I do not know what I am doing wrong, and I also already sketched the (really simple) 3D scene to verify my data, and it all seems correct to me.
Could anyone please check the following XAML and tell me what I am doing wrong? I only want to create a plane in the x-z-plane, i.e. some sort of "floor" with the camera looking down on it from the top.
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0 1 0"
LookDirection="0 -1 0"
FieldOfView="60"/>
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D>
<MeshGeometry3D.Positions>
<Point3D X="-1" Y="0" Z="1"/>
<Point3D X="1" Y="0" Z="1"/>
<Point3D X="1" Y="0" Z="-1"/>
<Point3D X="-1" Y="0" Z="-1"/>
</MeshGeometry3D.Positions>
<MeshGeometry3D.TriangleIndices>
0 1 2 0 2 3
</MeshGeometry3D.TriangleIndices>
<MeshGeometry3D.Normals>
<Vector3D X="0" Y="1" Z="0"/>
<Vector3D X="0" Y="1" Z="0"/>
<Vector3D X="0" Y="1" Z="0"/>
<Vector3D X="0" Y="1" Z="0"/>
<Vector3D X="0" Y="1" Z="0"/>
<Vector3D X="0" Y="1" Z="0"/>
</MeshGeometry3D.Normals>
</MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<MaterialGroup>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Red" Opacity="0.75"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</MaterialGroup>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D.Children>
</Viewport3D>
EDIT: I just experimented with the camera's Position and LookDirection, and finally saw something when I changed the LookDirection to be not perpendicular to the plane, for example:
<PerspectiveCamera Position="0 2 0"
LookDirection="0 -2 1"
FieldOfView="60"/>
Is this normal behavior?
Many thanks!
gehho.

When you are pointing the camera, it is important to watch out for the Up vector as well as the Look direction.
The problem comes from the default value for the Up vector (PerspectiveCamera.UpDirection), which is [0,1,0]. The camera's Look and Up vectors must not be parallel, because in that case it would be impossible to tell which way is up.
Since your model is in the XZ plane, and you want to look down over it, you can simply set UpDirection to [0,0,1] or [1,0,0], so that up points in the direction of either the Z or the X axis, respectively. But if you are planning on allowing the camera to look in all directions, you should be taking care of the Up vector too.

Related

WPF Viewport3D TextureCoordinates

I want to render a cube with a texture mapped over it.
This is my Texture:
The areas with text "Empty" should not be used.
This is my Viewport3D:
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera FarPlaneDistance="100" LookDirection="22,-10,-10" UpDirection="0,1,0" NearPlaneDistance="1" Position="-20,15,15" FieldOfView="60"/>
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="White" Direction="-2,-3,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="White" Direction="2,3,1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="
0,0,0 8,0,0 0,8,0 8,8,0
0,0,0 0,0,8 0,8,0 0,8,8
0,0,0 8,0,0 0,0,8 8,0,8
8,0,0 8,8,8 8,0,8 8,8,0
0,0,8 8,0,8 0,8,8 8,8,8
0,8,0 0,8,8 8,8,0 8,8,8"
TriangleIndices="
0,2,1 1,2,3
4,5,6 6,5,7
8,9,10 9,11,10
12,13,14 12,15,13
16,17,18 19,18,17
20,21,22 22,21,23"
TextureCoordinates="
0.5,0 0,0.25 0.25,0 1,0.5
0.25,0.25 0,0.25 0.25,0 0,0 ">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D.Children>
</Viewport3D>
The result:
First I wanted to try to get only the front side.
I only got as far as showing the first rectangle.
Unfortunately I can't manage to select another rectangle and it's mirrored too.
In this post
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d71dacba-167a-4249-8817-1b3995103835/correctly-texture-mapping-a-cube
Charles Petzold says
A good part of Chapter 5 of my book "3D Programming for Windows" attacks the problem of covering a cube (and square cuboid) with a bitmap image in a reasonable way.
Generally a good way to start is to draw (on a piece of paper) a rectangle that represents your image, and then to decide what part of that image should be positioned on what part of the cube. Since each point in the Positions collection maps to a point in the TextureCoordinates collection, you might find that what you're trying to do is topologically impossible.
But if all else fails, you can always treat the cube as 6 separate squares, and do each square independently of the others.
I went with his "brute force" suggestion and modified one of his examples from Chapter 5, using your bitmap. This is what the result looks like:
For each face, I use a ViewBox to define just the part of the image used for that face. Here's the source code (note there are scrollbars you can use spin the image around and verify all sides look right):
<DockPanel>
<ScrollBar Name="horz"
DockPanel.Dock="Bottom"
Orientation="Horizontal"
Minimum="-180"
Maximum="180"
LargeChange="10"
SmallChange="1" />
<ScrollBar Name="vert"
DockPanel.Dock="Right"
Orientation="Vertical"
Minimum="-180"
Maximum="180"
LargeChange="10"
SmallChange="1" />
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="-2 2 4" LookDirection="2 -2 -4" FieldOfView="60" />
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="White" />
<!-- Unit cube: front -->
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-0.5 0.5 0.5, 0.5 0.5 0.5,
-0.5 -0.5 0.5, 0.5 -0.5 0.5"
TriangleIndices=" 0 2 1, 1 2 3"
TextureCoordinates="0 0, 1 0, 0 1, 1 1" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png" Viewbox="0.25,0.5,0.25,0.5" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Black"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
<!-- Unit cube: back -->
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions=" 0.5 0.5 -0.5, -0.5 0.5 -0.5,
0.5 -0.5 -0.5, -0.5 -0.5 -0.5"
TriangleIndices=" 0 2 1, 1 2 3"
TextureCoordinates="0 0, 1 0, 0 1, 1 1"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png" Viewbox="0.75,0.5,0.25,0.5" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Black"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
<!-- Unit cube: left -->
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-0.5 0.5 -0.5, -0.5 0.5 0.5,
-0.5 -0.5 -0.5, -0.5 -0.5 0.5"
TriangleIndices=" 0 2 1, 1 2 3"
TextureCoordinates="0 0, 1 0, 0 1, 1 1"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png" Viewbox="0,0.5,0.25,.5" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Black"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
<!-- Unit cube: right -->
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions=" 0.5 0.5 0.5, 0.5 0.5 -0.5,
0.5 -0.5 0.5, 0.5 -0.5 -0.5"
TriangleIndices=" 0 2 1, 1 2 3"
TextureCoordinates="0 0, 1 0, 0 1, 1 1"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png" Viewbox="0.5,0.5,0.25,.5" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Black"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
<!-- Unit cube: top -->
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-0.5 0.5 -0.5, 0.5 0.5 -0.5,
-0.5 0.5 0.5, 0.5 0.5 0.5"
TriangleIndices=" 0 2 1, 1 2 3"
TextureCoordinates="0 0, 1 0, 0 1, 1 1"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png" Viewbox="0.25,0.0,0.25,.5" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Black"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
<!-- Unit cube: bottom. -->
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions=" 0.5 -0.5 -0.5, -0.5 -0.5 -0.5,
0.5 -0.5 0.5, -0.5 -0.5 0.5"
TriangleIndices=" 0 2 1, 1 2 3"
TextureCoordinates="0 0, 1 0, 0 1, 1 1"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="cube.png" Viewbox="0.5,0.0,0.25,.5" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Black"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
<ModelVisual3D.Transform>
<Transform3DGroup>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="0 1 0" Angle="{Binding ElementName=horz, Path=Value}" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="1 0 0" Angle="{Binding ElementName=vert, Path=Value}" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Transform3DGroup>
</ModelVisual3D.Transform>
</ModelVisual3D>
</Viewport3D.Children>
</Viewport3D>
</DockPanel>

Keeping a Rotated Linear Gradient Unrotated when Shape is Rotated in SVG

(SVG or WPF XAML - I'm open to (and need) both. I don't suppose they are any different in implementation. Below example is in SVG).
I'm trying to find a way to use rotation on a linear gradient (in this case 270°), but then when the shape it fills is rotated, keep the linear gradient unchanged, as if the shape it is filling isn't rotated.
By way of example, this is what Microsoft Word can do. When filling an AutoShape with a linear gradient, you can uncheck "Rotate with shape" and then the linear gradient will stay in place no matter how you rotate the shape.
So, here's an example, I want to rotated the linear gradient by 270° on it's center (in the linearGradient definition, gradientTransform="rotate(270 0.5 0.5)"). After that, I want to rotate the path it fills 45° (in the path, transform="rotate(45 0.5 0.5)").
<svg width="960" height="540" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<svg x="265.24353" y="133.125046" width="337.287231" height="211.206543" viewBox="0 0 337.287231 211.206543" style="overflow: visible;" >
<defs>
<linearGradient id="linear" gradientTransform="rotate(270 0.5 0.5)" spreadMethod="pad" >
<stop offset="0%" stop-color="#FF0000"/>
<stop offset="48%" stop-color="#FF0000"/>
<stop offset="48%" stop-color="#0070C0"/>
<stop offset="100%" stop-color="#0070C0"/>
</linearGradient>
</defs>
<path id="9" fill="url(#linear)" transform="rotate(45 0.5 0.5)" stroke="#000000" stroke-width="5" stroke-linecap="round" d="M0,0L205.8147,0L205.8147,174.9073L0,174.9073Z"/>
</svg>
</svg>
Okay, so this doesn't work, right? It's not supposed to. So I try subtracting 45° (path's rotation) from 270° (lin grad's rotation) for 225° and then in the linearGradient set gradientTransform="rotate(225 0.5 0.5)". That gets me close. Really close. So then I try lowering the angle and voilà, it's about 221° that seems to be correct. 4° lower than 270°-45°.
So I try this strategy again with a path rotation 65° - I know the linearGradient's rotation (originally at 270°) won't be 205°, but somewhere close to that, ah ha! It's 201° (or some floating point of that) 4° lower than 270°-65°.
How do I know it's 4° lower than 270°-65° lower than the subtraction in both cases? I eyeball the divider in the linearGradient to ensure it is horizontal.
So would there be a way to calculate the above regardless of linearGradient rotation angle or the shape's rotation angle? For example, if the liner gradient's rotation is 180° (which divides the above example vertically) or any other degree? If I could figure how to insert JS Fiddle here, I'd put more examples that can be run.
UPDATE (on WPF):
#Clemens provided some keen insight into how this can be accomplished in WPF by transforming the PathGeometry, not the Path. Awesome.
Here's the sample of transforming the Path, which is identical the SVG above.
<Path RenderTransformOrigin="0.5,0.5" Data="M0,0L205.8147,0L205.8147,174.9073L0,174.9073Z" Stroke="Black" StrokeLineJoin="Miter" StrokeThickness="5">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform Angle="45" CenterY="0.5" CenterX="0.5"/>
</TransformGroup>
</Path.RenderTransform>
<Path.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,1" >
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<RotateTransform Angle="221" CenterY="0.5" CenterX="0.5"/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStopCollection>
<GradientStop Offset="0" Color="#FF0000" />
<GradientStop Offset="0.48" Color="#FF0000" />
<GradientStop Offset="0.48" Color="#0070C0" />
<GradientStop Offset="1" Color="#0070C0" />
</GradientStopCollection>
</LinearGradientBrush>
</Path.Fill>
</Path>
And here's the way to transform just the PathGeometry - it works exactly as I need (well, except for the center of rotation, but I think I can resolve that).
<Path RenderTransformOrigin="0.5,0.5" Stroke="Black" StrokeLineJoin="Miter" StrokeThickness="5" Canvas.Left="15" Canvas.Top="23" >
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" IsClosed="True">
<LineSegment Point="205.8147,0"/>
<LineSegment Point="205.8147,174.9073"/>
<LineSegment Point="0,174.9073"/>
</PathFigure>
</PathGeometry.Figures>
<PathGeometry.Transform>
<RotateTransform Angle="45" CenterY="0.5" CenterX="0.5"/>
</PathGeometry.Transform>
</PathGeometry>
</Path.Data>
<Path.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,1" >
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<RotateTransform Angle="270" CenterY="0.5" CenterX="0.5"/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStopCollection>
<GradientStop Offset="0" Color="#FF0000" />
<GradientStop Offset="0.48" Color="#FF0000" />
<GradientStop Offset="0.48" Color="#0070C0" />
<GradientStop Offset="1" Color="#0070C0" />
</GradientStopCollection>
</LinearGradientBrush>
</Path.Fill>
</Path>
SVG only:
The angles don't add up because of the way gradients are applied on an element. By default..
(...) It essentially scales the gradient to the size of your object, so you only have to specify coordinates in values from zero to one, and they're scaled to the size of your object automatically for you.
https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Gradients
Another way to look at it; the gradient is first applied to a square, and then stretched to fit your element's bounding box. See this example where all three elements have the same 45 degrees gradient:
<svg width="960" height="540" xmlns="http://www.w3.org/2000/svg" >
<defs>
<linearGradient id="linear" gradientTransform="rotate(45 0.5 0.5)" spreadMethod="pad">
<stop offset="49%" stop-color="gold"/>
<stop offset="51%" stop-color="blue"/>
</linearGradient>
</defs>
<path fill="url(#linear)" d="M0,0 h170 v100 h-170"/>
<path fill="url(#linear)" d="M210,0 h100 v100 h-100"/>
<path fill="url(#linear)" d="M350,0 h100 v170 h-100"/>
</svg>
So in your case, where you want the gradient at a 225 degree angle, imagine squeezing the gradient back into a square form, and calculate what the angle looks like then.
Long story short, here is some code:
https://jsfiddle.net/bc4k4Lcv/

how to tile 3D mesh with image brush in XAML

I have a 2D square in a ViewPort3D that I want to do a tiling of an image (like a checkerboard or flooring with "tiles" effect).
I've created an image brush (the image is 50x50 pixels, the surface 250x550 pixels) and a viewport (trying to follow MS's site - though their example is for 2D), but only 1 of the colors in the "tile" image shows up and no tiling is seen.
I can't find a single example on the Internet and MS's site has no info (that I can find) on 3D XAML anywhere, so I'm stumped as how to actually do this.
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="125,790,120" LookDirection="0,-.7,-0.25" UpDirection="0,0,1" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="white" />
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="0,0,0 250,0,0 250,550,0 0,550,0 " TriangleIndices="0 1 3 1 2 3 "/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ViewportUnits="Absolute" TileMode="Tile" ImageSource="testsquare.gif" Viewport="0,0,50,50" Stretch="None" ViewboxUnits="Absolute" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
OK, Got it figured out. Besides the TextureCoordinates, I needed to set the alignment property of the brush. Here is the final, working code.
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="125,790,120" LookDirection="0,-.7,-0.25" UpDirection="0,0,1" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="white" />
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="0,0,0 250,0,0 250,550,0 0,550,0 " TriangleIndices="0 1 3 1 2 3" TextureCoordinates="0,0 250,0 250,550 0,550 "/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ViewportUnits="Absolute" TileMode="Tile" ImageSource="testsquare.gif" Viewport="0,0,50,50" ViewboxUnits="Absolute" Stretch="None" AlignmentX="Left" AlignmentY="Top" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>

Creating an advanced HUD

I'm making an interface for the AR Drone Quadcopter in WPF.
I neen some stuff on my HUD to make it usable.
One of the more advanced controls on the HUD is the artificial horizon, which tells the pilot the craft's current alignment to the horizon.
I have these 3 PNGs
The first image I will move (The current pitch of the craft) and rotate (The current roll of the craft).
I will put the second image over the first, this one will only rotate around the center axis, it has ticks at certain degrees which will visualize the craft's roll even more.
The last one I will put on top of the second, this image just a visual improver.
Then I want to mask first image so that you only see whats inside the circle in image 2.
Last but not least I want to add a textblock to it and display the current altitude
The result will look something like this
I know how to rotate and move the image, but how do I place the images on top of each other, and how do I mask the first image?
edit: Thanks to Ben I've gotten this far:
But I also need to translate the image Y position (The pitch of the aircraft)
When I add the translate transform I also translate the Clip (Mask) how can I translate the image without moving the mask?
A little sample that how you can use DrawingGroups and a ClipGeometry inside it.
<Grid>
<Image Source="Images\Background.jpg" />
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup>
<!-- You can rotate a DrawingGroup -->
<DrawingGroup.Transform>
<RotateTransform Angle="-15" CenterX="50" CenterY="50" />
</DrawingGroup.Transform>
<ImageDrawing ImageSource="Images\last.png" Rect="0,0,100,100" />
<DrawingGroup.ClipGeometry>
<EllipseGeometry Center="50,50" RadiusX="25" RadiusY="25" />
</DrawingGroup.ClipGeometry>
</DrawingGroup>
<DrawingGroup>
<ImageDrawing ImageSource="Images\middle.png" Rect="0,0,100,100" />
<ImageDrawing ImageSource="Images\outer.png" Rect="0,0,100,100" />
</DrawingGroup>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Grid>
I was tired last night :D
To get the background to rotate and translate but not the Clipping was just to put the background in a sub group to the clipping group... Now it works!
<Image Width="240" Height="240">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup>
<DrawingGroup>
<DrawingGroup.Transform>
<TransformGroup>
<RotateTransform Angle="-15" CenterX="120" CenterY="120" />
<TranslateTransform Y="-20" />
</TransformGroup>
</DrawingGroup.Transform>
<ImageDrawing ImageSource="Images\pNxVK.png" Rect="0,0,240,240" />
</DrawingGroup>
<DrawingGroup.ClipGeometry>
<EllipseGeometry Center="120,120" RadiusX="60" RadiusY="60">
</EllipseGeometry>
</DrawingGroup.ClipGeometry>
</DrawingGroup>
<DrawingGroup>
<ImageDrawing ImageSource="Images\zUr8D.png" Rect="0,0,240,240" />
<ImageDrawing ImageSource="Images\XPZW9.png" Rect="0,0,240,240" />
</DrawingGroup>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>

WPF 3D Gradientbrush problem

The main problem is in LinearGradientBrush. It fills triangle in solid red. What's wrong? I have tried almost the same code with 2d shapes. It worked perfectly.
<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="215" Width="336">
<Grid Height="146" Width="232">
<Viewport3D Name="myViewPort" ClipToBounds="False">
<Viewport3D.Camera>
<PerspectiveCamera x:Name="myCamera"
Position="10,10,10"
UpDirection="0,1,0"
LookDirection="-10,-10,-10"
FieldOfView="10"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,0,0 0,1,0 1,0,0" TriangleIndices="0,2,1" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Black" Offset="0"></GradientStop>
<GradientStop Color="Red" Offset="0.6"></GradientStop>
</LinearGradientBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight></AmbientLight>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
You need to add TextureCoordinates to your Geometry:
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-1,0,0 0,1,0 1,0,0"
TextureCoordinates="0,0 1,0 1,1"
TriangleIndices="0,2,1"
/>
</GeometryModel3D.Geometry>
Once you do this, the material will map to the texture coordinates appropriately, and you'll see your black->red gradients. Right now, the texture coordinates are all defaulting to a point that's in the "red" portion of the gradient.

Resources