Click here to Skip to main content
15,884,010 members
Please Sign up or sign in to vote.
4.80/5 (3 votes)
See more:
I'm trying to get some text to a desired angle using WPFs built-in 3D classes (and only using XAML). The code that uses this user control then calls a method in the control to render the renderPanel to a png file. According to this xaml, it's displaying exactly the way I want it. However, it looks substantially different in the resulting PNG file.

XML
<UserControl x:Class="WpfControls.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             mc:Ignorable="d" 
             d:DesignHeight="350" d:DesignWidth="350" removed="black"
             >
    <Grid x:Name="renderGrid">

        <Border x:Name="renderPanel" removed="Transparent" SnapsToDevicePixels="True" >
            <Viewport3D x:Name="viewPort" >
                <Viewport3D.Camera >
                    <PerspectiveCamera Position="0, 0, 5" />
                </Viewport3D.Camera>

                <Viewport2DVisual3D >
                    <Viewport2DVisual3D.Transform>
                        <RotateTransform3D>
                            <RotateTransform3D.Rotation>
                                <AxisAngleRotation3D Angle="51" Axis="-95, -10, -138" />
                            </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                    </Viewport2DVisual3D.Transform>

                    <Viewport2DVisual3D.Geometry>
                        <MeshGeometry3D Positions="-1,1,0  -2.1,-1.1,0  1,-1.1,0  2,1,0"
                                        TextureCoordinates="0,0  0,1  1,1  1,0" 
                                        TriangleIndices="0 1 2 0 2 3"/>
                    </Viewport2DVisual3D.Geometry>

                    <Viewport2DVisual3D.Material>
                        <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" 
                                         Brush="White"/>
                    </Viewport2DVisual3D.Material>

                    <!-- Putting the textblock into a border made the text look exactly the 
                    way I wanted it to. -->
                    <Border BorderBrush="Transparent" BorderThickness="0" >
                        <TextBlock Text="11:35" FontWeight="Thin" 
                                   FontFamily="Roboto Th" Foreground="White" >
                        </TextBlock>
                    </Border>
                </Viewport2DVisual3D>

                <ModelVisual3D>
                    <ModelVisual3D.Content>
                        <DirectionalLight Color="#FFFFFFFF" Direction="0,-1,-1"/>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
            </Viewport3D>
        </Border>
    </Grid>
</UserControl>


When, I run call the Render method in the following code, the resulting image file looks different (as if the textblock wasn't in the border container).You can see this if you comment out the border container in the xaml

C#
using System;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WpfControls
{
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
            this.Height = 275;
            this.Width = 275;
            this.DataContext = this;
        }

        public void Render(string filename)
        {
            this.renderPanel.Measure(new System.Windows.Size(this.Width, this.Height));
            this.renderPanel.Arrange(new Rect(new System.Windows.Size(this.Width, 
                                                                      this.Height)));
            this.renderPanel.UpdateLayout();
            this.UpdateLayout();
            RenderTargetBitmap rtb = new RenderTargetBitmap((int)this.renderPanel.ActualWidth, 
                                                            (int)this.renderPanel.ActualHeight, 
                                                            96d, 96d, PixelFormats.Pbgra32);
            rtb.Render(this.renderPanel);
            using (FileStream outputStream = new FileStream(filename, FileMode.Create))
            {
                PngBitmapEncoder enc = new PngBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(rtb));
                enc.Save(outputStream);
                outputStream.Close();
            }
        }

    }
}
Posted
Updated 23-Aug-13 3:21am
v3
Comments
Sergey Alexandrovich Kryukov 20-Aug-13 11:52am    
Pretty cool question, my 5. I can imaging how impressive the use of it can be.
—SA
#realJSOP 22-Aug-13 17:51pm    
We create what we call middleware that performs a task. In this case, the task is to get the current time, and position it so that it looks like the output of a flat time display being viewed at an angle.

1 solution

Without knowing exactly what you mean with "head-on" I would suggest (if possible for your use-case) to try moving the camera instead of rotating the text.

I would leave the text with no rotation, and I would position the camera and the camera look-at target to achieve what effect you want.

And easy way to do this would be to knock up a quick application that lets you modify camera position and look-at target using slider (for example), then play around with that until you get the look you want and then simply record the values for the camera.

Also, you might want to fiddle a bit with the Field of View as that can be really effective in exaggerating the perspective feel of a 3D object.

Hope this helps,
Fredrik
 
Share this answer
 
Comments
#realJSOP 22-Aug-13 17:56pm    
I want the angle to be such that the numbers are at less of an angle. Here's a new wrinkle. After posting the original question, I tried putting the textblock into another border so that the 3d stuff was being applied to the border instead of the text in it. The image in the designer changed, but the rendered image did not.

I'm afraid I don't know what the "look-at target" is or where to set it, but my next stop is google (again). When I change the position of the camera, it merely moves closer/further, or moves the image within the bounding container.
Fredrik Bornander 23-Aug-13 2:41am    
Look-at target can be used to calculate LookDirection on the camera, and for some it's more intuitive to use instead of the LookDirection;
<pre>camera.LookDirection = myLookAtTarget - camera.Position;
</pre>

Sometimes it helps thinking about the camera having a position and a point it's looking at rather than changing the direction (which I know is the equivalent but still different).
#realJSOP 23-Aug-13 9:22am    
I updated the code in the origianl question to give you an idea of what I'm after (you can get the specified font (Roboto Thin) from DaFont.com, but that shouldn't really matter.
Fredrik Bornander 23-Aug-13 9:32am    
Could you add an image with a rectangle positioned in 3D space like you would want the text, draw it in paint or something, then I can (probably) show you how to position your camera.
#realJSOP 23-Aug-13 12:18pm    
I am of the lightly considered opinion that the 3D stuff in WPF is buggy as hell. I was showing a coworker some of the weirdness associated with this effort. One of the weird things was that if I specified a transparent background for the text, the text would simply disappear in the designer. That was before I enclosed the textbox in its own border. So I had alreadty commented out the border, and changed the background to transparent, and the text angle became "correct". On the off chance this would generate a proper image, I ran the code, and waddayaknow? It came out the way the designer was showing it. I closed the ticket and told the customer that's as good as it gets. :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900