■ MeshGeometry3D 클래스 : 수레바퀴 만들기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


MeshGeneratorBase.cs

 

 

using System.Windows;

using System.Windows.Markup;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Media.Media3D;

 

namespace TestProject

{

    /// <summary>

    /// 메쉬 제너레이터 베이스

    /// </summary>

    [RuntimeNameProperty("Name")]

    public abstract class MeshGeneratorBase : Animatable

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 도형 키

        /// </summary>

        private static DependencyPropertyKey GeometryKey = DependencyProperty.RegisterReadOnly

        (

            "Geometry",

            typeof(MeshGeometry3D),

            typeof(MeshGeneratorBase),

            new PropertyMetadata(new MeshGeometry3D())

        );

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region Field

 

        /// <summary>

        /// 명칭 속성

        /// </summary>

        public static readonly DependencyProperty NameProperty = DependencyProperty.Register

        (

            "Name",

            typeof(string),

            typeof(MeshGeneratorBase)

        );

 

        /// <summary>

        /// 도형 속성

        /// </summary>

        public static readonly DependencyProperty GeometryProperty = GeometryKey.DependencyProperty;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 명칭 - Name

 

        /// <summary>

        /// 명칭

        /// </summary>

        public string Name

        {

            set

            {

                SetValue(NameProperty, value);

            }

            get

            {

                return (string)GetValue(NameProperty);

            }

        }

 

        #endregion

        #region 도형 - Geometry

 

        /// <summary>

        /// 도형

        /// </summary>

        public MeshGeometry3D Geometry

        {

            get

            {

                return (MeshGeometry3D)GetValue(GeometryProperty);

            }

            protected set

            {

                SetValue(GeometryKey, value);

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MeshGeneratorBase()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MeshGeneratorBase()

        {

            Geometry = new MeshGeometry3D();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 속성 변경시 처리하기 - PropertyChanged(d, e)

 

        /// <summary>

        /// 속성 변경시 처리하기

        /// </summary>

        /// <param name="d">의존 객체</param>

        /// <param name="e">이벤트 인자</param>

        protected static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            (d as MeshGeneratorBase).PropertyChanged(e);

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

        //////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 삼각형 구성하기 - Triangulate(e, vertexCollection, normalCollection, indexCollection, textureCollection)

 

        /// <summary>

        /// 삼각형 구성하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        /// <param name="vertexCollection">꼭지점 컬렉션</param>

        /// <param name="normalCollection">법선 컬렉션</param>

        /// <param name="indexCollection">인덱스 컬렉션</param>

        /// <param name="textureCollection">텍스쳐 컬렉션</param>

        protected abstract void Triangulate(DependencyPropertyChangedEventArgs e, Point3DCollection vertexCollection,

            Vector3DCollection normalCollection, Int32Collection indexCollection, PointCollection textureCollection);

 

        #endregion

        #region 속성 변경시 처리하기 - PropertyChanged(e)

 

        /// <summary>

        /// 속성 변경시 처리하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        protected virtual void PropertyChanged(DependencyPropertyChangedEventArgs e)

        {

            MeshGeometry3D mesh = Geometry;

 

            Point3DCollection  vertexCollection  = mesh.Positions;

            Vector3DCollection normalCollection  = mesh.Normals;

            Int32Collection    indexCollection   = mesh.TriangleIndices;

            PointCollection    textureCollection = mesh.TextureCoordinates;

 

            mesh.Positions          = null;

            mesh.Normals            = null;

            mesh.TriangleIndices    = null;

            mesh.TextureCoordinates = null;

 

            Triangulate(e, vertexCollection, normalCollection, indexCollection, textureCollection);

 

            mesh.TextureCoordinates = textureCollection;

            mesh.TriangleIndices    = indexCollection;

            mesh.Normals            = normalCollection;

            mesh.Positions          = vertexCollection;

        }

 

        #endregion

    }

}

 

 

CylindricalMeshBase.cs

 

 

using System.Windows;

 

namespace TestProject

{

    /// <summary>

    /// 실린더 메쉬 베이스

    /// </summary>

    public abstract class CylindricalMeshBase : MeshGeneratorBase

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region Field

 

        /// <summary>

        /// 길이 속성

        /// </summary>

        public static readonly DependencyProperty LengthProperty = DependencyProperty.Register

        (

            "Length",

            typeof(double),

            typeof(CylindricalMeshBase),

            new PropertyMetadata(1.0, PropertyChanged)

        );

 

        /// <summary>

        /// 반경

        /// </summary>

        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register

        (

            "Radius",

            typeof(double),

            typeof(CylindricalMeshBase),

            new PropertyMetadata(1.0, PropertyChanged)

        );

 

        /// <summary>

        /// 슬라이스 수 속성

        /// </summary>

        public static readonly DependencyProperty SliceCountProperty = DependencyProperty.Register

        (

            "SliceCount",

            typeof(int),

            typeof(CylindricalMeshBase),

            new PropertyMetadata(36, PropertyChanged),

            ValidateSliceCount

        );

 

        /// <summary>

        /// 스택 수 속성

        /// </summary>

        public static readonly DependencyProperty StackCountProperty = DependencyProperty.Register

        (

            "StackCount",

            typeof(int),

            typeof(CylindricalMeshBase),

            new PropertyMetadata(1, PropertyChanged),

            ValidateStackCount

        );

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 길이 - Length

 

        /// <summary>

        /// 길이

        /// </summary>

        public double Length

        {

            set

            {

                SetValue(LengthProperty, value);

            }

            get

            {

                return (double)GetValue(LengthProperty);

            }

        }

 

        #endregion

        #region 반경 - Radius

 

        /// <summary>

        /// 반경

        /// </summary>

        public double Radius

        {

            set

            {

                SetValue(RadiusProperty, value);

            }

            get

            {

                return (double)GetValue(RadiusProperty);

            }

        }

 

        #endregion

        #region 슬라이스 수 - SliceCount

 

        /// <summary>

        /// 슬라이스 수

        /// </summary>

        public int SliceCount

        {

            set

            {

                SetValue(SliceCountProperty, value);

            }

            get

            {

                return (int)GetValue(SliceCountProperty);

            }

        }

 

        #endregion

        #region 스택 수 - StackCount

 

        /// <summary>

        /// 스택 수

        /// </summary>

        public int StackCount

        {

            set

            {

                SetValue(StackCountProperty, value);

            }

            get

            {

                return (int)GetValue(StackCountProperty);

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 슬라이스 수 무결성 체크하기 - ValidateSliceCount(sourceObject)

 

        /// <summary>

        /// 슬라이스 수 무결성 체크하기

        /// </summary>

        /// <param name="sourceObject">소스 객체</param>

        /// <returns>처리 결과</returns>

        private static bool ValidateSliceCount(object sourceObject)

        {

            return (int)sourceObject > 2;

        }

 

        #endregion

        #region 스택 수 무결성 체크하기 - ValidateStackCount(sourceObject)

 

        /// <summary>

        /// 스택 수 무결성 체크하기

        /// </summary>

        /// <param name="sourceObject">소스 객체</param>

        /// <returns>처리 결과</returns>

        private static bool ValidateStackCount(object sourceObject)

        {

            return (int)sourceObject > 0;

        }

 

        #endregion

    }

}

 

 

SphereMesh.cs

 

 

using System;

using System.Windows;

using System.Windows.Media;

using System.Windows.Media.Media3D;

 

namespace TestProject

{

    /// <summary>

    /// 구체 메쉬

    /// </summary>

    public class SphereMesh : MeshGeneratorBase

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region Field

 

        /// <summary>

        /// 중심점 속성

        /// </summary>

        public static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register

        (

            "CenterPoint",

            typeof(Point3D),

            typeof(SphereMesh),

            new PropertyMetadata(new Point3D(), PropertyChanged)

        );

 

        /// <summary>

        /// 반경 속성

        /// </summary>

        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register

        (

            "Radius",

            typeof(double),

            typeof(SphereMesh),

            new PropertyMetadata(1.0, PropertyChanged)

        );

 

        /// <summary>

        /// 슬라이스 수 속성

        /// </summary>

        public static readonly DependencyProperty SliceCountProperty = DependencyProperty.Register

        (

            "SliceCount",

            typeof(int),

            typeof(SphereMesh),

            new PropertyMetadata(36, PropertyChanged),

            ValidateSliceCount

        );

 

        /// <summary>

        /// 스택 수 속성

        /// </summary>

        public static readonly DependencyProperty StackCountProperty = DependencyProperty.Register

        (

            "StackCount",

            typeof(int),

            typeof(SphereMesh),

            new PropertyMetadata(18, PropertyChanged),

            ValidateStackCount

        );

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 중심점 - CenterPoint

 

        /// <summary>

        /// 중심점

        /// </summary>

        public Point3D CenterPoint

        {

            set

            {

                SetValue(CenterPointProperty, value);

            }

            get

            {

                return (Point3D)GetValue(CenterPointProperty);

            }

        }

 

        #endregion

        #region 반경 - Radius

 

        /// <summary>

        /// 반경

        /// </summary>

        public double Radius

        {

            set

            {

                SetValue(RadiusProperty, value);

            }

            get

            {

                return (double)GetValue(RadiusProperty);

            }

        }

 

        #endregion

        #region 슬라이스 수 - SliceCount

 

        /// <summary>

        /// 슬라이스 수

        /// </summary>

        public int SliceCount

        {

            set

            {

                SetValue(SliceCountProperty, value);

            }

            get

            {

                return (int)GetValue(SliceCountProperty);

            }

        }

 

        #endregion

        #region 스택 수 - StackCount

 

        /// <summary>

        /// 스택 수

        /// </summary>

        public int StackCount

        {

            set

            {

                SetValue(StackCountProperty, value);

            }

            get

            {

                return (int)GetValue(StackCountProperty);

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - SphereMesh()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public SphereMesh()

        {

            PropertyChanged(new DependencyPropertyChangedEventArgs());

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 슬라이스 수 무결성 체크하기 - ValidateSliceCount(sourceObject)

 

        /// <summary>

        /// 슬라이스 수 무결성 체크하기

        /// </summary>

        /// <param name="sourceObject">소스 객체</param>

        /// <returns>처리 결과</returns>

        private static bool ValidateSliceCount(object sourceObject)

        {

            return (int)sourceObject > 2;

        }

 

        #endregion

        #region 스택 수 무결성 체크하기 - ValidateStackCount(sourceObject)

 

        /// <summary>

        /// 스택 수 무결성 체크하기

        /// </summary>

        /// <param name="sourceObject">소스 객체</param>

        /// <returns>처리 결과</returns>

        private static bool ValidateStackCount(object sourceObject)

        {

            return (int)sourceObject > 1;

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

        //////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 삼각형 구성하기 - Triangulate(e, vertexCollection, normalCollection, indexCollection, textureCollection)

 

        /// <summary>

        /// 삼각형 구성하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        /// <param name="vertexCollection">꼭지점 컬렉션</param>

        /// <param name="normalCollection">법선 컬렉션</param>

        /// <param name="indexCollection">인덱스 컬렉션</param>

        /// <param name="textureCollection">텍스처 컬렉션</param>

        protected override void Triangulate(DependencyPropertyChangedEventArgs e, Point3DCollection vertexCollection,

            Vector3DCollection normalCollection, Int32Collection indexCollection, PointCollection textureCollection)

        {

            vertexCollection.Clear();

            normalCollection.Clear();

            indexCollection.Clear();

            textureCollection.Clear();

 

            for(int stack = 0; stack <= StackCount; stack++)

            {

                double phi   = Math.PI / 2 - stack * Math.PI / StackCount;

                double y     = Radius * Math.Sin(phi);

                double scale = -Radius * Math.Cos(phi);

 

                for(int slice = 0; slice <= SliceCount; slice++)

                {

                    double theta = slice * 2 * Math.PI / SliceCount;

                    double x     = scale * Math.Sin(theta);

                    double z     = scale * Math.Cos(theta);

 

                    Vector3D normal = new Vector3D(x, y, z);

 

                    normalCollection.Add(normal);

 

                    vertexCollection.Add(normal + CenterPoint);

 

                    textureCollection.Add(new Point((double)slice / SliceCount, (double)stack / StackCount));

                }

            }

 

            for(int stack = 0; stack < StackCount; stack++)

            {

                for(int slice = 0; slice < SliceCount; slice++)

                {

                    if(stack != 0)

                    {

                        indexCollection.Add((stack + 0) * (SliceCount + 1) + slice    );

                        indexCollection.Add((stack + 1) * (SliceCount + 1) + slice    );

                        indexCollection.Add((stack + 0) * (SliceCount + 1) + slice + 1);

                    }

 

                    if(stack != StackCount - 1)

                    {

                        indexCollection.Add((stack + 0) * (SliceCount + 1) + slice + 1);

                        indexCollection.Add((stack + 1) * (SliceCount + 1) + slice    );

                        indexCollection.Add((stack + 1) * (SliceCount + 1) + slice + 1);

                    }

                }

            }

        }

 

        #endregion

        #region 인스턴스 생성하기 (코어) - CreateInstanceCore()

 

        /// <summary>

        /// 인스턴스 생성하기 (코어)

        /// </summary>

        /// <returns>인스턴스</returns>

        protected override Freezable CreateInstanceCore()

        {

            return new SphereMesh();

        }

 

        #endregion

    }

}

 

 

HollowCylinderMesh.cs

 

 

using System;

using System.Windows;

using System.Windows.Media;

using System.Windows.Media.Media3D;

 

namespace TestProject

{

    /// <summary>

    /// 빈 실린더 메쉬

    /// </summary>

    public class HollowCylinderMesh : CylindricalMeshBase

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - HollowCylinderMesh()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public HollowCylinderMesh()

        {

            PropertyChanged(new DependencyPropertyChangedEventArgs());

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 삼각형 구성하기 - Triangulate(e, vertexCollection, normalCollection, indexCollection, textureCollection)

 

        /// <summary>

        /// 삼각형 구성하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        /// <param name="vertexCollection">꼭지점 컬렉션</param>

        /// <param name="normalCollection">법선 컬렉션</param>

        /// <param name="indexCollection">인덱스 컬렉션</param>

        /// <param name="textureCollection">텍스처 컬렉션</param>

        protected override void Triangulate(DependencyPropertyChangedEventArgs e, Point3DCollection vertexCollection,

            Vector3DCollection normalCollection, Int32Collection indexCollection, PointCollection textureCollection)

        {

            vertexCollection.Clear();

            normalCollection.Clear();

            indexCollection.Clear();

            textureCollection.Clear();

 

            for(int stack = 0; stack <= StackCount; stack++)

            {

                double y = Length - stack * Length / StackCount;

 

                for(int slice = 0; slice <= SliceCount; slice++)

                {

                    double theta = slice * 2 * Math.PI / SliceCount;

                    double x     = -Radius * Math.Sin(theta);

                    double z     = -Radius * Math.Cos(theta);

 

                    normalCollection.Add(new Vector3D(x, 0, z));

                    vertexCollection.Add(new Point3D(x, y, z));

                    textureCollection.Add(new Point((double)slice / SliceCount, (double)stack / StackCount));

                }

            }

 

            for(int stack = 0; stack < StackCount; stack++)

            {

                for(int slice = 0; slice < SliceCount; slice++)

                {

                    indexCollection.Add((stack + 0) * (SliceCount + 1) + slice    );

                    indexCollection.Add((stack + 1) * (SliceCount + 1) + slice    );

                    indexCollection.Add((stack + 0) * (SliceCount + 1) + slice + 1);

 

                    indexCollection.Add((stack + 0) * (SliceCount + 1) + slice + 1);

                    indexCollection.Add((stack + 1) * (SliceCount + 1) + slice    );

                    indexCollection.Add((stack + 1) * (SliceCount + 1) + slice + 1);

                }

            }

        }

 

        #endregion

        #region 인스턴스 생성하기 (코어) - CreateInstanceCore()

 

        /// <summary>

        /// 인스턴스 생성하기 (코어)

        /// </summary>

        /// <returns>인스턴스</returns>

        protected override Freezable CreateInstanceCore()

        {

            return new HollowCylinderMesh();

        }

 

        #endregion

    }

}

 

 

TorusMesh.cs

 

 

using System;

using System.Windows;

using System.Windows.Media;

using System.Windows.Media.Media3D;

 

namespace TestProject

{

    /// <summary>

    /// 원환체 메쉬

    /// </summary>

    public class TorusMesh : MeshGeneratorBase

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region Field

 

        /// <summary>

        /// 반경 속성

        /// </summary>

        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register

        (

            "Radius",

            typeof(double),

            typeof(TorusMesh),

            new PropertyMetadata(1.0, PropertyChanged)

        );

 

        /// <summary>

        /// 튜브 반경 속성

        /// </summary>

        public static readonly DependencyProperty TubeRadiusProperty = DependencyProperty.Register

        (

            "TubeRadius",

            typeof(double),

            typeof(TorusMesh),

            new PropertyMetadata(0.25, PropertyChanged)

        );

 

        /// <summary>

        /// 슬라이스 수 속성

        /// </summary>

        public static readonly DependencyProperty SliceCountProperty = DependencyProperty.Register

        (

            "SliceCount",

            typeof(int),

            typeof(TorusMesh),

            new PropertyMetadata(18, PropertyChanged),

            ValidateSliceCount

        );

 

        /// <summary>

        /// 스택 수 속성

        /// </summary>

        public static readonly DependencyProperty StackCountProperty = DependencyProperty.Register

        (

            "StackCount",

            typeof(int),

            typeof(TorusMesh),

            new PropertyMetadata(36, PropertyChanged),

            ValidateStackCount

        );

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 반경 - Radius

 

        /// <summary>

        /// 반경

        /// </summary>

        public double Radius

        {

            set

            {

                SetValue(RadiusProperty, value);

            }

            get

            {

                return (double)GetValue(RadiusProperty);

            }

        }

 

        #endregion

        #region 튜브 반경 - TubeRadius

 

        /// <summary>

        /// 튜브 반경

        /// </summary>

        public double TubeRadius

        {

            set

            {

                SetValue(TubeRadiusProperty, value);

            }

            get

            {

                return (double)GetValue(TubeRadiusProperty);

            }

        }

 

        #endregion

        #region 슬라이스 수 - SliceCount

 

        /// <summary>

        /// 슬라이스 수

        /// </summary>

        public int SliceCount

        {

            set

            {

                SetValue(SliceCountProperty, value);

            }

            get

            {

                return (int)GetValue(SliceCountProperty);

            }

        }

 

        #endregion

        #region 스택 수 - StackCount

 

        /// <summary>

        /// 스택 수

        /// </summary>

        public int StackCount

        {

            set

            {

                SetValue(StackCountProperty, value);

            }

            get

            {

                return (int)GetValue(StackCountProperty);

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - TorusMesh()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public TorusMesh()

        {

            PropertyChanged(new DependencyPropertyChangedEventArgs());

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 슬라이스 수 무결성 체크하기 - ValidateSliceCount(sourceObject)

 

        /// <summary>

        /// 슬라이스 수 무결성 체크하기

        /// </summary>

        /// <param name="sourceObject">소스 객체</param>

        /// <returns>처리 결과</returns>

        private static bool ValidateSliceCount(object sourceObject)

        {

            return (int)sourceObject > 2;

        }

 

        #endregion

        #region 스택 수 무결성 체크하기 - ValidateStackCount(sourceObject)

 

        /// <summary>

        /// 스택 수 무결성 체크하기

        /// </summary>

        /// <param name="sourceObject">소스 객체</param>

        /// <returns>처리 결과</returns>

        private static bool ValidateStackCount(object sourceObject)

        {

            return (int)sourceObject > 2;

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Instance

        //////////////////////////////////////////////////////////////////////////////// Protected

 

        #region 삼각형 구성하기 - Triangulate(e, vertexCollection, normalCollection, indexCollection, textureCollection)

 

        /// <summary>

        /// 삼각형 구성하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        /// <param name="vertexCollection">꼭지점 컬렉션</param>

        /// <param name="normalCollection">법선 컬렉션</param>

        /// <param name="indexCollection">인덱스 컬렉션</param>

        /// <param name="textureCollection">텍스처 컬렉션</param>

        protected override void Triangulate(DependencyPropertyChangedEventArgs e, Point3DCollection vertexCollection,

            Vector3DCollection normalCollection, Int32Collection indexCollection, PointCollection textureCollection)

        {

            vertexCollection.Clear();

            normalCollection.Clear();

            indexCollection.Clear();

            textureCollection.Clear();

 

            for(int stack = 0; stack <= StackCount; stack++)

            {

                double  phi         = stack * 2 * Math.PI / StackCount;

                double  xCenter     = Radius * Math.Sin(phi);

                double  yCenter     = Radius * Math.Cos(phi);

                Point3D centerPoint = new Point3D(xCenter, yCenter, 0);

 

                for(int slice = 0; slice <= SliceCount; slice++)

                {

                    double  theta = slice * 2 * Math.PI / SliceCount + Math.PI;

                    double  x     = (Radius + TubeRadius * Math.Cos(theta)) * Math.Sin(phi);

                    double  y     = (Radius + TubeRadius * Math.Cos(theta)) * Math.Cos(phi);

                    double  z     = -TubeRadius * Math.Sin(theta);

                    Point3D point = new Point3D(x, y, z);

 

                    vertexCollection.Add(point);

 

                    normalCollection.Add(point - centerPoint);

 

                    textureCollection.Add(new Point((double)slice / SliceCount, (double)stack / StackCount));

                }

            }

 

            for(int stack = 0; stack < StackCount; stack++)

            {

                for(int slice = 0; slice < SliceCount; slice++)

                {

                    indexCollection.Add((stack + 0) * (SliceCount + 1) + slice    );

                    indexCollection.Add((stack + 1) * (SliceCount + 1) + slice    );

                    indexCollection.Add((stack + 0) * (SliceCount + 1) + slice + 1);

 

                    indexCollection.Add((stack + 0) * (SliceCount + 1) + slice + 1);

                    indexCollection.Add((stack + 1) * (SliceCount + 1) + slice    );

                    indexCollection.Add((stack + 1) * (SliceCount + 1) + slice + 1);

                }

            }

        }

 

        #endregion

        #region 인스턴스 생성하기 (코어) - CreateInstanceCore()

 

        /// <summary>

        /// 인스턴스 생성하기 (코어)

        /// </summary>

        /// <returns>인스턴스</returns>

        protected override Freezable CreateInstanceCore()

        {

            return new TorusMesh();

        }

 

        #endregion

    }

}

 

 

MainWindow.xaml

 

 

<Window x:Class="TestProject.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:TestProject"

    Width="800"

    Height="600"

    Title="MeshGeometry3D 클래스 : 수레바퀴 만들기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Window.Resources>

        <local:SphereMesh x:Key="hubSphereMeshKey"

            Radius="0.2" />

        <local:HollowCylinderMesh x:Key="spokeHollowCylinderMeshKey"

            Radius="0.03"

            Length="1" />

        <local:TorusMesh x:Key="tireTorusMeshKey"

            Radius="1"

            TubeRadius="0.2"

            SliceCount="144"

            StackCount="96" />

        <DiffuseMaterial x:Key="steelDiffuseMaterialKey"

            Brush="SteelBlue" />

        <DiffuseMaterial x:Key="tireDiffuseMaterialKey"

            Brush="DarkGray" />

        <Model3DGroup x:Key="spokeModel3DGroupKey">

            <GeometryModel3D

                Geometry="{Binding Source={StaticResource spokeHollowCylinderMeshKey}, Path=Geometry}"

                Material="{StaticResource steelDiffuseMaterialKey}" />

            <GeometryModel3D

                Geometry="{Binding Source={StaticResource spokeHollowCylinderMeshKey}, Path=Geometry}"

                Material="{StaticResource steelDiffuseMaterialKey}">

                <GeometryModel3D.Transform>

                    <RotateTransform3D>

                        <RotateTransform3D.Rotation>

                            <AxisAngleRotation3D

                                Axis="0 0 -1"

                                Angle="30" />

                        </RotateTransform3D.Rotation>

                    </RotateTransform3D>

                </GeometryModel3D.Transform>

            </GeometryModel3D>

            <GeometryModel3D

                Geometry="{Binding Source={StaticResource spokeHollowCylinderMeshKey}, Path=Geometry}"

                Material="{StaticResource steelDiffuseMaterialKey}">

                <GeometryModel3D.Transform>

                    <RotateTransform3D>

                        <RotateTransform3D.Rotation>

                            <AxisAngleRotation3D

                                Axis="0 0 -1"

                                Angle="60" />

                        </RotateTransform3D.Rotation>

                    </RotateTransform3D>

                </GeometryModel3D.Transform>

            </GeometryModel3D>

        </Model3DGroup>

        <Model3DGroup x:Key="wheelModel3DGroupKey">

            <GeometryModel3D

                Geometry="{Binding Source={StaticResource hubSphereMeshKey}, Path=Geometry}"

                Material="{StaticResource steelDiffuseMaterialKey}" />

            <StaticResource ResourceKey="spokeModel3DGroupKey" />

            <Model3DGroup>

                <StaticResource ResourceKey="spokeModel3DGroupKey" />

                <Model3DGroup.Transform>

                    <RotateTransform3D>

                        <RotateTransform3D.Rotation>

                            <AxisAngleRotation3D

                                Axis="0 0 -1"

                                Angle="90" />

                        </RotateTransform3D.Rotation>

                    </RotateTransform3D>

                </Model3DGroup.Transform>

            </Model3DGroup>

            <Model3DGroup>

                <StaticResource ResourceKey="spokeModel3DGroupKey" />

                <Model3DGroup.Transform>

                    <RotateTransform3D>

                        <RotateTransform3D.Rotation>

                            <AxisAngleRotation3D

                                Axis="0 0 -1"

                                Angle="180" />

                        </RotateTransform3D.Rotation>

                    </RotateTransform3D>

                </Model3DGroup.Transform>

            </Model3DGroup>

            <Model3DGroup>

                <StaticResource ResourceKey="spokeModel3DGroupKey" />

                <Model3DGroup.Transform>

                    <RotateTransform3D>

                        <RotateTransform3D.Rotation>

                            <AxisAngleRotation3D

                                Axis="0 0 -1"

                                Angle="270" />

                        </RotateTransform3D.Rotation>

                    </RotateTransform3D>

                </Model3DGroup.Transform>

            </Model3DGroup>

            <GeometryModel3D

                Geometry="{Binding Source={StaticResource tireTorusMeshKey}, Path=Geometry}"

                Material="{StaticResource tireDiffuseMaterialKey}" />

        </Model3DGroup>

    </Window.Resources>

    <Viewport3D>

        <ModelVisual3D Content="{StaticResource wheelModel3DGroupKey}">

            <ModelVisual3D.Transform>

                <RotateTransform3D>

                    <RotateTransform3D.Rotation>

                        <AxisAngleRotation3D x:Name="axisAngleRotation3D"

                            Axis="0 0 -1" />

                    </RotateTransform3D.Rotation>

                </RotateTransform3D>

            </ModelVisual3D.Transform>

        </ModelVisual3D>

        <ModelVisual3D>

            <ModelVisual3D.Content>

                <Model3DGroup>

                    <AmbientLight Color="#404040" />

                    <DirectionalLight

                        Color="#C0C0C0"

                        Direction="2 -3 -1" />

                </Model3DGroup>

            </ModelVisual3D.Content>

        </ModelVisual3D>

        <Viewport3D.Camera>

            <PerspectiveCamera

                Position="-4 0 4"

                LookDirection="4 0 -4"

                UpDirection="0 1 0"

                FieldOfView="45" />

        </Viewport3D.Camera>

    </Viewport3D>

    <Window.Triggers>

        <EventTrigger RoutedEvent="Window.Loaded">

            <BeginStoryboard>

                <Storyboard>

                    <DoubleAnimation

                        Storyboard.TargetName="axisAngleRotation3D"

                        Storyboard.TargetProperty="Angle"

                        From="0"

                        To="360"

                        Duration="0:0:5"

                        RepeatBehavior="Forever" />

                </Storyboard>

            </BeginStoryboard>

        </EventTrigger>

    </Window.Triggers>

</Window>

 

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker

댓글을 달아 주세요