3

I've been trying to make a 3D user interface in WPF for my class assignment and I ran into a problem which I can't fix for 2-3 days now. I've tried to google the answer, I've taken a look into some stackoverflow posts, but none have yet helped me to fix the issue.

So this is the situation: I have a 3D sphere on which I put 2 buttons. One button causes the material of the sphere to become transparent, and the other rotates the entire interface (Sphere + buttons)... The problem is the fact that the texture of the sphere is still there when it's transparent, so I can't see the buttons when they are at the other side of the sphere... I expected to see the buttons background at least...

Any help would be very much appreciated.

Here is my XAML:

<Window x:Class="RacunalnaGrafika_seminar.SphereWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:RacunalnaGrafika_seminar"
    AllowsTransparency="True"
    WindowStyle="None"
    Title="SphereWindow">

<Window.Resources>
    <src:SphereMeshGenerator x:Key="SphereGenerator" Center="0 0 0" Radius="0.5" />
</Window.Resources>

<Viewport3D x:Name="myViewport3D">

    <Viewport3D.Children>

        <ModelVisual3D>

            <Viewport2DVisual3D Geometry="{Binding Source={StaticResource SphereGenerator}, Path=Geometry}">

                <Viewport2DVisual3D.Material>
                    <MaterialGroup>
                        <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/>
                        <SpecularMaterial Brush="#00FFFFFF" SpecularPower="50"/>
                    </MaterialGroup>
                </Viewport2DVisual3D.Material>

                <Viewport2DVisual3D.Transform>
                    <RotateTransform3D>
                        <RotateTransform3D.Rotation>
                            <AxisAngleRotation3D x:Name="Hax" Axis="0 1 0" />
                        </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                </Viewport2DVisual3D.Transform>

                    <Viewport2DVisual3D.Visual>
                    <Canvas Background="Transparent" Width="500" Height="500">
                        <StackPanel Canvas.Top="150">
                            <Button Content="Rotate" Padding="10" >
                                <Button.Triggers>
                                    <EventTrigger RoutedEvent="Button.Click">
                                        <BeginStoryboard>
                                            <Storyboard TargetName="RotateInterface" TargetProperty="Angle">
                                                <DoubleAnimation From="0" To="360" RepeatBehavior="1x" Duration="0:0:5" />
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger>
                                </Button.Triggers>
                            </Button>
                            <Button Padding="10" Content="Click me" Click="Button_Click_1">
                                <Button.Triggers>
                                    <EventTrigger RoutedEvent="Button.Click">
                                        <BeginStoryboard>
                                            <Storyboard TargetName="SphereMaterial" TargetProperty="Color">
                                                <ColorAnimation To="Transparent" RepeatBehavior="1x" Duration="0:0:5" />
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger>
                                </Button.Triggers>
                            </Button>
                        </StackPanel>
                    </Canvas>
                </Viewport2DVisual3D.Visual>
            </Viewport2DVisual3D>

            <ModelVisual3D.Content>

                <Model3DGroup x:Name="SphereModel3DGroup">

                    <GeometryModel3D  x:Name="SphereGeometryModel" Geometry="{Binding Source={StaticResource SphereGenerator}, Path=Geometry}">

                        <GeometryModel3D.BackMaterial>
                            <DiffuseMaterial x:Name="SphereBackMaterial" Brush="Transparent" />
                        </GeometryModel3D.BackMaterial>

                        <GeometryModel3D.Material>
                            <DiffuseMaterial x:Name="SphereMaterial" > 
                                <DiffuseMaterial.Brush>
                                    <RadialGradientBrush>
                                        <GradientStop Color="#FF000000" Offset="1" />
                                        <GradientStop Color="#FF555555" Offset="0" />
                                    </RadialGradientBrush>
                                </DiffuseMaterial.Brush>
                            </DiffuseMaterial>
                        </GeometryModel3D.Material>

                        <GeometryModel3D.Transform>
                            <TranslateTransform3D />
                        </GeometryModel3D.Transform>
                    </GeometryModel3D>

                    <AmbientLight Color="White" />

                </Model3DGroup>
            </ModelVisual3D.Content>

            <ModelVisual3D.Transform>
                <RotateTransform3D>
                    <RotateTransform3D.Rotation>
                        <AxisAngleRotation3D x:Name="RotateInterface" Axis="0 1 0" />
                    </RotateTransform3D.Rotation>
                </RotateTransform3D>
            </ModelVisual3D.Transform>

        </ModelVisual3D>

    </Viewport3D.Children>

    <Viewport3D.Camera>
        <PerspectiveCamera Position="0 0 -3" LookDirection="0 0 1" UpDirection="0 1 0" FieldOfView="45" />
    </Viewport3D.Camera>

</Viewport3D>

Here is the sphere generator taken from Charles Petzold:

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace RacunalnaGrafika_seminar
{
  public class SphereMeshGenerator
  {
    private int _slices = 32;
    private int _stacks = 16;
    private Point3D _center = new Point3D();
    private double _radius = 1;

    public int Slices
    {
        get { return _slices; }
        set { _slices = value; }
    }

    public int Stacks
    {
        get { return _stacks; }
        set { _stacks = value; }
    }

    public Point3D Center
    {
        get { return _center; }
        set { _center = value; }
    }

    public double Radius
    {
        get { return _radius; }
        set { _radius = value; }
    }

    public MeshGeometry3D Geometry
    {
        get
        {
            return CalculateMesh();
        }
    }


    private MeshGeometry3D CalculateMesh()
    {
        MeshGeometry3D mesh = new MeshGeometry3D();

        for (int stack = 0; stack <= Stacks; stack++)
        {
            double phi = Math.PI / 2 - stack * Math.PI / Stacks; // kut koji zamisljeni pravac povucen iz sredista koordinatnog sustava zatvara sa XZ ravninom. 
            double y = _radius * Math.Sin(phi); // Odredi poziciju Y koordinate. 
            double scale = -_radius * Math.Cos(phi);

            for (int slice = 0; slice <= Slices; slice++)
            {
                double theta = slice * 2 * Math.PI / Slices; // Kada gledamo 2D koordinatni sustav osi X i Z... ovo je kut koji zatvara zamisljeni pravac povucen iz sredista koordinatnog sustava sa Z osi ( Z = Y ). 
                double x = scale * Math.Sin(theta); // Odredi poziciju X koordinate. Uoči da je scale = -_radius * Math.Cos(phi)
                double z = scale * Math.Cos(theta); // Odredi poziciju Z koordinate. Uoči da je scale = -_radius * Math.Cos(phi)

                Vector3D normal = new Vector3D(x, y, z); // Normala je vektor koji je okomit na površinu. U ovom slučaju normala je vektor okomit na trokut plohu trokuta. 
                mesh.Normals.Add(normal);                
                mesh.Positions.Add(normal + Center);     // Positions dobiva vrhove trokuta. 
                mesh.TextureCoordinates.Add(new Point((double)slice / Slices, (double)stack / Stacks));
                // TextureCoordinates kaže gdje će se neka točka iz 2D-a preslikati u 3D svijet. 
            }
        }

        for (int stack = 0; stack <= Stacks; stack++)
        {
            int top = (stack + 0) * (Slices + 1);
            int bot = (stack + 1) * (Slices + 1);

            for (int slice = 0; slice < Slices; slice++)
            {
                if (stack != 0)
                {
                    mesh.TriangleIndices.Add(top + slice);
                    mesh.TriangleIndices.Add(bot + slice);
                    mesh.TriangleIndices.Add(top + slice + 1);
                }

                if (stack != Stacks - 1)
                {
                    mesh.TriangleIndices.Add(top + slice + 1);
                    mesh.TriangleIndices.Add(bot + slice);
                    mesh.TriangleIndices.Add(bot + slice + 1);
                }
            }
        }

        return mesh;
      }
  }
}
user1118321
  • 25,567
  • 4
  • 55
  • 86
Marin
  • 861
  • 1
  • 11
  • 27
  • I think what you are seeing is backface culling, check this post and see if this helps http://stackoverflow.com/questions/4417457/disable-face-culling-in-wpf – dowhilefor Jan 12 '13 at 11:34
  • To be honest this is the firs time I hear about backface culling, however, as I see on the link that you posted, the person just set up the backmaterial in code to fix the problem... However, I already have that property set in XAML, perhpas I misunderstood at what you were pointing out... – Marin Jan 12 '13 at 11:50
  • But your Backmaterial is Transparent. Remember that in 3D triangles have a front and a back side usually indicated by the order of the vertices. Because they are often used to form "filled" objects, like a cube or a sphere, it wouldn't make sense to render the texture on the triangles that are facing backwards to the camera, and this is called backface culling. You need to set a material on your sphere how you want the backside to look. Yours is just transparent, try a solid color and check if thats the problem. – dowhilefor Jan 12 '13 at 12:25
  • It doesn't help... I've set the backmaterial to a solidcolorbrush with a color red, and when I make the material transparent, all I get is a Red sphere... – Marin Jan 12 '13 at 12:47

1 Answers1

1

Ok, I've just realised that I can't do this because the button has no back defined... after removing the GeometryModel3D that defined the sphere and clicking the rotate button, I've noticed that the same thing happend which means there is no back of a button... I can't believe I didn't think of this sooner.

Thanks to anyone who took the time to read my question.

Marin
  • 861
  • 1
  • 11
  • 27