I have a model that I created in 3ds Max. The model is a simple rectangle. Its texture has overlapping texture coordinates--the model should display the right half of the image file twice, side-by-side. I exported this model as an .obj
, and converted it to XAML using Microsoft Expression Blend.
I took the MeshGeometry3D
from blend, and added it to a Viewport3D
using two methods:
Viewport2DVisual3D
with a Label
as its Visual
. Set the Label
's background to the texture image. Using this method, everything works as expected.ModelVisual3D
with a GeometryModel3D
as its Content
. Set the GeometryModel3D
's material to a DiffuseMaterial
that uses the image as its brush. Using this method, the TextureCoordinates
of the MeshGeometry3D
appear to be interpreted differently.The full code is provided below. The code-behind is empty except for InitializeComponent()
:
<Window x:Class="TestTextureCoordinates.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<MeshGeometry3D x:Key="geometry"
Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1"
Positions="113.8997,102.4171,0 148.9045,102.4171,0 148.9045,148.41161,0 113.8997,148.41161,0 184.5722,102.4171,0 184.5722,148.41161,0 148.9045,148.41161,0 148.9045,102.4171,0"
TextureCoordinates="0.50639999,0.9995 1.0065,0.9995 1.0065,0.00050002337 0.50639999,0.00050002337 1.0022,0.9995 1.0022,0.00050002337 0.5,0.00050002337 0.5,0.9995"
TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7"/>
<ImageBrush x:Key="brush" ImageSource="img/test.jpg" />
</Grid.Resources>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="195,125,210" LookDirection="0,0,-1" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
<!-- The first model, using a Viewport2DVisual3D. This works as intended. -->
<Viewport2DVisual3D Geometry="{StaticResource geometry}">
<Viewport2DVisual3D.Visual>
<Label Background="{StaticResource brush}" />
</Viewport2DVisual3D.Visual>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" />
</Viewport2DVisual3D.Material>
</Viewport2DVisual3D>
<!-- The second model, using a ModelVisual3D and GeometryModel3D. The TextureCoordinates do not work as intended. -->
<ModelVisual3D>
<!-- We apply a transform to offset this model from the first model. -->
<ModelVisual3D.Transform>
<TranslateTransform3D OffsetX="90" />
</ModelVisual3D.Transform>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource geometry}">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="{StaticResource brush}" />
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
Here is test.jpg
:
Here is the final result. On the left is the Viewport2DVisual3D
, which looks the same as it does in 3ds Max. On the right is the ModelVisual3D
, which appears to be interpreting the TextureCoordinates
differently.
What's going on here? Due to other requirements of the software I am working on, I cannot use a Viewport2DVisual3D
. How can I make a GeometryModel3D
interpret the TextureCoordinates
correctly?
I just had to set ViewportUnits
on the ImageBrush
to Absolute
:
<ImageBrush x:Key="brush" ImageSource="img/test.jpg" ViewportUnits="Absolute" />
See this post (archive) from the WPF3D team blog:
If you don't set TileBrush.ViewportUnits to BrushMappingMode.Absolute, your texture coordinates will be relative to the bounding box of your geometry. For example, let's say you only want half of your texture in v to be mapped to the mesh. In other APIs, you would just range your coordinate from 0.0 -> 0.5. If you do that in WPF3D without setting ViewportUnits to Absolute, it'll still map the entire thing. Essentially any time you don't want one copy of the entire texture you'll want to set Absolute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With