实例介绍
【实例简介】
实现3D图片墙功能
【实例截图】
【核心代码】
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using System.IO;
using System.Security;
namespace WPFDemo
{
public class FlipTile3D : WrapperElement<Viewport3D>
{
public FlipTile3D()
: base(new Viewport3D())
{
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(setup3D));
m_listener.Rendering = tick;
this.Unloaded = delegate(object sender, RoutedEventArgs e)
{
m_listener.StopListening();
};
}
#region render/layout overrides
protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
base.OnRender(drawingContext);
drawingContext.DrawRectangle(Brushes.Transparent, null, new Rect(this.RenderSize));
}
#endregion
#region mouse overrides
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
{
_lastMouse = e.GetPosition(this);
}
protected override void OnMouseLeave(MouseEventArgs e)
{
_lastMouse = new Point(double.NaN, double.NaN);
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
_isFlipped = !_isFlipped;
if (_isFlipped)
{
setClickedItem(e.GetPosition(this));
}
}
#endregion
#region private methods
private void setClickedItem(Point point)
{
//move point to center
point -= (new Vector(this.ActualWidth / 2, this.ActualHeight / 2));
//flip it
point.Y *= -1;
//scale it to 1x1 dimentions
double scale = Math.Min(this.ActualHeight, this.ActualWidth) / 2;
point = (Point)(((Vector)point) / scale);
//set it up so that bottomLeft = 0,0 & topRight = 1,1 (positive Y is up)
point = (Point)(((Vector)point new Vector(1, 1)) * .5);
//scale up so that the point coordinates align w/ the x/y scale
point.Y *= c_yCount;
point.X *= c_xCount;
//now we have the indicies of the x & y of the tile clicked
int yIndex = (int)Math.Floor(point.Y);
int xIndex = (int)Math.Floor(point.X);
int tileIndex = yIndex * c_xCount xIndex;
_backMaterial.Brush = _tiles[tileIndex].DiffuseMaterial.Brush;
}
private void setup3D()
{
//perf improvement. Clipping in 3D is expensive. Avoid if you can!
WrappedElement.ClipToBounds = false;
PerspectiveCamera camera = new PerspectiveCamera(
new Point3D(0, 0, 3.73), //position
new Vector3D(0, 0, -1), //lookDirection
new Vector3D(0, 1, 0), //upDirection
30 //FOV
);
WrappedElement.Camera = camera;
Model3DGroup everything = new Model3DGroup();
Model3DGroup lights = new Model3DGroup();
DirectionalLight whiteLight = new DirectionalLight(Colors.White, new Vector3D(0, 0, -1));
lights.Children.Add(whiteLight);
everything.Children.Add(lights);
ModelVisual3D model = new ModelVisual3D();
double tileSizeX = 2.0 / c_xCount;
double startX = -((double)c_xCount) / 2 * tileSizeX tileSizeX / 2;
double startY = -((double)c_yCount) / 2 * tileSizeX tileSizeX / 2;
int index;
Size tileTextureSize = new Size(1.0 / c_xCount, 1.0 / c_yCount);
//so, tiles are numbers, left-to-right (ascending x), bottom-to-top (ascending y)
for (int y = 0; y < c_yCount; y )
{
for (int x = 0; x < c_xCount; x )
{
index = y * c_xCount x;
Rect backTextureCoordinates = new Rect(
x * tileTextureSize.Width,
// this will give you a headache. Exists since we are going
// from bottom bottomLeft of 3D space (negative Y is down),
// but texture coor are negative Y is up
1 - y * tileTextureSize.Height - tileTextureSize.Height,
tileTextureSize.Width, tileTextureSize.Height);
_tiles[index] = new TileData();
_tiles[index].Setup3DItem(
everything,
getMaterial(index),
new Size(tileSizeX, tileSizeX),
new Point(startX x * tileSizeX, startY y * tileSizeX),
_backMaterial,
backTextureCoordinates);
}
}
model.Content = everything;
WrappedElement.Children.Add(model);
//start the per-frame tick for the physics
m_listener.StartListening();
}
private void tick(object sender, EventArgs e)
{
Vector mouseFixed = fixMouse(_lastMouse, this.RenderSize);
for (int i = 0; i < _tiles.Length; i )
{
//TODO: unwire Render event if nothing happens
_tiles[i].TickData(mouseFixed, _isFlipped);
}
}
private static Vector fixMouse(Point mouse, Size size)
{
Debug.Assert(size.Width >= 0 && size.Height >= 0);
double scale = Math.Max(size.Width, size.Height) / 2;
// Translate y going down to y going up
mouse.Y = -mouse.Y size.Height;
mouse.Y -= size.Height / 2;
mouse.X -= size.Width / 2;
Vector v = new Vector(mouse.X, mouse.Y);
v /= scale;
return v;
}
#endregion
#region Implementation
private DiffuseMaterial getMaterial(int index)
{
return _materials[index % _materials.Count];
}
private readonly IList<DiffuseMaterial> _materials = GetSamplePictures("Picture");
private static IList<DiffuseMaterial> GetSamplePictures(string Path)
{
IList<DiffuseMaterial> materials;
IList<string> files = null;
if (!string.IsNullOrEmpty(Path))
{
files = new List<string>();
try
{
DirectoryInfo di = new DirectoryInfo(Path);
if (di.Exists)
{
foreach (FileInfo fileInfo in di.GetFiles("*.jpg"))
{
files.Add(fileInfo.FullName);
if (files.Count > 50)
break;
}
}
}
catch (IOException) { }
catch (ArgumentException) { }
catch (SecurityException) { }
}
if (files.Count > 0)
{
materials = new List<DiffuseMaterial>();
foreach (string file in files)
{
Uri uri = new Uri(file);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = uri;
bitmapImage.DecodePixelWidth = 320;
bitmapImage.DecodePixelHeight = 240;
bitmapImage.EndInit();
bitmapImage.Freeze();
ImageBrush imageBrush = new ImageBrush(bitmapImage);
imageBrush.Stretch = Stretch.UniformToFill;
imageBrush.ViewportUnits = BrushMappingMode.Absolute;
imageBrush.Freeze();
DiffuseMaterial diffuseMaterial = new DiffuseMaterial(imageBrush);
materials.Add(diffuseMaterial);
}
}
else
{
Brush[] brushes = new Brush[] {
Brushes.LightBlue,
Brushes.Pink,
Brushes.LightGray,
Brushes.Yellow,
Brushes.Orange,
Brushes.LightGreen };
DiffuseMaterial[] materialsArray =
brushes.Select(brush => new DiffuseMaterial(brush)).ToArray();
materials = materialsArray;
}
return materials;
}
private Point _lastMouse = new Point(double.NaN, double.NaN);
private bool _isFlipped;
private readonly TileData[] _tiles = new TileData[c_xCount * c_yCount];
private readonly DiffuseMaterial _backMaterial = new DiffuseMaterial();
private readonly CompositionTargetRenderingListener m_listener =
new CompositionTargetRenderingListener();
private const int c_xCount = 7, c_yCount = 7;
#endregion
}
}
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论