Click here to Skip to main content
15,896,207 members
Articles / Desktop Programming / WPF

WPF 3D - Kerkythea Exporter

Rate me:
Please Sign up or sign in to vote.
3.50/5 (3 votes)
10 Jul 2009Ms-PL1 min read 53.8K   3.8K   25  
Export the WPF 3D scene graph to raytracing/radiosity rendering software (Kerkythea)
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace OpenSource.Wpf3D
{
    public class Sphere3D : ModelUIElement3D
    {
        protected override void OnUpdateModel()
        {
            GeometryModel3D model = new GeometryModel3D();

            model.Geometry = Tessellate();
            if (Material == null)
                model.Material = CreateMaterial(System.Windows.Media.Brushes.Blue); 
            else
                model.Material = Material;

            model.BackMaterial = BackMaterial;
            
            Model = model;
        }

        private Material CreateMaterial(Brush brush)
        {
            MaterialGroup mg = new MaterialGroup();
            mg.Children.Add(new DiffuseMaterial(brush));
            mg.Children.Add(new SpecularMaterial(Brushes.White, 80));
            return mg;
        }
        
        public Brush Fill
        {
            set
            {
                Material = CreateMaterial(value);
            }
        }

        public Material Material
        {
            get { return (Material)GetValue(MaterialProperty); }
            set { SetValue(MaterialProperty, value); }
        }

        public static readonly DependencyProperty MaterialProperty =
            DependencyProperty.Register("Material", typeof(Material), typeof(Sphere3D), new UIPropertyMetadata(null));

        public Material BackMaterial
        {
            get { return (Material)GetValue(BackMaterialProperty); }
            set { SetValue(BackMaterialProperty, value); }
        }

        public static readonly DependencyProperty BackMaterialProperty =
            DependencyProperty.Register("BackMaterial", typeof(Material), typeof(Sphere3D), new UIPropertyMetadata(null));

        public Point3D Center
        {
            get { return (Point3D)GetValue(CenterProperty); }
            set { SetValue(CenterProperty, value); }
        }

        public static readonly DependencyProperty CenterProperty =
            DependencyProperty.Register("Center", typeof(Point3D), typeof(Sphere3D), new PropertyMetadata(new Point3D(0, 0, 0), CenterPropertyChanged));

        private static void CenterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Sphere3D s = (Sphere3D)d;
            s.InvalidateModel();
        }

        // The number of divisions to make in the theta direction on the sphere
        public static readonly DependencyProperty ThetaDivProperty =
            DependencyProperty.Register("ThetaDiv",
                                        typeof(int),
                                        typeof(Sphere3D),
                                        new PropertyMetadata(30, ThetaDivPropertyChanged));

        private static void ThetaDivPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Sphere3D s = (Sphere3D)d;
            s.InvalidateModel();
        }

        public int ThetaDiv
        {
            get
            {
                return (int)GetValue(ThetaDivProperty);
            }

            set
            {
                SetValue(ThetaDivProperty, value);
            }
        }

        // The number of divisions to make in the phi direction on the sphere
        public static readonly DependencyProperty PhiDivProperty =
            DependencyProperty.Register("PhiDiv",
                                        typeof(int),
                                        typeof(Sphere3D),
                                        new PropertyMetadata(30, PhiDivPropertyChanged));

        private static void PhiDivPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Sphere3D s = (Sphere3D)d;
            s.InvalidateModel();
        }

        public int PhiDiv
        {
            get
            {
                return (int)GetValue(PhiDivProperty);
            }

            set
            {
                SetValue(PhiDivProperty, value);
            }
        }

        // The radius of the sphere
        public static readonly DependencyProperty RadiusProperty =
            DependencyProperty.Register("Radius",
                                        typeof(double),
                                        typeof(Sphere3D),
                                        new PropertyMetadata(1.0, RadiusPropertyChanged));

        private static void RadiusPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Sphere3D s = (Sphere3D)d;
            s.InvalidateModel();
        }

        public double Radius
        {
            get
            {
                return (double)GetValue(RadiusProperty);
            }

            set
            {
                SetValue(RadiusProperty, value);
            }
        }


        // Tesselates the sphere and returns a MeshGeometry3D representing the 
        // tessellation based on the given parameters
        internal MeshGeometry3D Tessellate()
        {
            int tDiv = ThetaDiv;
            int pDiv = PhiDiv;
            double radius = Radius;

            double dt = 2 * Math.PI / tDiv;
            double dp = Math.PI / pDiv;

            MeshGeometry3D mesh = new MeshGeometry3D();

            for (int pi = 0; pi <= pDiv; pi++)
            {
                double phi = pi * dp;

                for (int ti = 0; ti <= tDiv; ti++)
                {
                    double theta = ti * dt;

                    // Spherical coordinates
                    // http://mathworld.wolfram.com/SphericalCoordinates.html
                    double x = Math.Cos(theta) * Math.Sin(phi);
                    double y = Math.Sin(theta) * Math.Sin(phi);
                    double z = Math.Cos(phi);
                    Point3D p = new Point3D(Center.X + radius * x, Center.Y + radius * y, Center.Z + radius * z);
                    Vector3D n = new Vector3D(x, y, z); 
                    System.Windows.Point uv = new System.Windows.Point(theta / (2 * Math.PI), phi / (Math.PI));

                    mesh.Positions.Add(p);
                    mesh.Normals.Add(n);
                    mesh.TextureCoordinates.Add(uv);
                }
            }

            for (int pi = 0; pi < pDiv; pi++)
            {
                for (int ti = 0; ti < tDiv; ti++)
                {
                    int x0 = ti;
                    int x1 = (ti + 1);
                    int y0 = pi * (tDiv + 1);
                    int y1 = (pi + 1) * (tDiv + 1);

                    mesh.TriangleIndices.Add(x0 + y0);
                    mesh.TriangleIndices.Add(x0 + y1);
                    mesh.TriangleIndices.Add(x1 + y0);

                    mesh.TriangleIndices.Add(x1 + y0);
                    mesh.TriangleIndices.Add(x0 + y1);
                    mesh.TriangleIndices.Add(x1 + y1);
                }
            }

            mesh.Freeze();
            return mesh;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Norway Norway
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions