첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ ModelVisual3D 클래스 상속하기

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


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

    }

}

 

 

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>

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요