■ 원뿔(Cone) 그리기

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


TestProject.zip


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"

    Width="800"

    Height="600"

    Title="원뿔(Cone) 그리기"

    Loaded="Window_Loaded"

    KeyDown="Window_KeyDown">

    <Grid>

        <Viewport3D Name="viewport3D" />

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System;

using System.Windows;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Media3D;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

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

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

 

        #region Field

 

        /// <summary>

        /// 모델 그룹

        /// </summary>

        private Model3DGroup modeGroup = new Model3DGroup();

 

        /// <summary>

        /// 카메라

        /// </summary>

        private PerspectiveCamera camera;

 

        /// <summary>

        /// 카메라 파이

        /// </summary>

        private double cameraPhi = Math.PI / 6.0;

 

        /// <summary>

        /// 카메라 세타

        /// </summary>

        private double cameraTheta = Math.PI / 6.0;

 

        /// <summary>

        /// 카메라 R

        /// </summary>

        private double cameraR = 3.0;

 

        /// <summary>

        /// 카메라 델타 파이

        /// </summary>

        private const double CAMERA_DELTA_PHI = 0.1;

 

        /// <summary>

        /// 카메라 델타 세타

        /// </summary>

        private const double CAMERA_DELTA_THETA = 0.1;

 

        /// <summary>

        /// 카메라 델타 R

        /// </summary>

        private const double CAMERA_DELTA_R = 0.1;

 

        #endregion

        

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

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

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

        }

 

        #endregion

 

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

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

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)

 

        /// <summary>

        /// 윈도우 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

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

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            this.camera = new PerspectiveCamera();

 

            this.camera.FieldOfView = 60;

 

            this.viewport3D.Camera = this.camera;

 

            SetCameraPosition();

 

            DefineLight();

 

            DefineModel(this.modeGroup);

 

            ModelVisual3D modelVisual = new ModelVisual3D();

 

            modelVisual.Content = this.modeGroup;

 

            this.viewport3D.Children.Add(modelVisual);

        }

 

        #endregion

        #region 윈도우 키 DOWN 처리하기 - Window_KeyDown(sender, e)

 

        /// <summary>

        /// 윈도우 키 DOWN 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

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

        private void Window_KeyDown(object sender, KeyEventArgs e)

        {

            switch(e.Key)

            {

                case Key.Up :

 

                    this.cameraPhi += CAMERA_DELTA_PHI;

 

                    if(this.cameraPhi > Math.PI / 2.0)

                    {

                        this.cameraPhi = Math.PI / 2.0;

                    }

 

                    break;

 

                case Key.Down :

 

                    this.cameraPhi -= CAMERA_DELTA_PHI;

 

                    if(this.cameraPhi < -Math.PI / 2.0)

                    {

                        this.cameraPhi = -Math.PI / 2.0;

                    }

 

                    break;

 

                case Key.Left :

 

                    this.cameraTheta += CAMERA_DELTA_THETA;

 

                    break;

 

                case Key.Right :

 

                    this.cameraTheta -= CAMERA_DELTA_THETA;

 

                    break;

 

                case Key.Add     :

                case Key.OemPlus :

 

                    this.cameraR -= CAMERA_DELTA_R;

 

                    if(this.cameraR < CAMERA_DELTA_R)

                    {

                        this.cameraR = CAMERA_DELTA_R;

                    }

 

                    break;

 

                case Key.Subtract :

                case Key.OemMinus :

 

                    this.cameraR += CAMERA_DELTA_R;

 

                    break;

            }

 

            SetCameraPosition();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 카메라 위치 설정하기 - SetCameraPosition()

 

        /// <summary>

        /// 카메라 위치 설정하기

        /// </summary>

        private void SetCameraPosition()

        {

            double y   = this.cameraR * Math.Sin(this.cameraPhi);

            double hyp = this.cameraR * Math.Cos(this.cameraPhi);

            double x   = hyp * Math.Cos(this.cameraTheta);

            double z   = hyp * Math.Sin(this.cameraTheta);

 

            this.camera.Position = new Point3D(x, y, z);

 

            this.camera.LookDirection = new Vector3D(-x, -y, -z);

 

            this.camera.UpDirection = new Vector3D(0, 1, 0);

        }

        

        #endregion

        #region 조명 정의하기 - DefineLight()

 

        /// <summary>

        /// 조명 정의하기

        /// </summary>

        private void DefineLight()

        {

            AmbientLight     ambientLight     = new AmbientLight(Colors.Gray);

            DirectionalLight directionalLight = new DirectionalLight(Colors.Gray, new Vector3D(-1.0, -3.0, -2.0));

 

            this.modeGroup.Children.Add(ambientLight    );

            this.modeGroup.Children.Add(directionalLight);

        }

 

        #endregion

        #region 원뿔 추가하기 - AddCone(mesh, endPoint, axisVector, radius1, radius2, sideCount)

 

        /// <summary>

        /// 원뿔 추가하기

        /// </summary>

        /// <param name="mesh">메시</param>

        /// <param name="endPoint">종단 포인트</param>

        /// <param name="axisVector">축 벡터</param>

        /// <param name="radius1">반지름 1</param>

        /// <param name="radius2">반지름 2</param>

        /// <param name="sideCount">면 카운트</param>

        private void AddCone(MeshGeometry3D mesh, Point3D endPoint, Vector3D axisVector, double radius1, double radius2, int sideCount)

        {

            Vector3D topVector1;

 

            if((axisVector.Z < -0.01) || (axisVector.Z > 0.01))

            {

                topVector1 = new Vector3D(axisVector.Z, axisVector.Z, -axisVector.X - axisVector.Y);

            }

            else

            {

                topVector1 = new Vector3D(-axisVector.Y - axisVector.Z, axisVector.X, axisVector.X);

            }

 

            Vector3D topVector2 = Vector3D.CrossProduct(topVector1, axisVector);

 

            Vector3D bottomVector1 = topVector1;

            Vector3D bottomVector2 = topVector2;

 

            topVector1 *= (radius1 / topVector1.Length);

            topVector2 *= (radius1 / topVector2.Length);

 

            bottomVector1 *= (radius2 / bottomVector1.Length);

            bottomVector2 *= (radius2 / bottomVector2.Length);

 

            int point0 = mesh.Positions.Count;

 

            mesh.Positions.Add(endPoint);

 

            double theta      = 0;

            double deltaTheta = 2 * Math.PI / sideCount;

 

            for(int i = 0; i < sideCount; i++)

            {

                mesh.Positions.Add(endPoint + Math.Cos(theta) * topVector1 + Math.Sin(theta) * topVector2);

 

                theta += deltaTheta;

            }

 

            int point1 = mesh.Positions.Count - 1;

            int point2 = point0 + 1;

 

            for(int i = 0; i < sideCount; i++)

            {

                mesh.TriangleIndices.Add(point0);

                mesh.TriangleIndices.Add(point1);

                mesh.TriangleIndices.Add(point2);

 

                point1 = point2++;

            }

 

            point0 = mesh.Positions.Count;

 

            Point3D endPoint2 = endPoint + axisVector;

 

            mesh.Positions.Add(endPoint2);

 

            theta = 0;

 

            for(int i = 0; i < sideCount; i++)

            {

                mesh.Positions.Add(endPoint2 + Math.Cos(theta) * bottomVector1 + Math.Sin(theta) * bottomVector2);

 

                theta += deltaTheta;

            }

 

            theta = 0;

 

            point1 = mesh.Positions.Count - 1;

            point2 = point0 + 1;

 

            for(int i = 0; i < sideCount; i++)

            {

                mesh.TriangleIndices.Add(point0);

                mesh.TriangleIndices.Add(point2);

                mesh.TriangleIndices.Add(point1);

 

                point1 = point2++;

            }

 

            int firstSidePoint = mesh.Positions.Count;

 

            theta = 0;

 

            for(int i = 0; i < sideCount; i++)

            {

                Point3D p1 = endPoint + Math.Cos(theta) * topVector1 + Math.Sin(theta) * topVector2;

                

                mesh.Positions.Add(p1);

 

                Point3D p2 = endPoint + axisVector + Math.Cos(theta) * bottomVector1 + Math.Sin(theta) * bottomVector2;

 

                mesh.Positions.Add(p2);

 

                theta += deltaTheta;

            }

 

            point1 = mesh.Positions.Count - 2;

            point2 = point1 + 1;

 

            int point3 = firstSidePoint;

            int point4 = point3 + 1;

 

            for(int i = 0; i < sideCount; i++)

            {

                mesh.TriangleIndices.Add(point1);

                mesh.TriangleIndices.Add(point2);

                mesh.TriangleIndices.Add(point4);

 

                mesh.TriangleIndices.Add(point1);

                mesh.TriangleIndices.Add(point4);

                mesh.TriangleIndices.Add(point3);

 

                point1 = point3;

 

                point3 += 2;

 

                point2 = point4;

 

                point4 += 2;

            }

        }

 

        #endregion

        #region 모델 정의하기 - DefineModel(modelGroup)

 

        /// <summary>

        /// 모델 정의하기

        /// </summary>

        /// <param name="modelGroup">모델 그룹</param>

        private void DefineModel(Model3DGroup modelGroup)

        {

            // Y축 원뿔을 만든다.

            MeshGeometry3D mesh1 = new MeshGeometry3D();

 

            AddCone(mesh1, new Point3D(0, 1, 0), new Vector3D(0, -2, 0), 0.1, 0.25, 10);

 

            SolidColorBrush brush1    = Brushes.LightGreen;

            DiffuseMaterial material1 = new DiffuseMaterial(brush1);

            GeometryModel3D model1    = new GeometryModel3D(mesh1, material1);

 

            modelGroup.Children.Add(model1);

 

            // Z축 원뿔을 만든다.

            MeshGeometry3D mesh2 = new MeshGeometry3D();

 

            AddCone(mesh2, new Point3D(-1, 0, 0), new Vector3D(2, 0, 0), 0.5, 0.1, 20);

 

            SolidColorBrush brush2    = Brushes.Red;

            DiffuseMaterial material2 = new DiffuseMaterial(brush2);

            GeometryModel3D model2    = new GeometryModel3D(mesh2, material2);

 

            modelGroup.Children.Add(model2);

 

            // X축 원뿔을 만든다.

            MeshGeometry3D mesh3 = new MeshGeometry3D();

 

            AddCone(mesh3, new Point3D(0, 0, -1), new Vector3D(0, 0, 2), 0.5, 0.0, 20);

 

            SolidColorBrush brush3    = Brushes.LightBlue;

            DiffuseMaterial material3 = new DiffuseMaterial(brush3);

            GeometryModel3D model3    = new GeometryModel3D(mesh3, material3);

 

            modelGroup.Children.Add(model3);

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker

댓글을 달아 주세요