첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

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
    }
}

 

728x90

 

▶ 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
    }
}

 

300x250

 

▶ 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>
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요