첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형

TestProject.zip
다운로드

▶ SphereModelVisual3D.cs

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace TestProject
{
    /// <summary>
    /// 구체 모델 비주얼 3D
    /// </summary>
    public class SphereModelVisual3D : ModelVisual3D
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 재료 속성
        /// </summary>
        public static readonly DependencyProperty MaterialProperty = GeometryModel3D.MaterialProperty.AddOwner
        (
            typeof(SphereModelVisual3D),
            new PropertyMetadata(MaterialPropertyChangedCallback)
        );

        /// <summary>
        /// 후면 재료 속성
        /// </summary>
        public static readonly DependencyProperty BackMaterialProperty = GeometryModel3D.BackMaterialProperty.AddOwner
        (
            typeof(SphereModelVisual3D),
            new PropertyMetadata(MaterialPropertyChangedCallback)
        );

        /// <summary>
        /// 중심점 속성
        /// </summary>
        public static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register
        (
            "CenterPoint",
            typeof(Point3D),
            typeof(SphereModelVisual3D),
            new PropertyMetadata
            (
                new Point3D(),
                PropertyChangedCallback
            )
        );

        /// <summary>
        /// 반경 속성
        /// </summary>
        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register
        (
            "Radius",
            typeof(double),
            typeof(SphereModelVisual3D),
            new PropertyMetadata
            (
                1.0,
                PropertyChangedCallback
            )
        );

        /// <summary>
        /// 슬라이스 수 속성
        /// </summary>
        public static readonly DependencyProperty SliceCountProperty = DependencyProperty.Register
        (
            "SliceCount",
            typeof(int),
            typeof(SphereModelVisual3D),
            new PropertyMetadata
            (
                32,
                PropertyChangedCallback
            )
        );

        /// <summary>
        /// 스택 수 속성
        /// </summary>
        public static readonly DependencyProperty StackCountProperty = DependencyProperty.Register
        (
            "StackCount",
            typeof(int),
            typeof(SphereModelVisual3D),
            new PropertyMetadata
            (
                16,
                PropertyChangedCallback
            )
        );

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 도형 모델 3D
        /// </summary>
        private GeometryModel3D geometryModel3D;

        /// <summary>
        /// 메쉬 도형 3D
        /// </summary>
        private MeshGeometry3D meshGeometry3D;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 재료 - Material

        /// <summary>
        /// 재료
        /// </summary>
        public Material Material
        {
            set
            {
                SetValue(MaterialProperty, value);
            }
            get
            {
                return (Material)GetValue(MaterialProperty);
            }
        }

        #endregion
        #region 후면 재료 - BackMaterial

        /// <summary>
        /// 후면 재료
        /// </summary>
        public Material BackMaterial
        {
            set
            {
                SetValue(BackMaterialProperty, value);
            }
            get
            {
                return (Material)GetValue(BackMaterialProperty);
            }
        }

        #endregion

        #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 생성자 - SphereModelVisual3D()

        /// <summary>
        /// 생성자
        /// </summary>
        public SphereModelVisual3D()
        {
            this.geometryModel3D = new GeometryModel3D();

            this.meshGeometry3D = new MeshGeometry3D();

            this.geometryModel3D.Geometry = this.meshGeometry3D;

            Content = this.geometryModel3D;

            PropertyChanged(new DependencyPropertyChangedEventArgs());
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 재료 속성 변경시 콜백 처리하기 - MaterialPropertyChangedCallback(d, e)

        /// <summary>
        /// 재료 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void MaterialPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as SphereModelVisual3D).MaterialPropertyChanged(e);
        }

        #endregion
        #region 속성 변경시 콜백 처리하기 - PropertyChangedCallback(d, e)

        /// <summary>
        /// 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">의존 객체</param>
        /// <param name="e">이벤트 인자</param>
        private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as SphereModelVisual3D).PropertyChanged(e);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 재료 속성 변경시 처리하기 - MaterialPropertyChanged(e)

        /// <summary>
        /// 재료 속성 변경시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        private void MaterialPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            if(e.Property == MaterialProperty)
            {
                this.geometryModel3D.Material = e.NewValue as Material;
            }
            else if(e.Property == BackMaterialProperty)
            {
                this.geometryModel3D.BackMaterial = e.NewValue as Material;
            }
        }

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

        /// <summary>
        /// 속성 변경시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        private void PropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            Point3DCollection  vertexCollection  = this.meshGeometry3D.Positions;
            Vector3DCollection normalCollection  = this.meshGeometry3D.Normals;
            Int32Collection    indexCollection   = this.meshGeometry3D.TriangleIndices;
            PointCollection    textureCollection = this.meshGeometry3D.TextureCoordinates;

            this.meshGeometry3D.Positions          = null;
            this.meshGeometry3D.Normals            = null;
            this.meshGeometry3D.TriangleIndices    = null;
            this.meshGeometry3D.TextureCoordinates = null;

            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++)
            {
                int top    = (stack + 0) * (SliceCount + 1);
                int bottom = (stack + 1) * (SliceCount + 1);

                for(int slice = 0; slice < SliceCount; slice++)
                {
                    if(stack != 0)
                    {
                        indexCollection.Add(top    + slice    );
                        indexCollection.Add(bottom + slice    );
                        indexCollection.Add(top    + slice + 1);
                    }

                    if(stack != StackCount - 1)
                    {
                        indexCollection.Add(top    + slice + 1);
                        indexCollection.Add(bottom + slice    );
                        indexCollection.Add(bottom + slice + 1);
                    }
                }
            }

            this.meshGeometry3D.TextureCoordinates = textureCollection;
            this.meshGeometry3D.TriangleIndices    = indexCollection;
            this.meshGeometry3D.Normals            = normalCollection;
            this.meshGeometry3D.Positions          = vertexCollection;
        }

        #endregion
    }
}

 

728x90

 

▶ 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="ModelVisual3D 클래스 상속하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Viewport3D>
        <local:SphereModelVisual3D
            SliceCount="72"
            StackCount="36">
            <local:SphereModelVisual3D.Material>
                <DiffuseMaterial Brush="RoyalBlue" />
            </local:SphereModelVisual3D.Material>
            <local:SphereModelVisual3D.Transform>
                <ScaleTransform3D x:Name="scaleTransform3D" />
            </local:SphereModelVisual3D.Transform>
        </local:SphereModelVisual3D>
        <ModelVisual3D>
            <ModelVisual3D.Content>
                <Model3DGroup>
                    <AmbientLight Color="#404040" />
                    <DirectionalLight
                        Color="#C0C0C0"
                        Direction="2 -3 -1" />
                </Model3DGroup>
            </ModelVisual3D.Content>
        </ModelVisual3D>
        <Viewport3D.Camera>
            <PerspectiveCamera
                Position="4 4 4"
                LookDirection="-1 -1 -1"
                UpDirection="0 1 0"
                FieldOfView="45" />
        </Viewport3D.Camera>
    </Viewport3D>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard TargetName="scaleTransform3D">
                    <DoubleAnimation
                        Storyboard.TargetProperty="ScaleX"
                        From="0.5"
                        To="2"
                        Duration="0:0:3"
                        AutoReverse="True"
                        RepeatBehavior="Forever" />
                    <DoubleAnimation
                        Storyboard.TargetProperty="ScaleY"
                        From="0.5"
                        To="2"
                        Duration="0:0:5"
                        AutoReverse="True"
                        RepeatBehavior="Forever" />
                    <DoubleAnimation
                        Storyboard.TargetProperty="ScaleZ"
                        From="0.5"
                        To="2"
                        Duration="0:0:7"
                        AutoReverse="True"
                        RepeatBehavior="Forever" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
</Window>
728x90
반응형
그리드형(광고전용)
Posted by 사용자 icodebroker
TAG , , ,

댓글을 달아 주세요