using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Xml;
namespace HelixToolkit
{
///
/// Export the WPF3D visual tree to a Kerkythea xml file
/// Kerkythea: http://www.kerkythea.net/joomla
///
public class KerkytheaExporter : Exporter
{
#region RenderSettings enum
public enum RenderSettings
{
RayTracer,
PhotonMap,
MetropolisLightTransport
} ;
#endregion
private readonly HashSet names = new HashSet();
private readonly XmlWriter writer;
public Dictionary RegisteredMaterials = new Dictionary();
///
/// Initializes a new instance of the class.
///
/// Name of the output file.
public KerkytheaExporter(string outputFileName)
{
Name = "My Scene";
BackgroundColor = Colors.Black;
ReflectionColor = Colors.Gray;
Reflections = true;
Shadows = true;
SoftShadows = true;
LightMultiplier = 3.0;
Threads = 2;
ShadowColor = Color.FromArgb(255, 100, 100, 100);
RenderSetting = RenderSettings.RayTracer;
Aperture = "Pinhole";
FocusDistance = 1.0;
LensSamples = 3;
Width = 500;
Height = 500;
TexturePath = Path.GetDirectoryName(outputFileName);
TextureWidth = 1024;
TextureHeight = 1024;
var settings = new XmlWriterSettings { Indent = true, };
writer = XmlWriter.Create(outputFileName, settings);
}
public Color BackgroundColor { get; set; }
public double LightMultiplier { get; set; }
public bool Reflections { get; set; }
public Color ReflectionColor { get; set; }
public bool Shadows { get; set; }
public bool SoftShadows { get; set; }
public Color ShadowColor { get; set; }
public RenderSettings RenderSetting { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int Threads { get; set; }
public string Name { get; set; }
public double FocalLength { get; set; }
public double FocusDistance { get; set; }
public string Aperture { get; set; }
public int LensSamples { get; set; }
public string TexturePath { get; set; }
public int TextureWidth { get; set; }
public int TextureHeight { get; set; }
public void RegisterMaterial(Material m, string filename)
{
var doc = new XmlDocument();
doc.Load(filename);
RegisteredMaterials.Add(m, doc);
}
protected override void ExportHeader()
{
writer.WriteStartDocument();
writer.WriteStartElement("Root");
writer.WriteAttributeString("Label", "Default Kernel");
writer.WriteAttributeString("Name", "");
writer.WriteAttributeString("Type", "Kernel");
WriteStartObject("./Modellers/XML Modeller", "XML Modeller", "XML Modeller", "Modeller");
WriteEndObject();
WriteStartObject("./Image Handlers/Free Image Support", "Free Image Support", "Free Image Support",
"Image Handler");
WriteParameter("Tone Mapping", "External");
WriteParameter("Jpeg Quality", "Higher");
WriteEndObject();
WriteStartObject("./Direct Light Estimators/Refraction Enhanced", "Refraction Enhanced",
"Refraction Enhanced", "Direct Light Estimator");
WriteParameter("Enabled", "Boolean", "1");
WriteParameter("PseudoCaustics", "Boolean", "0");
WriteParameter("PseudoTranslucencies", "Boolean", "0");
WriteParameter("Area Light Evaluation", "Boolean", "1");
WriteParameter("Optimized Area Lights", "Boolean", "1");
WriteParameter("Accurate Soft Shadows", "Boolean", "0");
WriteParameter("Antialiasing", "String", "High");
WriteParameter("./Evaluation/Diffuse", "Boolean", "1");
WriteParameter("./Evaluation/Specular", "Boolean", "1");
WriteParameter("./Evaluation/Translucent", "Boolean", "1");
WriteParameter("./Evaluation/Transmitted", "Boolean", "1");
WriteEndObject();
// add ray tracer module.
for (int i = 0; i < Threads; i++)
{
WriteStandardRayTracer("#" + i);
}
WriteThreadedRaytracer(Threads);
// add spatial subdivision module.
WriteStartObject("./Environments/Octree Environment", "Octree Environment", "Octree Environment",
"Environment");
WriteParameter("Max Objects per Cell", 20);
WriteParameter("Instancing Switch", 1000000);
WriteParameter("Caching Switch", 6000000);
WriteEndObject();
// add basic post filtering / tone mapping.
WriteStartObject("./Filters/Simple Tone Mapping", "Simple Tone Mapping", "", "Filter");
WriteParameter("Enabled", true);
WriteParameter("Method", "Simple");
WriteParameter("Exposure", 1.0);
WriteParameter("Gamma", 1.0);
WriteParameter("Dark Multiplier", 1.0);
WriteParameter("Bright Multiplier", 1.0);
WriteParameter("Reverse Correction", true);
WriteParameter("Reverse Gamma", 2.2);
WriteEndObject();
// start of scene description.
WriteStartObject("./Scenes/" + Name, "Default Scene", Name, "Scene");
}
public void WriteMetropolisLightTransport(string name)
{
WriteStartObject("./Ray Tracers/" + name, "Metropolis Light Transport", name, "Ray Tracer");
WriteParameter("Max Ray Tracing Depth", 100);
WriteParameter("Max Iterations", 10000);
WriteParameter("Linear Lightflow", true);
WriteParameter("Seed Paths", 50000);
WriteParameter("Large Step Probability", 0.2);
WriteParameter("Max Mutation Distance", 0.02);
WriteParameter("Live Probability", 0.7);
WriteParameter("Max Consecutive Rejections", 200);
WriteParameter("Bidirectional", true);
WriteParameter("Super Sampling", "3x3");
WriteParameter("Image Filename", "temp.jpg");
WriteParameter("Random Seed", "Automatic");
WriteEndObject();
}
public void WriteStandardRayTracer(string name)
{
WriteStartObject("./Ray Tracers/" + name, "Standard Ray Tracer", name, "Ray Tracer");
WriteParameter("Rasterization", "Auto");
// WriteParameter("Antialiasing", "Extra Pass 3x3");
WriteParameter("Antialiasing", "Production AA");
WriteParameter("Antialiasing Filter", "Mitchell-Netravali 0.5 0.8");
WriteParameter("Antialiasing Threshold", 0.3);
WriteParameter("Texture Filtering", true);
WriteParameter("Ambient Lighting", true);
WriteParameter("Direct Lighting", true);
WriteParameter("Sky Lighting", true);
WriteParameter("Brightness Threshold", 0.002);
WriteParameter("Max Ray Tracing Depth", 5);
WriteParameter("Max Scatter Bounces", 5);
WriteParameter("Max Dirac Bounces", 5);
WriteParameter("Irradiance Precomputation", 4);
WriteParameter("Irradiance Scale", Colors.White);
WriteParameter("Linear Lightflow", true);
WriteParameter("Max Iterations", 5);
WriteParameter("Super Sampling", "None");
WriteParameter("Image Filename", "temp.jpg");
WriteParameter("./Sampling Criteria/Diffuse Samples", 1024);
WriteParameter("./Sampling Criteria/Specular Samples", 32);
WriteParameter("./Sampling Criteria/Dispersion Samples", true);
WriteParameter("./Sampling Criteria/Trace Diffusers", false);
WriteParameter("./Sampling Criteria/Trace Translucencies", false);
WriteParameter("./Sampling Criteria/Trace Fuzzy Reflections", true);
WriteParameter("./Sampling Criteria/Trace Fuzzy Refractions", true);
WriteParameter("./Sampling Criteria/Trace Reflections", true);
WriteParameter("./Sampling Criteria/Trace Refractions", true);
WriteParameter("./Sampling Criteria/Random Generator", "Pure");
WriteEndObject();
}
public void WriteThreadedRaytracer(int threads)
{
WriteStartObject("./Ray Tracers/Threaded Ray Tracer", "Threaded Ray Tracer", "Threaded Ray Tracer",
"Ray Tracer");
for (int i = 0; i < threads; i++)
{
WriteParameter("Thread #" + i, "#" + i);
}
WriteParameter("Network Mode", "None");
WriteParameter("Listening Port", 6200);
WriteParameter("Host", "127.0.0.1");
WriteEndObject();
}
public override void Close()
{
// end of scene description.
writer.WriteFullEndElement();
// it is necessary to describe the primary/active modules as there might exist more than one!
WriteParameter("Mip Mapping", true);
WriteParameter("./Interfaces/Active", "Null Interface");
WriteParameter("./Modellers/Active", "XML Modeller");
WriteParameter("./Image Handlers/Active", "Free Image Support");
WriteParameter("./Ray Tracers/Active", "Threaded Ray Tracer");
WriteParameter("./Irradiance Estimators/Active", "Null Irradiance Estimator");
WriteParameter("./Direct Light Estimators/Active", "Refraction Enhanced");
WriteParameter("./Environments/Active", "Octree Environment");
WriteParameter("./Filters/Active", "Simple Tone Mapping");
WriteParameter("./Scenes/Active", Name);
WriteParameter("./Libraries/Active", "Material Librarian");
// end of root element
writer.WriteFullEndElement();
writer.WriteEndDocument();
writer.Close();
base.Close();
}
protected override void ExportCamera(Camera c)
{
var pc = c as PerspectiveCamera;
if (pc == null)
throw new InvalidOperationException("Only perspective cameras are supported.");
const string name = "Camera #1";
WriteStartObject("./Cameras/" + name, "Pinhole Camera", name, "Camera");
// FOV = 2 arctan (x / (2 f)), x is diagonal, f is focal length
// f = x / 2 / Tan(FOV/2)
// http://en.wikipedia.org/wiki/Angle_of_view
// http://kmp.bdimitrov.de/technology/fov.html
// PerspectiveCamera.FieldOfView: Horizontal field of view
// Must multiply by ratio of Viewport Width/Height
double ratio = Width / (double)Height;
const double x = 40;
double f = 0.5 * ratio * x / Math.Tan(0.5 * pc.FieldOfView / 180.0 * Math.PI);
WriteParameter("Focal Length (mm)", f);
WriteParameter("Film Height (mm)", x);
WriteParameter("Resolution", String.Format(CultureInfo.InvariantCulture, "{0}x{1}", Width, Height));
var t = CreateTransform(pc.Position, pc.LookDirection, pc.UpDirection);
WriteTransform("Frame", t);
WriteParameter("Focus Distance", FocusDistance);
WriteParameter("f-number", Aperture);
WriteParameter("Lens Samples", LensSamples);
WriteParameter("Blades", 6);
WriteParameter("Diaphragm", "Circular");
WriteParameter("Projection", "Planar");
WriteEndObject();
}
protected override void ExportLight(Light l, Transform3D t)
{
if (l is AmbientLight)
{
return;
}
string name = GetUniqueName(l, l.GetType().Name);
var d = l as DirectionalLight;
var s = l as SpotLight;
var p = l as PointLight;
WriteStartObject("./Lights/" + name, "Default Light", name, "Light");
{
string stype = "Projector Light";
if (s != null)
{
stype = "Spot Light";
}
if (p != null)
{
stype = "Omni Light";
}
WriteStartObject(stype, stype, "", "Emittance");
// emitter Radiance
WriteStartObject("./Radiance/Constant Texture", "Constant Texture", "", "Texture");
var c = Colors.White;
WriteParameter("Color", c);
WriteEndObject();
// var v = new Vector3D(l.Color.R, l.Color.G, l.Color.B);
// double lum = v.Length;
WriteParameter("Attenuation", "None");
// SpotLight (Spot Light)
if (s != null)
{
// todo : export the specular parameters
// s.ConstantAttenuation
// s.LinearAttenuation
// s.QuadraticAttenuation
WriteParameter("Fall Off", s.OuterConeAngle);
WriteParameter("Hot Spot", s.InnerConeAngle);
}
// DirectionalLight (Projector Light)
if (d != null)
{
WriteParameter("Width", 2.0);
WriteParameter("Height", 2.0);
}
// PointLight (Omni light)
if (p != null)
{
// todo: export pointlight parameters
// p.ConstantAttenuation
// p.LinearAttenuation
// p.QuadraticAttenuation
// p.Range // distance beyond which the light has no effect
}
WriteParameter("Focal Length", 1.0);
WriteEndObject(); // stype
WriteParameter("Enabled", true);
WriteParameter("Shadow", Shadows);
WriteParameter("Soft Shadow", SoftShadows);
WriteParameter("Negative Light", false);
WriteParameter("Global Photons", true);
WriteParameter("Caustic Photons", true);
WriteParameter("Multiplier", LightMultiplier);
Matrix3D transform;
var upVector = new Vector3D(0, 0, 1);
if (s != null)
{
transform = CreateTransform(s.Position, s.Direction, upVector);
WriteTransform("Frame", transform);
}
if (d != null)
{
var origin = new Point3D(-1000 * d.Direction.X, -1000 * d.Direction.Y, -1000 * d.Direction.Z);
transform = CreateTransform(origin, d.Direction, upVector);
WriteTransform("Frame", transform);
}
if (p != null)
{
var direction = new Vector3D(-p.Position.X, -p.Position.Y, -p.Position.Z);
transform = CreateTransform(p.Position, direction, upVector);
WriteTransform("Frame", transform);
}
WriteParameter("Focus Distance", 4.0);
WriteParameter("Radius", 0.2);
WriteParameter("Shadow Color", ShadowColor);
}
WriteEndObject();
}
///
/// Create transform from the original coordinate system to the system defined by translation origin
///
private static Matrix3D CreateTransform(Point3D origin, Vector3D direction, Vector3D up)
{
var z = direction;
var x = Vector3D.CrossProduct(direction, up);
var y = up;
x.Normalize();
y.Normalize();
z.Normalize();
var m = new Matrix3D(x.X, y.X, z.X, 0, x.Y, y.Y, z.Y, 0, x.Z, y.Z, z.Z, 0, origin.X, origin.Y, origin.Z, 1);
return m;
}
public void WriteTransform(string name, Matrix3D m)
{
string value = String.Format(CultureInfo.InvariantCulture,
"{0:0.######} {1:0.######} {2:0.######} {3:0.######} {4:0.######} {5:0.######} {6:0.######} {7:0.######} {8:0.######} {9:0.######} {10:0.######} {11:0.######}",
m.M11, m.M12, m.M13, m.OffsetX,
m.M21, m.M22, m.M23, m.OffsetY,
m.M31, m.M32, m.M33, m.OffsetZ);
WriteParameter(name, "Transform", value);
}
// Transposed version
public void WriteTransformT(string name, Matrix3D m)
{
string value = String.Format(CultureInfo.InvariantCulture,
"{0:0.######} {1:0.######} {2:0.######} {3:0.######} {4:0.######} {5:0.######} {6:0.######} {7:0.######} {8:0.######} {9:0.######} {10:0.######} {11:0.######}",
m.M11, m.M21, m.M31, m.OffsetX,
m.M12, m.M22, m.M32, m.OffsetY,
m.M13, m.M23, m.M33, m.OffsetZ);
WriteParameter(name, "Transform", value);
}
public void ExportMesh(MeshGeometry3D m)
{
WriteStartObject("Triangular Mesh", "Triangular Mesh", "", "Surface");
writer.WriteStartElement("Parameter");
{
writer.WriteAttributeString("Name", "Vertex List");
writer.WriteAttributeString("Type", "Point3D List");
writer.WriteAttributeString("Value", m.Positions.Count.ToString());
foreach (var p in m.Positions)
{
writer.WriteStartElement("P");
writer.WriteAttributeString("xyz", ToKerkytheaString(p));
writer.WriteEndElement();
}
}
writer.WriteFullEndElement();
int triangles = m.TriangleIndices.Count / 3;
// NORMALS
// todo: write normal list per vertex instead of per triangle index
if (m.Normals.Count > 0)
{
writer.WriteStartElement("Parameter");
{
writer.WriteAttributeString("Name", "Normal List");
writer.WriteAttributeString("Type", "Point3D List");
writer.WriteAttributeString("Value", m.TriangleIndices.Count.ToString());
foreach (int index in m.TriangleIndices)
{
if (index >= m.Normals.Count)
{
continue;
}
var n = m.Normals[index];
writer.WriteStartElement("P");
writer.WriteAttributeString("xyz", ToKerkytheaString(n));
writer.WriteEndElement();
}
}
writer.WriteFullEndElement();
}
// TRIANGLE INDICES
writer.WriteStartElement("Parameter");
{
writer.WriteAttributeString("Name", "Index List");
writer.WriteAttributeString("Type", "Triangle Index List");
writer.WriteAttributeString("Value", triangles.ToString());
for (int a = 0; a < triangles; a++)
{
int i = m.TriangleIndices[a * 3];
int j = m.TriangleIndices[a * 3 + 1];
int k = m.TriangleIndices[a * 3 + 2];
writer.WriteStartElement("F");
writer.WriteAttributeString("ijk", String.Format("{0} {1} {2}", i, j, k));
writer.WriteEndElement();
}
}
writer.WriteFullEndElement();
WriteParameter("Smooth", true);
WriteParameter("AA Tolerance", 15.0);
WriteEndObject();
}
protected override void ExportModel(GeometryModel3D g, Transform3D transform)
{
var mesh = g.Geometry as MeshGeometry3D;
if (mesh == null)
{
return;
}
string name = GetUniqueName(g, g.GetType().Name);
WriteStartObject("./Models/" + name, "Default Model", name, "Model");
ExportMesh(mesh);
if (g.Material != null)
{
ExportMaterial(g.Material);
}
var tg = new Transform3DGroup();
tg.Children.Add(g.Transform);
tg.Children.Add(transform);
ExportMapChannel(mesh);
WriteTransformT("Frame", tg.Value);
WriteParameter("Enabled", true);
WriteParameter("Visible", true);
WriteParameter("Shadow Caster", true);
WriteParameter("Shadow Receiver", true);
WriteParameter("Caustics Transmitter", true);
WriteParameter("Caustics Receiver", true);
WriteParameter("Exit Blocker", false);
WriteEndObject();
}
private void ExportMapChannel(MeshGeometry3D m)
{
writer.WriteStartElement("Parameter");
{
writer.WriteAttributeString("Name", "Map Channel");
writer.WriteAttributeString("Type", "Point2D List");
int n = m.TriangleIndices.Count;
writer.WriteAttributeString("Value", n.ToString());
foreach (int index in m.TriangleIndices)
{
if (index >= m.TextureCoordinates.Count)
{
continue;
}
var uv = m.TextureCoordinates[index];
writer.WriteStartElement("P");
writer.WriteAttributeString("xy", ToKerkytheaString(uv));
writer.WriteEndElement();
}
}
writer.WriteFullEndElement();
}
private Color GetSolidColor(Brush brush, Color fallbackColor)
{
var scb = brush as SolidColorBrush;
if (scb != null)
{
return scb.Color;
}
return fallbackColor;
}
private void WriteWeight(string identifier, double weight)
{
WriteStartObject(identifier, "Weighted Texture", identifier, "Texture");
WriteStartObject("Constant Texture", "Constant Texture", "", "Texture");
WriteParameter("Color", Colors.White);
WriteEndObject();
WriteParameter("Weight #0", weight);
WriteEndObject();
}
private void WriteDielectricMaterial(string identifier, Color? reflection, Color? refraction,
double indexOfRefraction = 1.0, double dispersion = 0.0,
string nkfile = null)
{
WriteStartObject(identifier, "Ashikhmin Material", identifier, "Material");
if (reflection.HasValue)
WriteConstantTexture("Reflection", reflection.Value);
if (refraction.HasValue)
WriteConstantTexture("Refraction", refraction.Value);
WriteParameter("Index of Refraction", indexOfRefraction);
WriteParameter("Dispersion", dispersion);
WriteParameter("N-K File", "");
WriteEndObject();
}
private void WriteAshikhminMaterial(string identifier, Color? diffuse, Color? specular,
Color? shininessXMap, Color? shininessYMap, Color? rotationMap,
double shininessX = 100, double shininessY = 100,
double rotation = 0, double indexOfRefraction = 1.0, string nkfile = null)
{
WriteStartObject(identifier, "Ashikhmin Material", identifier, "Material");
if (diffuse.HasValue)
WriteConstantTexture("Diffuse", diffuse.Value);
if (specular.HasValue)
WriteConstantTexture("Specular", specular.Value);
if (shininessXMap.HasValue)
WriteConstantTexture("Shininess X Map", shininessXMap.Value);
if (shininessYMap.HasValue)
WriteConstantTexture("Shininess Y Map", shininessYMap.Value);
if (rotationMap.HasValue)
WriteConstantTexture("RotationMap", rotationMap.Value);
WriteParameter("Shininess X", shininessX);
WriteParameter("Shininess Y", shininessY);
WriteParameter("Rotation", rotation);
WriteParameter("Attenuation", "Schlick");
WriteParameter("Index of Refraction", indexOfRefraction);
WriteParameter("N-K File", nkfile);
WriteEndObject();
}
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
private void WriteWhittedMaterial(string identifier, string texture, Color? diffuse, Color? specular,
Color? refraction,
double shininess = 128.0, double indexOfRefraction = 1.0)
{
WriteStartObject(identifier, "Whitted Material", identifier, "Material");
if (texture != null)
WriteBitmapTexture("Diffuse", texture);
if (diffuse.HasValue)
WriteConstantTexture("Diffuse", diffuse.Value);
if (specular.HasValue)
WriteConstantTexture("Specular", specular.Value);
if (refraction.HasValue)
WriteConstantTexture("Refraction", refraction.Value);
WriteParameter("Shininess", shininess);
WriteParameter("Transmitted Shininess", 128.0);
WriteParameter("Index of Refraction", indexOfRefraction);
WriteParameter("Specular Sampling", false);
WriteParameter("Transmitted Sampling", false);
WriteParameter("Specular Attenuation", "Cosine");
WriteParameter("Transmitted Attenuation", "Cosine");
WriteEndObject();
}
private void WriteConstantTexture(string name, Color color)
{
WriteStartObject("./" + name + "/Constant Texture", "Constant Texture", "", "Texture");
WriteParameter("Color", color);
WriteEndObject();
}
private void WriteBitmapTexture(string name, string filename)
{
if (!String.IsNullOrEmpty(filename))
{
WriteStartObject("./" + name + "/Bitmap Texture", "Bitmap Texture", "", "Texture");
WriteParameter("Filename", filename);
WriteParameter("Projection", "UV");
WriteParameter("Offset X", 0.0);
WriteParameter("Offset Y", 0.0);
WriteParameter("Scale X", 1.0);
WriteParameter("Scale Y", 1.0);
WriteParameter("Rotation", 0.0);
WriteParameter("Smooth", true);
WriteParameter("Inverted", false);
WriteParameter("Alpha Channel", false);
WriteEndObject();
}
}
private void ExportMaterial(string name, Material material, ICollection weights)
{
var g = material as MaterialGroup;
if (g != null)
{
foreach (var m in g.Children)
{
ExportMaterial(name, m, weights);
}
}
var d = material as DiffuseMaterial;
if (d != null)
{
string texture = null;
Color? color = null;
double alpha = 1.0;
if (d.Brush is SolidColorBrush)
{
color = GetSolidColor(d.Brush, d.Color);
alpha = color.Value.A / 255.0;
}
else
texture = GetTexture(d.Brush, name);
if (alpha > 0)
{
WriteWhittedMaterial(string.Format("#{0}", weights.Count), texture, color, null, null);
weights.Add(alpha);
}
// The refractive part
if (alpha < 1)
{
WriteWhittedMaterial(string.Format("#{0}", weights.Count), null, null, null, Colors.White);
weights.Add(1 - alpha);
}
}
var s = material as SpecularMaterial;
if (s != null)
{
var color = GetSolidColor(s.Brush, s.Color);
// color = Color.FromArgb((byte)(color.A * factor), (byte)(color.R * factor), (byte)(color.G * factor), (byte)(color.B * factor));
WriteWhittedMaterial(string.Format("#{0}", weights.Count), null, null, color, null, s.SpecularPower * 0.5);
double weight = color.A / 255.0;
weight *= 0.01;
weights.Add(weight);
}
var e = material as EmissiveMaterial;
if (e != null)
{
Trace.WriteLine("KerkytheaExporter: Emissive materials are not yet supported.");
//Color color = GetSolidColor(e.Brush, d.Color);
//WriteWhittedMaterial(string.Format("#{0}", weights.Count + 1), color, null, null);
// WriteStartObject("./Translucent/Constant Texture", "Constant Texture", "", "Texture");
// WriteParameter("Color", e.Color);
// WriteEndObject();
}
}
///
/// Texture bitmaps are reused. This dictionary contains a map from brush to filename
///
private readonly Dictionary textureFiles = new Dictionary();
private string GetTexture(Brush brush, string name)
{
// reuse textures
if (textureFiles.ContainsKey(brush))
return textureFiles[brush];
string filename = name + ".png";
string path = Path.Combine(TexturePath, filename);
RenderBrush(path, brush, TextureWidth, TextureHeight);
textureFiles.Add(brush, filename);
return filename;
}
private void ExportMaterial(Material material)
{
// If the material is registered, simply output the xml
if (RegisteredMaterials.ContainsKey(material))
{
var doc = RegisteredMaterials[material];
if (doc != null && doc.DocumentElement != null)
foreach (XmlNode e in doc.DocumentElement.ChildNodes)
{
e.WriteTo(writer);
}
return;
}
string name = GetUniqueName(material, "Material");
WriteStartObject(name, "Layered Material", name, "Material");
var weights = new List();
ExportMaterial(name, material, weights);
//if (Reflections)
//{
// WriteConstantTexture("Reflection", ReflectionColor);
//}
for (int i = 0; i < weights.Count; i++)
{
WriteWeight("Weight #" + i, weights[i]);
}
/*
switch (MaterialType)
{
case MaterialTypes.Ashikhmin:
WriteParameter("Rotation", 0.0);
WriteParameter("Attenuation", "Schlick");
WriteParameter("Index of Refraction", 1.0);
WriteParameter("N-K File", "");
break;
case MaterialTypes.Diffusive: // Whitted material
WriteParameter("Shininess", 60.0);
WriteParameter("Transmitted Shininess", 128.0);
WriteParameter("Index of Refraction", 1.0);
WriteParameter("Specular Sampling", true);
WriteParameter("Transmitted Sampling", false);
WriteParameter("Specular Attenuation", "Cosine");
WriteParameter("Transmitted Attenuation", "Cosine");
break;
}
*/
WriteEndObject();
}
private string GetUniqueName(DependencyObject o, string defaultName)
{
var name = o.GetValue(FrameworkElement.NameProperty) as string;
if (String.IsNullOrEmpty(name))
{
int n = 1;
while (true)
{
// name = defaultName + " #" + n;
name = defaultName + n;
if (!names.Contains(name))
{
break;
}
n++;
}
}
names.Add(name);
return name;
}
// Viewport3D
// ModelVisual3D : Visual3D
// GeometryModel3D
// DirectionalLight
// AmbientLight
// PointLight
// SpotLight
// Model3DGroup
// Model3DCollection
// GeometryModel3D
// Model3DGroup
// ModelUIElement3D : UIElement3D : Visual3D
protected override void ExportViewport(Viewport3D v)
{
var ambient = Visual3DHelper.Find(v);
// default global settings
WriteStartObject("Default Global Settings", "Default Global Settings", "", "Global Settings");
if (ambient != null)
{
WriteParameter("Ambient Light", ambient.Color);
}
WriteParameter("Background Color", BackgroundColor);
WriteParameter("Compute Volume Transfer", false);
WriteParameter("Transfer Recursion Depth", 1);
WriteParameter("Background Type", "Sky Color");
WriteParameter("Sky Intensity", 1.0);
WriteParameter("Sky Frame", "Transform", "1 0 0 0 0 1 0 0 0 0 1 0 ");
WriteParameter("Sun Direction", "0 0 1");
WriteParameter("Sky Turbidity", 2.0);
WriteParameter("Sky Luminance Gamma", 1.2);
WriteParameter("Sky Chromaticity Gamma", 1.8);
WriteParameter("Linear Lightflow", true);
WriteParameter("Index of Refraction", 1.0);
WriteParameter("Scatter Density", 0.1);
WriteParameter("./Location/Latitude", 0.0);
WriteParameter("./Location/Longitude", 0.0);
WriteParameter("./Location/Timezone", 0);
WriteParameter("./Location/Date", "0/0/2007");
WriteParameter("./Location/Time", "12:0:0");
WriteParameter("./Background Image/Filename", "[No Bitmap]");
WriteParameter("./Background Image/Projection", "UV");
WriteParameter("./Background Image/Offset X", 0.0);
WriteParameter("./Background Image/Offset Y", 0.0);
WriteParameter("./Background Image/Scale X", 1.0);
WriteParameter("./Background Image/Scale Y", 1.0);
WriteParameter("./Background Image/Rotation", 0.0);
WriteParameter("./Background Image/Smooth", true);
WriteParameter("./Background Image/Inverted", false);
WriteParameter("./Background Image/Alpha Channel", false);
WriteEndObject();
// Visual3DHelper.Traverse(v.Children, ExportLight);
// Visual3DHelper.Traverse(v.Children, ExportGeometryModel3D);
}
private static double NotNaN(double value, double defaultValue)
{
if (double.IsNaN(value))
{
return defaultValue;
}
return value;
}
private static string ToKerkytheaString(Point p)
{
return String.Format(CultureInfo.InvariantCulture, "{0} {1}", p.X, p.Y);
}
private static string ToKerkytheaString(Point3D p)
{
return String.Format(CultureInfo.InvariantCulture, "{0:0.######} {1:0.######} {2:0.######}", NotNaN(p.X, 1),
NotNaN(p.Y, 0), NotNaN(p.Z, 0));
}
private static string ToKerkytheaString(Vector3D p)
{
return String.Format(CultureInfo.InvariantCulture, "{0:0.######} {1:0.######} {2:0.######}", NotNaN(p.X, 1),
NotNaN(p.Y, 0), NotNaN(p.Z, 0));
}
private static string ToKerkytheaString(Color c)
{
return String.Format(CultureInfo.InvariantCulture, "{0:0.######} {1:0.######} {2:0.######}", c.R / 255.0,
c.G / 255.0, c.B / 255.0);
}
#region helper methods
private void WriteParameter(string name, string type, string value)
{
writer.WriteStartElement("Parameter");
writer.WriteAttributeString("Name", name);
writer.WriteAttributeString("Type", type);
writer.WriteAttributeString("Value", value);
writer.WriteEndElement();
}
private void WriteParameter(string p, string value)
{
WriteParameter(p, "String", value);
}
private void WriteParameter(string p, Color color)
{
WriteParameter(p, "RGB", ToKerkytheaString(color));
}
private void WriteParameter(string p, bool flag)
{
WriteParameter(p, "Boolean", flag ? "1" : "0");
}
private void WriteParameter(string p, double value)
{
WriteParameter(p, "Real", value.ToString(CultureInfo.InvariantCulture));
}
private void WriteParameter(string p, int value)
{
WriteParameter(p, "Integer", value.ToString(CultureInfo.InvariantCulture));
}
protected void WriteObject(string identifier, string label, string name, string type)
{
WriteStartObject(identifier, label, name, type);
WriteEndObject();
}
protected void WriteStartObject(string identifier, string label, string name, string type)
{
writer.WriteStartElement("Object");
writer.WriteAttributeString("Identifier", identifier);
writer.WriteAttributeString("Label", label);
writer.WriteAttributeString("Name", name);
writer.WriteAttributeString("Type", type);
}
protected void WriteEndObject()
{
writer.WriteFullEndElement();
}
#endregion
}
}