Dip2K’s WPF 3D 입문 (2/3)

이제 앞에서 XAML를 통해 만들어 놓은 UI에 대한 로직을 CS(C# 소스) 코드로 작성해 보는 것을 정리해보자. 코드를 작성하기에 앞서 이해하고 넘어가야 할 것은 WPF의 3D 부분을 구성하고 있는 클래스이다. 이 클래스는 System.Windows.Media.Media3D 네임스페이스에 위치하며 이 글에서 사용하는 주요 클래스의 관계도는 다음과 같다.

각 클래스의 목적(용도)을 간단이 정리하면 다음과 같다.

MeshGeometry3D는 Mesh의 Vertex, Normal, Vertex Index, Textture Coordnate 정보를 가지고 있으며, Material은 Mesh에 대한 재질 정보를, GeometryModel3D는 MeshGeometry3D와 Material 정보를 하나로 묶어 주는 역활을 한다. Model3DGroup는 여러개의 GeometryModel3D을 묶어 마치 하나의 GeometryModel3D 처럼 사용할 수 있도록 하며, ModelVisual3D는 최종적으로 화면에 렌더링하기 위한 목적을 갖는다.

우리는 최종적으로 다음과 같은 결과을 얻고자 한다. 화면상에 정육면체 Mesh를 렌더링하고 사용자가 버튼을 눌러 이 Mesh를 회전시켜 보는 것이다.

Window1.xaml.cs 소스 파일을 보면 기본적으로 Window1 클래스가 있는데, 이 Window1 클래스의 맴버 변수로 아래의 항목을 추가한다.

private ModelVisual3D model = null;
private Transform3DGroup transformGroup = new Transform3DGroup();

model은 최종적으로 화면상에 렌더링할 Mesh로 사용되며 transformGroup은 이동, 회전, 크기조정과 같은 Transform을 위해서 필요한데, model의 Transform 속성에 바로 이 transformGroup를 대입해주면 우리가 원하는 회전이 이루어진다.

이제 앞에서 구성한 UI의 이벤트를 하나 하나 구현해 보도록 하자. 먼저 Cube 버튼을 눌렀을 경우 실행되는 코드는 다음과 같다.

private void ClickCubeButton(object Sender, RoutedEventArgs e)
{
     if (model != null) return;

     Model3DGroup cube = new Model3DGroup();

     Point3D p0 = new Point3D(-1, -1, -1);
     Point3D p1 = new Point3D(1, -1, -1);
     Point3D p2 = new Point3D(1, -1, 1);
     Point3D p3 = new Point3D(-1, -1, 1);
     Point3D p4 = new Point3D(-1, 1, -1);
     Point3D p5 = new Point3D(1, 1, -1);
     Point3D p6 = new Point3D(1, 1, 1);
     Point3D p7 = new Point3D(-1, 1, 1);

     //front side triangles
     cube.Children.Add(CreateTriangleModel(p3, p2, p6));
     cube.Children.Add(CreateTriangleModel(p3, p6, p7));
     //right side triangles
     cube.Children.Add(CreateTriangleModel(p2, p1, p5));
     cube.Children.Add(CreateTriangleModel(p2, p5, p6));
     //back side triangles
     cube.Children.Add(CreateTriangleModel(p1, p0, p4));
     cube.Children.Add(CreateTriangleModel(p1, p4, p5));
     //left side triangles
     cube.Children.Add(CreateTriangleModel(p0, p3, p7));
     cube.Children.Add(CreateTriangleModel(p0, p7, p4));
     //top side triangles
     cube.Children.Add(CreateTriangleModel(p7, p6, p5));
     cube.Children.Add(CreateTriangleModel(p7, p5, p4));
     //bottom side triangles
     cube.Children.Add(CreateTriangleModel(p2, p3, p0));
     cube.Children.Add(CreateTriangleModel(p2, p0, p1));

     model = new ModelVisual3D();
     model.Content = cube;

     mainViewport.Children.Add(model);
}

정육면체는 모두 8개의 Vertex로 이루어져 있으며 총 6개의 사각형의 면으로 이루어져 있다. 3D에서는 면을 삼각형으로 표현하므로, 결과적으로 총 12개의 삼각형의 면으로 이루어진다. 위의 코드에서 Point3D를 이용해 총 8개의 Vertex를 구성하고 Model3DGroup 클래스의 변수인 cube에 삼각형 면을 구성해서 cube의 Children 속성에 넣어준다. 삼각형 면을 구성하기 위해서는 3개의 Vertex가 필요한데, 이렇게 삼각형 면을 구성하는 함수를 따로 만들었다. 그 함수는 아래의 CreateTriangleModel이다.

private Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D p2)
{
    MeshGeometry3D mesh = new MeshGeometry3D();
        
    mesh.Positions.Add(p0);
    mesh.Positions.Add(p1);
    mesh.Positions.Add(p2);

    mesh.TriangleIndices.Add(0);
    mesh.TriangleIndices.Add(1);
    mesh.TriangleIndices.Add(2);

    Vector3D normal = CalculateNormal(p0, p1, p2);
            
    mesh.Normals.Add(normal);
    mesh.Normals.Add(normal);
    mesh.Normals.Add(normal);

    Material material = new DiffuseMaterial(new SolidColorBrush(Colors.Blue));
    GeometryModel3D model = new GeometryModel3D(mesh, material);
            
    Model3DGroup group = new Model3DGroup();
    group.Children.Add(model);
            
    return group;
}

CreateTriangleModel은 세개의 Vertex를 받아서 MeshGeometry3D를 만들어주게 되는데, 이 MeshGeometry3D는 앞서 설명했던 것처럼 Vertex와 이 Vertex의 인덱스로부터 삼각형의 면을 구성하기 위한 Vertex Inddex 지정, 그리고 빛에 대한 사실적인 재질 렌더링을 위한 법선 벡터를 갖는다. 그리고 파랑색의 재질을 만들기 위해 Material 클래스를 사용하였고, 이렇게 만들어진 두개의 MeshGeometry3D와 Material을 묶어서 GeometryModel3D 클래스의 인스턴스를 만들어었다. 그리고 최종적으로 Model3DGroup을 생성해 GeometryModel3D의 인스턴스를 자식으로 추가해준후 반환해주게 되면 파랑색의 삼각형면이 하나 만들어지게된다. 여기서 빛에 대한 사실적인 렌더링을 위한 법선 벡터를 만들기 위해 또 하나의 함수를 만들었는데 아래와 같다.

private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
    Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
    Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);

    return Vector3D.CrossProduct(v0, v1);
}

법선벡터는 면에 대한 수직벡터이다. 벡터의 외적을 이용하여 구할 수 있으며 위의 코드가 그 외적을 구현하고 있다.

여기가지 코딩을 하고 실행한후, Cube 버튼을 눌러보면 화면상에 Mesh가 나타나게 된다. 이제 X, Y, Z 축에 대한 회전 버튼을 눌렀을 경우에 대한 이벤트를 구현해보자. 먼저 RotateX 버튼에 대한 구현부는 아래와 같다.

private void ClickRotateXButton(object Sender, RoutedEventArgs e) 
{
    AxisAngleRotation3D rotation = new AxisAngleRotation3D(
        new Vector3D(1, 0, 0), 5);

    RotateTransform3D rt = new RotateTransform3D(rotation);
            
    transformGroup.Children.Add(rt);

    model.Transform = transformGroup;
}

X축을 기준으로 하는 회전에 대한  정보를 만들기 위해서 AxisAngleRotation3D 클래스를 사용하였다. X축이므로 (1,0,0)와 5도 만큼의 회전값을 인자로 주어 생성을 하였다. (참고로 회전은 축에 대한 회전과 쿼터니언에 의한 회전이 있으며 WPF는 둘 모두를 지원한다) 이제 AxisAngleRotation3D를 이용해 실제 회전 Matrix(행렬)을 만들기 위해 RotateTransform3D 클래스를 생상하며, 이렇게 생성된 RotateTransform3D를 앞서 Window1 클래스의 맴버로 추가한 Transform3DGroup 클래스 타입인 transformGroup의 Children으로 추가한다. 자식으로써 추가하는 이유는 회전뿐만이 아니라 이동이나 크기조정 등과 같은 여러개의 Transform을 다중으로 적용할 수 있도록 하기 위해서이다. 결국 이렇게 설정된 transformGroup를 model의 Transform 속성에 넣어주게 되면 버튼을 누를때마다 X축으로 회전이 일어나게 된다. Y축과 Z축에 대한 회전은 그 축만 다르고 나머지는 동일하므로 설명은 생략한다.

Dip2K’s WPF 3D 입문 (1/3)

.NET 3.0의 기초화장(파운데이션) 중에 하나인 WPF에 대한 자료를 찾아 살펴보았다. 2D에 앞서 바로 3D를 살펴보았는데.. 이를 정리해 보고자한다.

먼저 개발을 위한 요구사항은 먼저 .NET 3.0 Framework를 설치해야 한다. 그리고 2개를 더 설치해줘야 하는데..  Microsoft Windows SDK for .NET Framework 3.0와  Visual Studio 2005 extensions for .NET Framework 3.0 (WCF & WPF)를 순서대로 설치해야 한다. 물론 이 모두에 앞서 OS(Win2000, XP, Vista)와 Visual Studio 2005가 설치되어져 있어야 한다. 참고로 필자의 OS는 .NET 3.0이 이미 설치된 윈도우즈 비스타이다.

일단 필요한것을 모두 실치했다면 VS2005를 실행해보라. 그리고 새로운 프로젝트 생성을 실행시키면 다음과 같은 WPF와 WCF 관련 프로젝트 생성을 위한 템플릿이 추가된다. (아래 이미지 캡춰는 비스타의 기본 프로그램인 “캡처도구”를 사용하였다) 참고로 WWF, 즉 지금의 WF는 또 다른 Extensions를 설치해줘야 한다.

여기서 Windows Application (WPF)를 선택하자. WPF에서 2D와 3D가 따로 있는것이 아니라 2D든 3D든 똑같이 WPF인데, 새로운 프로젝트를 생성하게 되면 자동으로 솔루션 탐색기에 아래와 같은 파일들이 자동으로 구성된다.

여기서 실제 우리가 관심을 집중시켜 코딩할 소스 파일은 Window1.xaml과 Windows1.xaml.cs이다. 확장자 XAML은 eXtansible Application Markup Language로써 개발단계에서 UI와 Data 부분을 정의할 수 있는 XML 포멧이다. UI와 Data가 아닌 실행에 관련된 로직은 확장자가 CS인 XAML 까지 포함한 동일한 파일명이다. 여기서 한가지 더 언급하면 Data의 경우 XAML 에도 넣을 수 있지만 CS 에서도 정의할 수 있다는 점이다. 여하튼 바로 이러한 UI와 Logic의 분리.. 즉, UI는 XAML 에 작성하고 로직은 CS 에 작성한다는 것이 디자이너와 개발자간의 분리된 효율적인 협업이 손쉬워졌다는 것이다. 아직 이러한 방식으로 프로젝트에서 디자이너와 협업을 해보지 않아서 모르겠지만, 적용했을시에 개발자는 편해지겠지만 디자이너는 머리가 좀 아플것같다. 디자이너가 XAML 에 익숙해져야 하는데, 이 XAML 이 꽤나 많은 내용을 담고 있기 때문인데… 이러한 문제점에 대해서 MS에서는 디자이너가 코딩보다는 미적인 감각을 더욱 잘살리길 바라는 바, XAML을 좀더 쉽게 만들 수 있는 툴을 MS에서 제공하고 있다. (참고로 XAML은 발음은 “제믈” 이다)

이제 UI를 작성해보자. 즉, 아래와 같은 폼을 구성할 것이다.

도구모음을 통해 해당 컨트롤을 가져다 디자인을 하든, 아니면 필자처럼 직접 xaml을 막코딩하든…. 위의 폼 구성에 대한 xaml의 내용은 다음과 같다. 참고로 여전이 WPF를 위한 VS2005의 개발환경의 지원은 완벽하지 않다.


  
    
      
        
        
        
        
      
      
      
        
          
        
        
          
            
          
        
      
    
  

청색 코드가 실제로 새롭게 추가된 코드이다. 먼저 폼에 DockPanel 컨트롤을 올려 놓았고 그 DockPanel의 좌측에 StackPanel와 우측에 Viewport3D 컨트롤을 올려놓았다. StackPanel에는 Cube, RotateX, RotateY, RotateZ 버튼이 놓여있다. 위의 코드를 보면 각 버튼을 클릭했을때 수행해야할 이벤트 매서드가 Click이라는 속성의 값으로 지정 되어져 있다. 이 이벤트 지정에 관련된 부분만 뽑아내 보면 아래와 같다.


    
    
    
    

이제 Viewport3D를 살펴보자. OpenGL이나 DirectX와 같은 3D 그래픽 개발을 해본 사람이라면 알겠지만 이 XAML 의 Viewport3D 요소 안에 카메라의 설정과 빛이 정의되어져 있다. 마찬가지로 3D Model에 대한 좌표데이터와 같은 Data 부분도 이 XAML 에 정의할 수 있다는 것은 앞서 언급을 했다. Viewport3D를 로직 구현부분(CS 파일)에서 접근하기 위해 Viewport3D의 Name 속성의 값으로 “mainViewport”로 지정해 놓았다. 그리고 카메라와 빛에 대한 정의가 되어 있다. 3D 개발을 해본 사람이라면 이 부분(카메라와 빛의 속성)은 직관적으로 알 수 있기에 자세히 설명하지 않겠다. (궁금하면 방명록에 질문을 하시길..) Viewport3D에 대한 부분만을 다시 나타내보면 아래와 같다.


    
        
    
    
        
            
        
    

여기까지가 UI에대한 XAML 부분이고 UI의 이벤트 등과 같은 로직에 대한 부분은 다음에 살펴보기로 하겠다.

Shape에 Effect 넣기

예전에 PowerPoint 2007을 설치하고 글자와 도형에 멋진 효과를 넣을 수 있는 것을 보고 직접 구현해 보았다. GDI+을 이용하였으며 Native C++로 구현하였다. 필요한 자료를 찾던 중에 윈도우즈 개발 환경은 이제 C#으로 넘어가야하나라는 생각이 강하게 들었다. 같은 GDI+라도 .NET과 Native Win32에서 제공되는 클래스가 차별화되어있고 많은 GDI+ 관련 자료가 C#으로 되어 있는 이유이다.

위의 실행 결과를 보면 Shape에 입체효과(베벨 또는 엠보싱)와 그림자를 넣어주었다. 이미지 처리에서 사용되는 Convolution Filter로써 Blur Filter와 Emboss Filter를 사용하여 효과를 주었다.

간단이 과정을 살명하면 먼저 도형을 GraphicsPath를 통해 만들고 이 Path를 임시 버퍼에 검정색으로 그린뒤, 이 버퍼에 Blur 효과를 주고 화면상에 그리면 그림자가 그려지게 된다. 여기에 사용한 Convolution Filter는 다음과 같다.

const int filterHalfSize = 4;
int convolutionFilter[(filterHalfSize*2+1)*(filterHalfSize*2+1)] = { 
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1, 1,
};

Divider 값은 필터의 크기가 9이므로 그 두배인 81로 했다. 이렇게 그림자를 그린후에 이 위에 그대로 Path를 그린다. 이제 다시 Emboss 효과를 줘서 만든 이미지를 생성하는데 여기에 사용한 Filter는 다음과 같다.

const int filterHalfSize2 = 1;
int convolutionFilter2[
	(filterHalfSize2*2+1)*(filterHalfSize2*2+1)] = { 
	1, 0, 0,
	0, 0, 0,
	0, 0, -1,
};

Divider 값은 1로 했으며(즉, 평균을 내기 위해 나누지 않았으며) 결과값에 32를 더했다. Emboss 효과를 적용해서 만들어진 이미지는 다음과 같다.


이것을 그대로 사용하면 않되고 원래 도형의 모양으로 Clipping 해야한다. GDI+의 grfx의 SetClip 함수를 이용해 Clipping해서 그려주게 되면 완료된다.

과거에는 이러한 효과를 실시간으로 적용하기에는 연산 속도가 느려 전문분야에나 활용되다가 이제는 윈도우즈 비스타의 UI에 기본적으로 사용되고 있다. 갑작이 드는 생각은 OS에서 버전업이라는 개념은 그 속내의 변화보다는 겉모양의 변화가 발생했을때 이루어지고 있다는 것이다. 속내의 변화는 서비스팩이나 업데이트를 통해 이루어지고 있고 새로운 제품으로써 버전업은 일반 사용자에게 가장 강하게 어필할 수 있는 UI 부분의 진보이다. 이러한 UI의 중요성을 절대 무시해서는 않될 것 같다.

4대 비지니스 스킬

파워포인트 2007을 이용해서 만들어 본것이다. 파워포인트의 산출물 퀄러티.. 간지가 아주 그냥 좔좔… 내가 담당하고 있는 저작툴.. 파워포인트 2007처럼 만들어봐?

In Thinking..

나는 전북대학교 토목공학과를 졸업했다. 고등학교 3학년때 컴퓨터공학이나 컴퓨터과학과를 가고 싶었지만, 학점도 딸렸고 정확히 말하면 그 당시에 컴퓨터는 단지 도구이고 그 도구 자체를 배우는 것보다는 좀더 현실에서 응용할 수 있는 분야를 공부하고 싶어서라는 당돌하고 아무것도 모르는 발상으로 토목공을 지원했다.

지금 생각해보면 만약 내가 처음부터 컴퓨터공학 쪽을 갔다면 또 어땠을까 하는 후회도 드는것도 사실이지만 GIS를 접할 수 있는 계기가 되어줬다는 점에서 후회는 그다지 크지도 않고, 항상 컴퓨터 분야를 전공하는 사람보다는 실력면에서 부족할 것이므로 더욱더 열심히 독학으로 공부를 했다. 내가 토목공을 나왔지만 토목공을 잘모르는 것처럼 컴퓨터분야를 나왔다고 해서 컴퓨터를 잘아는 것과는 관계가 없는 것 같다. 단지 동기부여와 기회을 제공한다는 차이점만 있을뿐 그 동기에 감동하고 기회를 잡는 것은 각자 자신의 몫이라는 것을 깨닫는것이 중요하지 않을까?

나에게 무척이나 진부하고 재미없었던 토목공학과를 겨우 졸업하고, 토목공학과 지형공간정보 대학원에 들어갔다. 간판으로 내세우는 홍보용 명칭은 GSIS & RS 연구실이였고, 나는 나와 친한 선배를 따라 GIS를 하게 되었다. 대학원에서 나는 4년동안 토목공학이라는 가시덩쿨에서 벗어나 마음껏 컴퓨터를 공부하고 활용할 수 있었다. 지금 생각해보면 학교에서였지만, 대학원생으로써 사회인 못지 않은 규모의 프로젝트를 수행 했었고 여느 전문 개발자 못지 않는 품질의 GIS 프로그램을 개발했다고 자부했었다. 하지만 그것은 내가 실력이 있어서가 아니라는 것을 깨닫게 되었다.

PDA용 프로그램을 작성해야할때 C밖에 몰랐던 나는 C++을 공부하면서 클래스만 사용하면 C++인줄로만 알고 열심히 “알기쉽게 해설한 C++” 책을 찾아가며 코딩을 했다. 그것이 내가 남들보다 쉽게 졸업 논문을 쓸 수 있게 한 “PDA를 이용한 교통사고 후처리 시스템”이며 이 블로그의 GIS 카테고리에 간단히 소개가 되어져있다. 오늘 잠시 그 당시에 C++를 공부하면서 코딩했던 그 코드를 들여다 보았다. 웃음은 커녕 내 가슴을 철렁하게 만든다. 문자열 처리라든지 메모리 할당방법, 메모리 해제는 제대로 해주고 있기나 한걸까? 그리고 UI를 띠우는 코드가 클래스와 공존한다든지… 어떻게 이런식으로 작성을 해서, 잘 돌아간다고 생각을 하고 자랑스럽게 시연을 했던 것일까? 이 소스를 가지고 어느 모업체에서 사업을 하고 있다고 하는데, 얼굴이 불어지고 가슴이 철렁 내려 앉는다. 또한 그때 스스로 대견해하며 우쭐하기만 했던 내 자신이 부끄러워진다.

그 시절에 제법 나는 실력이 있어.. 라는 생각은 완전이 잘못된 것이다. 열정이였다. 그 열정으로 순간 순간 머리가 노랗게 되는 상황에서도 해결책을 찾기 위해 나와 사투를 벌이며 노력했었고 그 열정의 댓가로 항상 해결책은 제공되었다. 어쩌면 운이 좋았기 때문인지도 모르겠다. 하지만 그 당시에는 코더로써 무엇가를 만들어 내는 것이 너무나도 즐거웠고 만족스러웠다.

그런데 그 당시에 항상 마음에 걸리는 것이 있었다. 그것은 내가 지금 하고 있는것이 GIS인가? 라는 의구심이였다. 대학원에서 선배들은 GIS에 이용하여 환경, 수질, 토지적성에 대한 분석을 할때, 나는 그 분석에 대한 것을 코딩으로 구현하고 그럴듯하게 UI를 만들어 주며 우쭐해 하곤 했었다. 하지만 그 우쭐함 뒤에는 나도 이런 코딩이 아니라 선배들처럼 GIS를 이용한 분석을 해야하지 않겠는가… 라는 갈등이 있었지만, 학사 4년동안 컴퓨터에 목말랐던 나는 컴퓨터 코딩 이외에 어느 무엇에도 눈을 돌릴 여유가 없었다……….. 하지만 언젠가는 정말 좀더 보다 GIS적인 것을 할것이기에 석사때는 컴퓨터에 매진하는것이 옳다고 믿었고 그래왔다.

그러다가 지금….. 나를 돌아본다… 여전이 나는 코더이다. 첫번째도 지금 다니는 회사 역시 GIS 분야이며, GIS 관련 어플을 개발하고 있다. 내가 전산분야 학과를 지망하지 않고 토목공학과를 지망해서 귀에 걸면 귀걸이, 코에 걸면 코걸이라는 속담에 딱인 GIS 활용 분야의 무한한 매력을 가지는GIS를 선택하였고, 지금도 후회는 없다. 하지만 석사때의 나와 지금의 나는 전혀 발전이 없이 그대로이다. GIS에 대한 전문 지식이 없어도 컴퓨터 프로그래머라면 누구나 자신이 아는 지식의 범위에서, 아니면 공부를 해서라도 할 수 있는 그런 것들이다.

이 순간만을 놓고 불때 나는 좌절을 느낀다. 아무리 넘쳐나는게 석사라지만, 그래도 GIS 분야의 석사라면, GIS 분야의 석사 다워야 하지 않겠는가? 하지만 여전이 나는 코딩을 좋아하고 코더라는 직업은 하늘이 내게 정해준 직업과 같다. 하지만 문득 이런 생각도 든다. 혹시 이 코딩이 나에게 천직이 아닌건 아닐까? 단지 내가 지금까지 가장 열심히 해왔던 것이 코딩이였기때문에 이런 착각이 드는 것은 아닐까….

하지만 이제 그건 중요하지 않다. 여전이 나는 코딩을 미치도록 좋아라하는 코더이고, 항상 공부를 해야하는 것에 대한 괴리감에 빠지는 일부 개발자와 다르게 최신 기술에 대한 공부를 즐길 줄 아는 운 좋은 코더이다. 이제는 하늘이 정해준 직업이 아니라 내 자신이 나에게 정해진 직업이다. 하지만 지금 나의 코더로써의 모습은 대학원 시절에 “알기쉽게 해설한 C++”을 읽으며 열정 하나로, 오로지 나에게는 엄청난 무엇을 만든다는 착각에서의 그때와 변한게 하나도 없다. 내가 불안한 것은 지금 현재의 열정은 언젠가는 식는다는 것이다. 어떤 목표에 대한 열정은 그 목표를 이루기 전에도 소멸할 수 있고, 그 목표를 이룬 후에도 소멸할 수 있다. 그 열정을 통해 또 다른 발전된 나와 상황을 만들어야 하며 그런 나와 상황에서 또 다른 목표에 대한 열정을 창조해야하지 않을까?

내 안의 나에게 절실하게 묻는다. 내가 원하는 것은 무엇인가? 내가 원하는 것이 내 삶에 더 많은 가능성과 설레임 그리고 희망을 제공할 수 있는가? 만약 그렇다면 내가 원하는 것을 이루기 위해 해야할 것은 무엇인가? 그리고 내 안의 나에게 간절이 부탁한다. 생각해보라고…. 내가 나에게 대답했던 것에 대한 답변에 대해서 깊이… 깊이… 생각해 보라고 말이다.