Initially, the screen looks like
this:
The epicentre of this application is
the 3D cube that displays pictures of the tracks of the current album and it
rotates in clockwise direction.
Upon selection of an album (e.g.: Hindu
Devotional), the cube takes a different look with pictures representing the
tracks in the album as below.
Upon clicking the picture, another
window opens up that plays the corresponding video for you as below.
WPF – 3D Geometry and
Material
The sides of the cubes are created
separately using the MeshGeometry3D class that builds a 3D shape. It
allows us to specify position, normal, and texture coordinate
information.
<MeshGeometry3D x:Key="CubeSide01"
TriangleIndices="0,1,2
3,4,5"
Normals="-1,0,0 -1,0,0 -1,0,0 -1,0,0
-1,0,0 -1,0,0 "
TextureCoordinates="0,1 0,0 1,0 1,0
1,1 0,1 "
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 -0.5,0.5,0.5 -0.5,0.5,-0.5 "
/>
The sides of the cube compose of a
Material, DiffuseMaterial in this case that allows the application of a
2-D brush, like a SolidColorBrush or TileBrush, to a diffusely-lit 3-D model.
For the album selected in the list, this Material is applied on the sides
dynamically, ImageBrush for the albums(Devotional and Taare Zameen Par)
that contains video tracks and LinearGradientBrush for no selection or
album(Pop/Rock) that has only one video.
<MaterialGroup
x:Key="TaareMaterial1">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush
Stretch="Fill" ImageSource="images\Taare\Taare1.jpg" TileMode="None"
ViewportUnits="Absolute" Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top"
Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</MaterialGroup>
Both the Geometry and Material
specifics are coded as Application Resources in app.xaml.
XAML for 3D Graphics
<Viewport3D
MouseDown="myViewport_MouseDown" ClipToBounds="True" Width="600" Height="400"
Name="myViewport" Focusable="True" >
<Viewport3D.Camera>
<PerspectiveCamera
x:Name="myPerspectiveCamera"
FarPlaneDistance="15"
LookDirection="0,0,1" UpDirection="0,1,0" NearPlaneDistance="1"
Position="0,0,-3" FieldOfView="50" />
</Viewport3D.Camera>
<ModelVisual3D
x:Name="topModelVisual3D">
<ModelVisual3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
...............
...............
<ModelVisual3D
x:Name="side1ModelVisual">
<ModelVisual3D.Content>
<GeometryModel3D
x:Name="side1GeometryModel3D" Geometry="{StaticResource CubeSide01}"
Material="{StaticResource InitMaterial1}" BackMaterial="{StaticResource
InsideMaterial}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
HitTest
The HitTest is the action that is taken
when the user clicks on a side of the 3D cube. This is implemented in the
ChooseTrack method wherein the mouseposition parameters are retrieved
from the MouseButtonEventArgs and test for a result in the
ViewPort3D.
public void ChooseTrack(object sender,
System.Windows.Input.MouseButtonEventArgs args)
{
if (listboxAlbum.SelectedIndex <=
0)
return;
Point mouseposition =
args.GetPosition(myViewport);
PointHitTestParameters pointparams =
new PointHitTestParameters(mouseposition);
//test for a result in the
Viewport3D
VisualTreeHelper.HitTest(myViewport,
null, HTResult, pointparams);
}
The HitTest method takes the
ViewPort object as parameter along with a callback method HTResult
and the position parameters. It is in the callback method HTResult, we
use the RayMeshGeometry3DHitTestResult object and calls the
ModelHit to get the GeometryModel3D object for the 3Dimensional shape
where the user hit the mouse.
public HitTestResultBehavior
HTResult(System.Windows.Media.HitTestResult rawresult)
{
RayHitTestResult rayResult =
rawresult as RayHitTestResult;
if (rayResult != null)
{
RayMeshGeometry3DHitTestResult
rayMeshResult = rayResult as RayMeshGeometry3DHitTestResult;
if (rayMeshResult !=
null)
{
GeometryModel3D hitgeo =
rayMeshResult.ModelHit as GeometryModel3D;
SetTrack(hitgeo);
PlayTrack();
}
}
return
HitTestResultBehavior.Stop;
}
There are two helper methods
SetTrack to select the track and PlayTrack to open the
mediaElement in a window to play the video. In the SetTrack method,
MusicPlayer instance is created and the properties CurrentAlbum
and CurrentTrackPath are set by calling the FindAlbum and
FindTrack methods respectively.
public void SetTrack(GeometryModel3D
hitgeo)
{
mplayer = new MusicPlayer();
mplayer.currentAlbum =
AvailTracks.FindAlbum(listboxAlbum.SelectedIndex - 1);
// For pop/rock, only one video is
placed. On clicking any picture on any of the 6 sides, the same video
plays.
if (listboxAlbum.SelectedIndex ==
2)
{
mplayer.currtrapath =
AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 0);
return;
}
if
(hitgeo.Geometry==MeshGeometry3D)Application.Current.Resources["CubeSide01"])
{
mplayer.currtrapath
=AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 0);
}
else if
(hitgeo.Geometry==(MeshGeometry3D)Application.Current.Resources["CubeSide02"])
{
mplayer.currtrapath
=AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 1);
}
else if (hitgeo.Geometry ==
(MeshGeometry3D)Application.Current.Resources["CubeSide03"])
{
mplayer.currtrapath =
AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 2);
}
else if (hitgeo.Geometry ==
(MeshGeometry3D)Application.Current.Resources["CubeSide04"])
{
mplayer.currtrapath =
AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 3);
}
else if (hitgeo.Geometry ==
(MeshGeometry3D)Application.Current.Resources["CubeSide05"])
{
mplayer.currtrapath =
AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 4);
}
else if (hitgeo.Geometry ==
(MeshGeometry3D)Application.Current.Resources["CubeSide06"])
{
mplayer.currtrapath =
AvailTracks.FindTrack(listboxAlbum.SelectedIndex - 1, 5);
}
}
In the PlayTrack method, the
MusicPlayer is shown as dialog as coded below.
public void
PlayTrack()
{
mplayer.ShowDialog();
}
|