今回は半透明を試してみる。完全な透明はアルファ値が最大の場合と考えればいい。
半透明を試すとなると、向こう側に透けて見える物体が欲しくなるので、立方体を3つ作ることにする。
半透明の面の作り方だが、立方体のひとつはビットマップ画像全体にアルファ値を設定する方法とした。そのために画像操作のヘルパークラス ImageHelper を追加した。ソースコードは以下のとおり。
また、のこりふたつの立方体は簡単に SolidColorBrush の Opacity を設定した。MainWindow.xaml.cs は以下のとおり。
実行結果は以下のとおり。
よく見ると、真ん中の写楽の立方体の向こうにある青と緑の立方体が透けて見えない。また、カメラを動かして青い立方体を手前に持ってくると、写楽の立方体は透けて見えるのに、緑の立方体は透けて見えない。
実は WPF の半透明(透明も)をうまく描画するためには、奥にあるものから順に書いていく必要があるようだ。。。
つづきは次回。
半透明を試すとなると、向こう側に透けて見える物体が欲しくなるので、立方体を3つ作ることにする。
半透明の面の作り方だが、立方体のひとつはビットマップ画像全体にアルファ値を設定する方法とした。そのために画像操作のヘルパークラス ImageHelper を追加した。ソースコードは以下のとおり。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
namespace sample1
{
public static class ImageHelper
{
public static Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
{
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapImage));
enc.Save(outStream);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
return new Bitmap(bitmap);
}
}
public static BitmapSource ToWpfBitmap(Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
stream.Position = 0;
BitmapImage result = new BitmapImage();
result.BeginInit();
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}
public static Bitmap CreateAlphaImage(Image srcImage, float alpha)
{
float[][] matrixItems ={
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, alpha, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(matrixItems);
ImageAttributes imageAtt = new ImageAttributes();
imageAtt.SetColorMatrix(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
int iWidth = srcImage.Width;
int iHeight = srcImage.Height;
Bitmap newImage = new Bitmap(iWidth, iHeight);
using (Graphics g = Graphics.FromImage(newImage))
{
g.DrawImage(srcImage,
new Rectangle(0, 0, iWidth, iHeight),
0.0f,
0.0f,
iWidth,
iHeight,
GraphicsUnit.Pixel,
imageAtt);
}
return newImage;
}
}
}
また、のこりふたつの立方体は簡単に SolidColorBrush の Opacity を設定した。MainWindow.xaml.cs は以下のとおり。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace sample1
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Init();
}
private void Init()
{
var root = this.Content as Grid;
// trackball
var td = new _3DTools.TrackballDecorator();
root.Children.Add(td);
// viewport
var viewport = new Viewport3D();
td.Content = viewport;
// camera
var camera = new PerspectiveCamera();
camera.Position = new Point3D(14, 13, 12);
camera.LookDirection = new Vector3D(-14, -13, -12);
camera.UpDirection = new Vector3D(0, 1, 0);
viewport.Camera = camera;
// light
var light = new DirectionalLight();
light.Color = Colors.White;
light.Direction = new Vector3D(-2, -3, -1);
var lightModel = new ModelVisual3D();
lightModel.Content = light;
viewport.Children.Add(lightModel);
// light2
var light2 = new AmbientLight();
light2.Color = Color.FromRgb(128, 128, 128);
var lightModel2 = new ModelVisual3D();
lightModel2.Content = light2;
viewport.Children.Add(lightModel2);
// axis
var xAxis = new _3DTools.ScreenSpaceLines3D();
xAxis.Points.Add(new Point3D(-100, 0, 0));
xAxis.Points.Add(new Point3D(100, 0, 0));
xAxis.Color = Colors.Red;
xAxis.Thickness = 1;
var yAxis = new _3DTools.ScreenSpaceLines3D();
yAxis.Points.Add(new Point3D(0, -100, 0));
yAxis.Points.Add(new Point3D(0, 100, 0));
yAxis.Color = Colors.Green;
yAxis.Thickness = 1;
var zAxis = new _3DTools.ScreenSpaceLines3D();
zAxis.Points.Add(new Point3D(0, 0, -100));
zAxis.Points.Add(new Point3D(0, 0, 100));
zAxis.Color = Colors.Blue;
zAxis.Thickness = 1;
var axis = new ModelVisual3D();
axis.Children.Add(xAxis);
axis.Children.Add(yAxis);
axis.Children.Add(zAxis);
viewport.Children.Add(axis);
// cube
var point0 = new Point3D(0, 0, 0); // bottom-back-left
var point1 = new Point3D(5, 0, 0); // bottom-back-right
var point2 = new Point3D(5, 0, 5); // bottom-front-right
var point3 = new Point3D(0, 0, 5); // bottom-front-left
var point4 = new Point3D(0, 5, 0); // top-back-left
var point5 = new Point3D(5, 5, 0); // top-back-right
var point6 = new Point3D(5, 5, 5); // top-front-right
var point7 = new Point3D(0, 5, 5); // top-front-left
// Y
// |
// p4 +------------------+ p5
// /| /|
// / | / |
// p7 / | p6 / |
// +------------------+ |
// | +--------------|---+---------- X
// | / p0 | / p1
// | / | /
// |/ |/
// +------------------+
// / p3 p2
// Z
var imageSrc = new BitmapImage(new Uri(@"C:\syaraku.JPG"));
var bitmap = ImageHelper.BitmapImage2Bitmap(imageSrc);
var alphaImage = ImageHelper.CreateAlphaImage(bitmap, 0.5F);
var alphaImageSrc = ImageHelper.ToWpfBitmap(alphaImage);
var material = new DiffuseMaterial(new ImageBrush(alphaImageSrc));
var group = new Model3DGroup();
group.Children.Add(new GeometryModel3D(CreateMesh(point7, point6, point2, point3), material)); // front
group.Children.Add(new GeometryModel3D(CreateMesh(point6, point5, point1, point2), material)); // right
group.Children.Add(new GeometryModel3D(CreateMesh(point5, point4, point0, point1), material)); // back
group.Children.Add(new GeometryModel3D(CreateMesh(point4, point7, point3, point0), material)); // left
group.Children.Add(new GeometryModel3D(CreateMesh(point4, point5, point6, point7), material)); // top
group.Children.Add(new GeometryModel3D(CreateMesh(point1, point0, point3, point2), material)); // bottom
var cubeModel = new ModelVisual3D();
cubeModel.Content = group;
viewport.Children.Add(cubeModel);
// cube2
var group2 = new Model3DGroup();
var br2 = new SolidColorBrush(Colors.Blue);
br2.Opacity = 0.5;
var material2 = new DiffuseMaterial(br2);
group2.Children.Add(new GeometryModel3D(CreateMesh(point7, point6, point2, point3), material2)); // front
group2.Children.Add(new GeometryModel3D(CreateMesh(point6, point5, point1, point2), material2)); // right
group2.Children.Add(new GeometryModel3D(CreateMesh(point5, point4, point0, point1), material2)); // back
group2.Children.Add(new GeometryModel3D(CreateMesh(point4, point7, point3, point0), material2)); // left
group2.Children.Add(new GeometryModel3D(CreateMesh(point1, point0, point3, point2), material2)); // bottom
group2.Children.Add(new GeometryModel3D(CreateMesh(point4, point5, point6, point7), material2)); // top
var cubeModel2 = new ModelVisual3D();
cubeModel2.Content = group2;
var trans2 = new Transform3DGroup();
trans2.Children.Add(new TranslateTransform3D(-3, -3, 3));
cubeModel2.Transform = trans2;
viewport.Children.Add(cubeModel2);
// cube3
var group3 = new Model3DGroup();
var br3 = new SolidColorBrush(Colors.Green);
br3.Opacity = 0.5;
var material3 = new DiffuseMaterial(br3);
group3.Children.Add(new GeometryModel3D(CreateMesh(point7, point6, point2, point3), material3)); // front
group3.Children.Add(new GeometryModel3D(CreateMesh(point6, point5, point1, point2), material3)); // right
group3.Children.Add(new GeometryModel3D(CreateMesh(point5, point4, point0, point1), material3)); // back
group3.Children.Add(new GeometryModel3D(CreateMesh(point4, point7, point3, point0), material3)); // left
group3.Children.Add(new GeometryModel3D(CreateMesh(point1, point0, point3, point2), material3)); // bottom
group3.Children.Add(new GeometryModel3D(CreateMesh(point4, point5, point6, point7), material3)); // top
var cubeModel3 = new ModelVisual3D();
cubeModel3.Content = group3;
var trans3 = new Transform3DGroup();
trans3.Children.Add(new TranslateTransform3D(-3, 3, -3));
cubeModel3.Transform = trans3;
viewport.Children.Add(cubeModel3);
}
private static MeshGeometry3D CreateMesh(Point3D p0, Point3D p1, Point3D p2, Point3D p3)
{
var mesh = new MeshGeometry3D();
mesh.Positions = new Point3DCollection(new Point3D[] { p0, p1, p2, p3 });
mesh.TriangleIndices = new Int32Collection(new int[] { 0, 2, 1, 0, 3, 2 });
mesh.TextureCoordinates = new PointCollection(new Point[] { new Point(0, 0), new Point(1, 0), new Point(1, 1), new Point(0, 1) });
return mesh;
}
}
}
実行結果は以下のとおり。

よく見ると、真ん中の写楽の立方体の向こうにある青と緑の立方体が透けて見えない。また、カメラを動かして青い立方体を手前に持ってくると、写楽の立方体は透けて見えるのに、緑の立方体は透けて見えない。
実は WPF の半透明(透明も)をうまく描画するためには、奥にあるものから順に書いていく必要があるようだ。。。
つづきは次回。



