패왕넷

location tag guestbook

  • RSS
  • admin
  • post

'WPF'에 해당되는 글 2건

  1. 2006/12/26 XAML로 스피어-메시 생성
  2. 2006/11/25 WPF 관련 자료
 

XAML로 스피어-메시 생성

분류없음 2006/12/26 15:25
 
 
 
 

A Korean translation of 「 Generating a sphere-mesh in XAML」


제가 월간 마이크로소프트웨어 2007년 1월호에 기고한 글에 나오는 WPF 예제입니다.

사용자 삽입 이미지


























소개


몇
일전에 WPF에서 제공하는 3D 기능을 재미있게 다루는 방법에 대해 생각해 보았는데, 2D 그래픽과 애니메이션 자료 밖에 없어서 MSDN을 뒤져봤다. MSDN에서 3D 그래픽을 소개하는 내용을 찾아냈고, 코드프로젝트에서는 XAML로 3D를 구현하는데 도움이 될만한 3D in XAML이란 아티클을 찾아냈다. 이 아티클에서는 카메라 기초상식, 메시, 빛 등에 대한 설명은 하고 있지 않다.


MSDN
에서 "지금은 스피어와 큐빅 같은 미리 정의된 3-D 도형은 지원하지 않는다 "라는 내용을 읽었을 때 적잖이 실망했다. WPF에서 제공하는
MeshGeometry3D 클래스는 삼각형 목록과 같은 도형을 빌드하는데 그칠 뿐이어서, 첫 WPF 3D 미니프로젝트에서는 스피어를 보여주는 메시를 생성하는 알고리즘을 구현하기록 결심했다.


아쉽게도
필자는 3D 그래픽을 구현하는데 능숙하지 못하다. 그래서, 삼각형 메시에서 스피어를 생성하는 비교적 간단한 알고리즘을 구현하려고 하며, 이를 위해 오픈소스 3D 모델러 블렌더(Blender)에서 제공하는 UVSphere 메시를 사용하려고 한다.


사용자 삽입 이미지













(
소스: 위키: Grundkörper)


이
그림에서 보이는 대로, 스피어를 선분(segment)과 링(ring)으로 나누었다. 그 결과 위 부분과 아래 부분에는 (삼각형 두 개로 나눌 수 있는) 정사각형과 삼각형 모형이 보이게 된다. 블렌더의 Icosphere(더 자세한 내용은 위키iki: Ikosaeder를 참조)는 XAML 메시에 적합하긴 하지만, 필자는 UVSphere로 시작하려고 한다.


스피어는
단지 라운드 메시(round mesh)가 아니며, 원을 선분으로 나눌 때 생성되기도 한다. 그래서 3D 공간에서 원을 구현하는데 추상 기본 클래스(abstract base class)를 사용하려고 한다.

using System;

using System.Windows.Media;

using System.Windows.Media.Media3D;

namespace Sphere3D

{

  abstract class RoundMesh3D

  {

       protected int n = 10;

       protected int r = 20;

       protected Point3DCollection points;

       protected Int32Collection triangleIndices;

       public virtual int Radius

       {

           get { return r; }

           set { r = value; CalculateGeometry(); }

       }

       public virtual int Separators

       {

           get { return n; }

           set { n = value; CalculateGeometry(); }

       }

       public Point3DCollection Points

       {

           get { return points; }

       }

       public Int32Collection TriangleIndices

       {

           get { return triangleIndices; }

       }

       protected abstract void CalculateGeometry();

  }

}


r
은 그물 모양(mesh)의 반지름을 나타내고, n은 원을 몇 개의 선분으로 나눌 건지를 나타낸다(4*n+4는 원을 동일하게 나누는데 사용하는 점의 수).


첫
번째 테스트는 원반 구현으로, 아래에 코드가 있다. 삼각함수에 대한 내용일 뿐이라 그다지 어렵지는 않다.

using System;

using System.Windows.Media;

using System.Windows.Media.Media3D;

using System.Diagnostics;

namespace Sphere3D

{

  class DiscGeometry3D : RoundMesh3D

  {

       protected override void  CalculateGeometry()

       {

           int numberOfSeparators = 4 * n + 4;

           points = new Point3DCollection(numberOfSeparators + 1);

           triangleIndices = new Int32Collection((numberOfSeparators + 1) * 3);

           points.Add(new Point3D(0, 0, 0));

           for (int divider = 0; divider < numberOfSeparators; divider++)

           {

               double alpha = Math.PI / 2 / (n + 1) * divider;

               points.Add(new Point3D(r * Math.Cos(alpha),

                          0, -1 * r * Math.Sin(alpha)));

               triangleIndices.Add(0);

               triangleIndices.Add(divider + 1);

               triangleIndices.Add((divider ==

                 (numberOfSeparators-1)) ? 1 : (divider + 2));

           }

       }

       public DiscGeometry3D()

       { }

  }

}


스피어를
생성하는 코드는 조금 길지만, 스피어를 점으로 나누는 건 정말 간단하다. 삼각형 생성이 좀 어렵긴 하지만 말이다.

using System;

using System.Windows.Media;

using System.Windows.Media.Media3D;

using System.Diagnostics;

namespace Sphere3D

{

  class SphereGeometry3D : RoundMesh3D

  {

       protected override void CalculateGeometry()

       {

           int e;

           double segmentRad = Math.PI / 2 / (n + 1);

           int numberOfSeparators = 4 * n + 4;

           points = new Point3DCollection();

           triangleIndices = new Int32Collection();

           for (e = -n; e <= n; e++)

           {

               double r_e = r * Math.Cos(segmentRad * e);

               double y_e = r * Math.Sin(segmentRad * e);

               for (int s = 0; s <= (numberOfSeparators - 1); s++)

               {

                   double z_s = r_e * Math.Sin(segmentRad * s) * (-1);

                   double x_s = r_e * Math.Cos(segmentRad * s);

                  points.Add(new Point3D(x_s, y_e, z_s));

               }

           }

           points.Add(new Point3D(0, r, 0));

           points.Add(new Point3D(0, -1 * r, 0));

           for (e = 0; e < 2 * n; e++)

           {

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

               {

                   triangleIndices.Add(e * numberOfSeparators + i);

                   triangleIndices.Add(e * numberOfSeparators + i +

                                       numberOfSeparators);

                   triangleIndices.Add(e * numberOfSeparators + (i + 1) %

                                       numberOfSeparators + numberOfSeparators);

                   triangleIndices.Add(e * numberOfSeparators + (i + 1) %

                                      numberOfSeparators + numberOfSeparators);

                   triangleIndices.Add(e * numberOfSeparators +

                                      (i + 1) % numberOfSeparators);

                   triangleIndices.Add(e * numberOfSeparators + i);

               }

           }

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

           {

               triangleIndices.Add(e * numberOfSeparators + i);

               triangleIndices.Add(e * numberOfSeparators + (i + 1) %

                                  numberOfSeparators);

               triangleIndices.Add(numberOfSeparators * (2 * n + 1));

           }

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

           {

               triangleIndices.Add(i);

              triangleIndices.Add((i + 1) % numberOfSeparators);

               triangleIndices.Add(numberOfSeparators * (2 * n + 1) + 1);

           }

       }

       public SphereGeometry3D()

       { }

  }

}


이
예제에서는 아티클 맨 위에 있는 그림처럼 스피어 두 개와 배경의 멋진 그림을 보여주려고 한다. 그래서
SphereGeometry3D에서 상속 받는 클래스 두 개를 생성하기로 했다.

namespace Sphere3D

{

  class BigPlanet : SphereGeometry3D

  {

       BigPlanet()

       {

           Radius = 30;

           Separators = 5;

     }

  }

  class SmallPlanet : SphereGeometry3D

  {

       SmallPlanet()

       {

           Radius = 5;

           Separators = 5;

       }

  }

}


마지막으로
, 위에서 본 그림처럼 실행되도록 하기 위해서는
MeshGeometry3D의 Positions 과 TriangleIndices를 바인딩 해야 한다. 여기에서는 XAML 데이터 바인딩 메커니즘을 사용하여 처리하도록 한다.

<Window x:Class="Sphere3D.Window1"

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

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

  xmlns:local="clr-namespace:Sphere3D"

  Title="Labyrinth3d" Height="600" Width="600"

  >

  <Window.Background>

       <ImageBrush Stretch="UniformToFill"

                   ImageSource="Images/Pleiades.jpg"/>

  </Window.Background>

  <Grid VerticalAlignment="Stretch"

            HorizontalAlignment="Stretch" x:Name="Grid1">

       <Grid.Resources>

           <local:BigPlanet x:Key="SphereGeometrySource1"/>

           <local:SmallPlanet x:Key="SphereGeometrySource2"/>

           <MeshGeometry3D x:Key="SphereGeometry1"

                 Positions="{Binding Source={StaticResource

                            SphereGeometrySource1}, Path=Points}"

               TriangleIndices="{Binding Source={StaticResource

                                 SphereGeometrySource1},

                                 Path=TriangleIndices}"/>

           <MeshGeometry3D x:Key="SphereGeometry2"

                   Positions="{Binding Source={StaticResource

                             SphereGeometrySource2}, Path=Points}"

               TriangleIndices="{Binding Source={StaticResource

                                SphereGeometrySource2},

                                Path=TriangleIndices}"/>

       </Grid.Resources>

      

       <Grid.ColumnDefinitions>

           <ColumnDefinition Width="20"/>

           <ColumnDefinition Width="*"/>

           <ColumnDefinition Width="20"/>

       </Grid.ColumnDefinitions>

       <Grid.RowDefinitions>

           <RowDefinition Height="20"/>

           <RowDefinition Height="*"/>

           <RowDefinition Height="20"/>

       </Grid.RowDefinitions>

       <Viewport3D Grid.Column="1" Grid.Row="1"

                   VerticalAlignment="Stretch"

                  HorizontalAlignment="Stretch" Name="Viewport1">

           <Viewport3D.Camera>

               <PerspectiveCamera x:Name="myCamera" Position="100 30 0"

                     LookDirection="-50 -33 0"

                     UpDirection="0,1,0" FieldOfView="90"/>

               <!--<OrthographicCamera x:Name="myCamera"

                     Position="200 0 0" LookDirection="-1 0 0"

                     Width="180" UpDirection="0,1,0"/>-->

           </Viewport3D.Camera>

           <ModelVisual3D>

               <ModelVisual3D.Content>

                   <Model3DGroup>

                       <DirectionalLight Color="#FFFFFF"

                                Direction="0 -30 0" />

                       <DirectionalLight Color="#FFFFFF"

                               Direction="0 +30 0" />

                       <GeometryModel3D

                              Geometry="{StaticResource SphereGeometry1}">

                           <GeometryModel3D.Material>

                               <MaterialGroup>

                                   <DiffuseMaterial>

                                       <DiffuseMaterial.Brush>

                                           <SolidColorBrush Color="Orange"/>

                                       </DiffuseMaterial.Brush>

                                   </DiffuseMaterial>

                               </MaterialGroup>

                           </GeometryModel3D.Material>

                       </GeometryModel3D>

                       <GeometryModel3D

                             Geometry="{StaticResource SphereGeometry2}">

                           <GeometryModel3D.Material>

                               <DiffuseMaterial>

                                   <DiffuseMaterial.Brush>

                                      <SolidColorBrush Color="Yellow"/>

                                   </DiffuseMaterial.Brush>

                               </DiffuseMaterial>

                           </GeometryModel3D.Material>

                          <GeometryModel3D.Transform>

                               <TranslateTransform3D

                                    x:Name="Sphere2Translation" OffsetZ="50" />

                           </GeometryModel3D.Transform>

                       </GeometryModel3D>

                   </Model3DGroup>

               </ModelVisual3D.Content>

           </ModelVisual3D>

       </Viewport3D>

  </Grid>

</Window>


출처
: http://www.codeproject.com/WPF/XamlUVSphere.asp


관련 파일 :

XamlUVSphere.zip


PDF 다운로드 :
XAML로 스피어-메시 생성.pdf



이 글은 고수닷넷, 데브피아, 훈스닷넷에도 게시되었습니다.

날개달기
2006/12/26 15:25 2006/12/26 15:25
TAG PDF, WPF, XAML
 
받은 트랙백이 없고, 댓글이 없습니다.

트랙백 주소 :: http://blog.paewang.net/trackback/25

 

WPF 관련 자료

분류없음 2006/11/25 17:01
[MSDN 웹 캐스트] .NET Framework 3.0, WPF의 물결 웹 캐스트 시리즈
http://www.microsoft.com/korea/events/WPF1/default.mspx

WPF(windows presentation foundation) 소개
http://network.hanbitbook.co.kr/view.php?bi_id=1307

템플릿을 사용한 WPF 컨트롤 사용자 지정
http://msdn.microsoft.com/msdnmag/issue ··· loc%3Dko

Expression Blend Beta Preview
http://movielibrary.lynda.com/html/modp ··· ef%3Dswf
날개달기
2006/11/25 17:01 2006/11/25 17:01
TAG WPF
 
받은 트랙백이 없고, 댓글이 없습니다.

트랙백 주소 :: http://blog.paewang.net/trackback/8

 
◀ 다음 글 목록 1 이전 글 목록 ▶

블로그 이미지
안녕하세요. 이광수입니다. 저는 한때 세계적인 컨설팅 회사인 맥킨지의 컨설턴트가 되는 목표를 가졌었지만, 지금은 리더십 · 자기계발 전문가를 꿈꾸고 있습니다. 2006년부터 최근까지 마이크로소프트 MVP로 활동했었습니다. by 날개달기

공지사항

패왕넷 - 최근 공지

  • 쿠키미디어에서 필진을 모집...
  • 문의사항
  • 운영자 소개

카테고리

  • ATOM 전체 (231)
    • ATOM 삶의 지혜 (70)
      • ATOM 고수독서법 (4)
      • ATOM 독서토론 (2)
      • ATOM 추천도서 (1)
    • ATOM 소프트웨어 개발 (30)
    • ATOM 소식 (6)

새로 등록된 글

  • 나는 고민에 빠져들게 하는...
  • 먼지가 되느니 차라리 재가...
  • 내가 몰입하는 이유
  • 소비자의 갈망을 충족시켜라
  • 한국리더십센터 up&up에 제... (2)

태그목록

  • 독서경영
  • C#
  • 육일약국
  • 프로필
  • up&up
  • 컨설팅
  • 김성오
  • MSE7
  • 검색
  • Ajax
  • Anthem.NET
  • RSS
  • PDF
  • 디버깅
  • atlas
  • 원고
  • 예약판매
  • 고수독서법
  • IIS
  • MySQL
  • Extentions
  • Debugger
  • 엠베스트
  • 전략컨설팅
  • 한국리더십센터
  • 세미나
  • 추적기
  • 메가스터디
  • 마소
  • 베스트셀러

글 보관함

  • 2010/03 (1)
  • 2010/01 (3)
  • 2009/12 (1)
  • 2009/11 (8)
  • 2009/10 (4)

달력

«   2010/03   »
일 월 화 수 목 금 토
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

새로 달린 댓글

  • 원래 아티클에 첨부된 파일만.... 01/30 날개달기
  • 안녕하세요. 잘 보았는데요...... 01/14 stephen
  • 지속적인 발전을 보이고 있네.... 2009 날개달기
  • 관리자만 볼 수 있는 댓글입.... 2009 비밀방문자
  • 스트레스 관리에 운동만한게.... 2009 날개달기
  • 좋은글이네여 역시 운동이 제.... 2009 montreal florist
  • 네, 참여 가능합니다. 조만간.... 2009 날개달기
  • 독서토론에 참가하고 싶어서.... 2009 성수정
  • 효율적으로 토론할 수 있는.... 2009 날개달기
  • 안녕하세요. 이 글은 프로그.... 2009 날개달기

새로 달린 트랙백

  • 소프트웨어 컨플릭트 2.0 2007 The note of Legendre
  • 자바스크립트 째려보기 2007 조선일보 사절
  • IIS 메타베이스에 액세스하지... 2007 tpoz님의 블로그

링크

  • 56 69 72 75 73 20 4D 79 74...
  • Ajax + 요구공학
  • AmiText
  • Architecture and Design
  • Babel Fish 번역
  • BPM
  • Creating Passionate Users
  • Enterprise Library
  • FreeBooksPedia
  • IT용어 사전
  • J & J
  • jwmx
  • Korea Embedded Developer Bl...
  • Loner's .NET Blog
  • Martin Fowler
  • MSDN Korea
  • MSDN2 라이브러리
  • my msdn
  • Nagging Machine: 꿈은 꾸되...
  • NetFx3
  • Prototype.js
  • Refactoring
  • Script#
  • searchmash
  • stophobia
  • The Art of Project Management
  • Toby’s Epril
  • Visual Studio 용어 사전
  • W3C CSS 검사 서비스
  • 강주헌의 <펍헙 번역학교>
  • 고수닷넷
  • 날개달기, 경영을 말하다
  • 달봉이넷
  • 독서가 만들어주는 하루
  • 두고보자
  • 마이크로소프트 언어 포털
  • 마케팅커뮤니케이터의 공부방
  • 북세미나닷컴 공식 블로그
  • 서광열의 소프트웨어 이야기
  • 소설같은 시리즈
  • 스마트플레이스
  • 애자일 이야기
  • 작은불꽃
  • 조엘 온 소프트웨어
  • 좋은글 러브젝트닷컴
  • 주간번역가
  • 철수네 소프트웨어 세상 3
  • 쿠키미디어
  • 태터툴즈 메뉴얼
  • 패왕넷 - 이즈블로그 분점
  • 패왕넷 - 티스토리 분점
  • 퍼키의 열고 보는 세상
  • 프로그래머의 마음공부
  • 피플웨어
  • 한국 eXtreme Programming 사...
  • 한국마이크로소프트 에반젤리...

카운터

  • 전체 : 80414
  • 오늘 : 6
  • 어제 : 61

이올린

skin by 써머즈