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>
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>
I'm struggling to get a PropertyPath to work - I've got a Transformation in the Window Resources that I'm trying to affect via a StoryBoard - also in Window Resources ...
Heres the property path i'm using ...
(Viewport2DVisual3D.Transform).(Transform3DGroup)[0].(RotateTransform3D).(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)
EDIT: Thanks to Anurags suggestion I've got a bit further ...
(Viewport2DVisual3D.Transform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)
but now it errors with "Rotation property does not point to a DependencyProperty"
Can anyone please put me back on track?
Heres the code in full ...
<Window
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Window.Resources>
<Transform3DGroup x:Key="WorldTranslation">
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="0,1,0" Angle="0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Transform3DGroup>
<Storyboard x:Key="MyStoryboard">
<DoubleAnimation
Storyboard.Target="{Binding TemplatedParent}"
Storyboard.TargetProperty="(Viewport2DVisual3D.Transform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)"
From="0.0" To="360" Duration="0:0:1" />
</Storyboard>
<MeshGeometry3D
x:Key="squareMeshFrontLeft"
Positions="-1,-1,1 1,-1,1 1,1,1 -1,1,1"
TriangleIndices="0 1 2 0 2 3"
TextureCoordinates="0,1 1,1 1,0 0,0" />
<DiffuseMaterial x:Key="visualHostMaterial" Brush="White" Viewport2DVisual3D.IsVisualHostMaterial="True" />
</Window.Resources>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0,0,10" LookDirection="0,0,-1" />
</Viewport3D.Camera>
<Viewport2DVisual3D Material="{StaticResource visualHostMaterial}" Geometry="{StaticResource squareMeshFrontLeft}" >
<Viewport2DVisual3D.Transform>
<StaticResource ResourceKey="WorldTranslation" />
</Viewport2DVisual3D.Transform>
<StackPanel Background="Blue" Width="80" Height="80">
<Button Height="30" Margin="20">
<Button.Content>Blah</Button.Content>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MyStoryboard}" >
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Viewport2DVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Window>
First of all, instead of DoubleAnimation, use 3D KeyFrame Animation.
and correct your StoryBoard.TargetProperty's syntax using (Transform3DGroup.Children) instead of
check this also:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/78170274-a585-4cd6-85ed-edfd655d34ab
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.
I've got a KeyFrame Animation storyboard and a separate rotation transformation in my Window.Resources.
The rotation transformation works as I can alter the angle and see the content rotate. I know the storyboard is being called, because it took me a few goes to get the PropertyPath right after I clicked on the button.
However now it does nothing - no error, but no rotation either!
Can anyone help please?
Thanks,
Andy
<Window
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="400">
<Window.Resources>
<Storyboard x:Key="myStoryboard">
<Rotation3DAnimationUsingKeyFrames
Storyboard.Target="{Binding TemplatedParent}"
Storyboard.TargetProperty="(Viewport2DVisual3D.Transform).(RotateTransform3D.Rotation)" >
<Rotation3DAnimationUsingKeyFrames.KeyFrames>
<LinearRotation3DKeyFrame KeyTime="0:0:1">
<LinearRotation3DKeyFrame.Value>
<AxisAngleRotation3D Axis="0,1,0" Angle="0" />
</LinearRotation3DKeyFrame.Value>
</LinearRotation3DKeyFrame>
</Rotation3DAnimationUsingKeyFrames.KeyFrames>
</Rotation3DAnimationUsingKeyFrames>
</Storyboard>
<RotateTransform3D x:Key="myRotateTransform3D" >
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="0,1,0" Angle="30" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
<!-- Front, left square -->
<MeshGeometry3D
x:Key="squareMeshFront"
Positions="-1,-1,1 1,-1,1 1,1,1 -1,1,1"
TriangleIndices="0 1 2 0 2 3"
TextureCoordinates="0,1 1,1 1,0 0,0" />
<!-- Bottom -->
<MeshGeometry3D
x:Key="squareMeshBottom"
Positions="-1,-1,1 1,-1,1 1,-1,-1 1,1,-1"
TriangleIndices="0 1 2 0 2 3"
TextureCoordinates="0,1 1,1 1,0 0,0" />
<DiffuseMaterial x:Key="visualHostMaterial" Brush="White" Viewport2DVisual3D.IsVisualHostMaterial="True" />
</Window.Resources>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0,0,9" LookDirection="0,0,-1" />
</Viewport3D.Camera>
<Viewport2DVisual3D Material="{StaticResource visualHostMaterial}" Geometry="{StaticResource squareMeshFront}" Transform="{StaticResource myRotateTransform3D}" >
<StackPanel Background="Blue" Width="120" Height="80">
<Button Height="30" Margin="20">
<Button.Content>Click Me</Button.Content>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource myStoryboard}" >
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Viewport2DVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Window>
The problem is in Storyboard.Target="{Binding TemplatedParent}". Give a name to Viewport2DVisual3D control: <Viewport2DVisual3D x:Name="vp" .../>, and set Storyboard.TargetName="vp" instead of what you have...
Cheers