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;
}
}
}
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.