Tech/Silverlight2010. 1. 6. 17:11

1. Custom Animation?

Silverlight에서 Storyboard를 사용한 Animation을 적용하고자 할 때 특정한 Property에 대한 Animation 적용이 힘든 경우가 있다. (ex. Grid의 Margin)

그것을 위해서 사용자가 직접 Animation을 구현하는 Class를 작성하면 된다.

Custom Animation Class는 DependencyProperty로 Time, Target, From, To, TargetProperty를 구현한다.


2. Thickness Animation

Grid의 Margin은 Type이 Thickness이다. 이것의 Animation을 위한 ThicknessAnimation Class는 다음과 같이 구현할 수 있다.



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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

using System.Windows;
using System.Windows.Media.Animation;

namespace CCPContentsList
{
    public class ThicknessAnimation  
    { 
        // The time along the animation from 0-1
        public static DependencyProperty TimeProperty = DependencyProperty.RegisterAttached(
            "Time", typeof(double), typeof(DoubleAnimation), new PropertyMetadata(OnTimeChanged));
        // The object being animated
        public static DependencyProperty TargetProperty = DependencyProperty.RegisterAttached(
            "Target", typeof(DependencyObject), typeof(ThicknessAnimation), null);
        // The thickness we're animating to
        public static DependencyProperty FromProperty = DependencyProperty.RegisterAttached(
            "From", typeof(Thickness), typeof(DependencyObject), null);
        // The tickness we're animating from
        public static DependencyProperty ToProperty = DependencyProperty.RegisterAttached(
            "To", typeof(Thickness), typeof(DependencyObject), null);
        // The target property to animate to.  Should have a property type of Thickness
        public static DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached(
            "TargetProperty", typeof(DependencyProperty), typeof(DependencyObject), null);

        /// <summary>
        /// Creates a Timeline used to animate the thickness of an object
        /// </summary>
        /// <param name="target">The object to animate</param>
        /// <param name="targetProperty">The property on the object to animate</param>
        /// <param name="duration">The length of the animation</param>
        /// <param name="from">The begining thickness</param>
        /// <param name="to">The final thickness</param>
        /// <returns>A timeline object that can be added to a storyboard</returns>
         public static Timeline Create(
             DependencyObject target, 
             DependencyProperty targetProperty, 
             Duration duration, 
             Thickness from, 
             Thickness to, 
             EasingFunctionBase ease)
         {
             DoubleAnimation timeAnimation = new DoubleAnimation() 
                    { From = 0, To = 1, Duration = duration, EasingFunction = ease };
             timeAnimation.SetValue(TargetProperty, target);
             timeAnimation.SetValue(TargetPropertyProperty, targetProperty);
             timeAnimation.SetValue(FromProperty, from);
             timeAnimation.SetValue(ToProperty, to);
             Storyboard.SetTargetProperty(timeAnimation, new PropertyPath("(ThicknessAnimation.Time)"));
             Storyboard.SetTarget(timeAnimation, timeAnimation); 
             return timeAnimation;
         }

         ///<summary>
         ///Silverlight's animation system is animating time from 0 to 1.  
         ///When time changes we update the thickness to be time
         ///percent between from and to 
         ///</summary>
         private static void OnTimeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
         {
             DoubleAnimation animation = (DoubleAnimation)sender;
             double time = GetTime(animation);
             Thickness from = (Thickness)sender.GetValue(FromProperty);
             Thickness to = (Thickness)sender.GetValue(ToProperty);
             DependencyProperty targetProperty = (DependencyProperty)sender.GetValue(TargetPropertyProperty);
             DependencyObject target = (DependencyObject)sender.GetValue(TargetProperty);
             target.SetValue(targetProperty, new Thickness((to.Left - from.Left) * time + from.Left,
             (to.Top - from.Top) * time + from.Top,
             (to.Right - from.Right) * time + from.Right,
             (to.Bottom - from.Bottom) * time + from.Bottom));
         } 

         public static double GetTime(DoubleAnimation animation)
         {
            return (double)animation.GetValue(TimeProperty);
         }

         public static void SetTime(DoubleAnimation animation, double value)
         {
            animation.SetValue(TimeProperty, value);
         }
    }
}

- 여기서 중요한 부분은 OnTimeChanged 함수이다. 이 함수로 들어온 DoubleAnimation으로 부터 설정한 애니메이션 정보를 얻은 다음에, Margin 값을 직접 수정하게 된다. (Margin의 Type은 Thickness)

- 이를 응용하면 애니메이션 적용이 힘든 다른 Property도 Custom Animation을 제작해 사용할 수 있다.


Posted by 알 수 없는 사용자
Tech/Silverlight2010. 1. 1. 14:21

Commands in Silverlight with SLExtensions - 1에서 이어집니다.

일단, 앞에서 새로 빌드한 SLExtensions.dll 파일을 프로젝트 참조에 추가해두고 다음으로 넘어가도록 합시다.

커맨드 제공자

첫 번째로는 커맨드들을 모아 둘 Commands 라는 정적 클래스를 만듭니다. 가령 무엇인가 삭제하는 Delete 라는 커맨드를 만든다고 하면 다음과 같은 Commands 클래스가 만들어지게 됩니다.

public static class Commands
{
public static Command DeleteCommand { get; private set; }

static Commands()
{
DeleteCommand = new Command("DeleteCommandName");
}
}

정적 생성자에서 정적 속성인 DeleteCommand를 초기화하는 것을 볼 수 있습니다. Command 개체의 생성자에 넣는 커맨드 이름은, 사용하려는 커맨드 이름과 동일하게 "DeleteCommand"라고 지정하는 것이 보통이겠으나 여기서는 확실히 구분을 주기 위해서 "DeleteCommandName"이라고 지정해 보았습니다.


ViewModel 연결

ViewModel 에서는 삭제 커맨드가 실행되었을 때 뭔가 삭제하는 작업을 수행해주어야 되겠죠. 커맨드가 실행되었다는 것을 알기 위해서 다음과 같이 생성자에서 Executed 이벤트를 구독합니다.

public MainPageViewModel()
{
Commands.DeleteCommand.Executed += new EventHandler<ExecutedEventArgs>(DeleteCommand_Executed);
}

DeleteCommand_Executed 라는 메서드에서 삭제 작업을 수행해 줄 것이라고 기대할 수 있겠습니다.


View 연결

이제 View에서 커맨드를 발생시키도록 합니다. 먼저 커맨드 관련 클래스들이 포함되어 있는 SLExtensions.Input 네임스페이스를 추가합니다.

xmlns:input="clr-namespace:SLExtensions.Input;assembly=SLExtensions"

다음으로는 삭제 버튼에 삭제 커맨드를 지정해줍니다.

<Button Content="Delete" input:CommandService.Command="DeleteCommandName"/>

DeleteCommandName 이라는 문자열을 사용해서 실행될 커맨드를 지정하고 있습니다. 이제 이 버튼을 클릭하면 삭제 커맨드가 실행되는 것이지요.


View - ViewModel 연결

한 번 실행해보기 위한 작업을 해 봅시다. 일단 ViewModel의 DeleteCommand_Executed 메서드에서 메시지 박스를 띄우도록 합니다.

void DeleteCommand_Executed(object sender, ExecutedEventArgs e)
{
MessageBox.Show("DeleteCommand");
}

그리고 View 생성 시 ViewModel이 같이 생성되도록 View의 xaml 파일을 수정합니다. 일단 프로젝트의 네임스페이스를 추가하고,

xmlns:local="clr-namespace:SilverlightApplication3"

ViewModel을 생성하도록 데이터 컨텍스트를 추가합니다. UserControl 태그의 여는 태그 바로 아래에 다음과 같은 내용을 추가합니다.

<UserControl.DataContext>
<
local:MainPageViewModel />
</
UserControl.DataContext>

이제 프로젝트를 실행해서 삭제 버튼을 누르면 메시지 박스가 뜨는 것을 볼 수 있을 것입니다.


이번에는 커맨드 패턴을 이용하여 어떻게 View와 ViewModel을 연결시키는지 간단히 살펴보았습니다. 다음 연재에서 좀 더 상세한 내용을 다뤄보도록 하겠습니다.

'Tech > Silverlight' 카테고리의 다른 글

[Silverlight Custom Font 적용]  (0) 2010.01.12
Custom Animation in Silverlight  (1) 2010.01.06
Commands in Silverlight with SLExtensions - 1  (0) 2009.12.26
Silverlight Pixel Shader 개발 팁  (0) 2009.10.28
Posted by wafe
Tech/Silverlight2009. 12. 26. 20:40

커맨드 패턴이 뭔지에 대한 설명은 생략하고 다짜고짜 들어가보도록 하겠습니다.

왜 커맨드 패턴인가?

보통 WPF/Silverlight에서는 Presentation Model 패턴(흔히 MVVM 패턴)을 써서 GUI(View)와 프로그램 상태(ViewModel)를 분리합니다. Binding 이라는 기술적인 개념 덕분에 xaml.cs 파일에는 코드 한 줄 쓰지 않고도 View와 ViewModel을 연결할 수가 있고, View와 ViewModel이 서로를 몰라도 되는 상황을 유지할 수 있습니다. 그런데 이건 보여주는 기능에만 해당되는 얘기일 뿐 사용자가 버튼을 클릭했을 때 발생하는 이벤트를 처리한다거나 하는 일을 위해서는 xaml.cs(View)에서 코드를 통해 ViewModel의 메서드를 호출해 줘야 합니다.

커맨드 패턴을 사용하면 View와 ViewModel의 분리 상태를 유지하면서 View에서 발생한 이벤트를 ViewModel로 알려줄 수 있게 됩니다.

준비 사항

Silverlight 4 이전 버전에서 커맨드 패턴을 사용하려면 SLExtensionsComposite Client Application Guidance(Prism) 라이브러리를 사용하면 됩니다. MS의 patterns & practices 그룹에서 발표한 Prism을 쓰고 싶었지만 단지 커맨드 패턴만을 쓰기 위해서는 프레임워크도 그렇고 문서도 그렇고 너무 방대해서 짧은 시간에 파악하기 힘들었습니다. 그래서 이번에는 SLExtensions를 사용해보도록 하겠습니다.

SLExtensions 다운로드 페이지에서 받을 수 있는 알파 릴리즈를 사용하면 Blend에서 프로젝트를 열였을 때 다음과 같은 에러가 발생하면서 XAML을 로드할 수 없게 됩니다.

A command with the same name '{0}' is already registered.

Blend에서 더미 데이터가 채워져 있는 GUI를 보면서 디자인 할 수 있다는 건 상당한 장점인데, 그러한 장점을 못쓰게 된다는 것은 뼈아픈 일이지요. 다행히 최신 소스 코드(현재 Changeset 35533)에서는 이 문제가 해결되어 있습니다.

일단 Source Code 페이지 우측의 Latest Version Download 링크에서 최신 버전 소스를 받습니다. 압축을 풀면 나오는 소스에서 trunk/SLExtensions/SLExtensions 폴더의 프로젝트를 빌드해서 사용하면 됩니다. 빌드된 dll 파일은 ClientBin 폴더에 생성됩니다.


다음 연재 : Commands in Silverlight with SLExtensions - 2

'Tech > Silverlight' 카테고리의 다른 글

Custom Animation in Silverlight  (1) 2010.01.06
Commands in Silverlight with SLExtensions - 2  (0) 2010.01.01
Silverlight Pixel Shader 개발 팁  (0) 2009.10.28
[Element Binding]  (0) 2009.10.12
Posted by wafe
Tech/WPF2009. 11. 12. 17:34
이전글 : [WPF 3D UI 구현하기 - 2]

이제 물체가 어떤 방식으로 빛을 반사하게 될 지를 결정하는 Material을 알아보도록 하자.
Material은 총 세 가지 종류로 되어 있다.
1. DiffuseMaterial
2. SpecularMaterial
3. EmissiveMaterial

Blend에서 한 번 확인해 볼까?



ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ..ㅋ.ㅋㅋㅋㅋㅋㅋㅋㅋ.....
ㅋ.
..
발광 재질 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 발광 ㅋㅋㅋㅋㅋㅋㅋㅋ ... ㅋ...ㅋ....

나만 재밌었나보다... -ㅅ-)... 어흠

여하튼, Blend에서도 저 3가지 종류의 Material을 설정할 수 있도록 되어 있다. 싱기방기.
내가 사용한 Material은 DiffuseMaterial인데 이 아이는 조명에 영향을 많이 받는다. 조명(Light)으로부터 들어오는 빛의 각도와 물체의 각도가 좁을수록 반사되는 빛이 많아지고, 각도가 클수록 반사되는 빛의 양이 적어진다. 때문에 빛을 덜 받는 부분은 자연스럽게 명암이 생긴다.
그런데 내가 만든 앞면 Panel은 평면이기 때문에 회전하지 않은 이상 정면에서 조명을 받게 되면 명암이 생길 이유가 없다. ㅎ.


<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White"/>
</Viewport2DVisual3D.Material>

IsVisualHostMaterial을 이 곳에서 True로 설정해주어 쌩뚱맞다고 생각할지도 모르겠다.
이 아이에 대해 msdn에 물어보면

"재질이 대화형이어야 하는지 여부를 지정하는 값을 가져오거나 설정합니다."
http://msdn.microsoft.com/ko-kr/library/system.windows.media.media3d.viewport2dvisual3d.isvisualhostmaterial.aspx

라고 대답할 것이다. 즉 지금 표현할 2차원 물체의 재질이 사용자와 상호작용을 할 놈인지 아닌지를 설정해주는 것이라고 생각하면 될 것 같다.
이것을 false로 설정한다면 ? 직접 해 보면 알겠지만 안 보인다.
물체가 반사할 색상은 White로 설정하였다. 사실 Geometry를 이용해서 물체를 그린 것이 아니고 이미 앞면 Panel을 만들어 놓은 상태에서 그것을 불러오기 때문에 굳이 반사할 색상을 정해주지 않아도 된다.

이제 실제 나타날 물체의 정보를 적어주면 되는데...
아주 간단하다.
<Viewport2DVisual3D.Visual> 같은 Visual에 대해 선언할 필요도 없이 바로 그냥 물체를 나타내는 XAML코드를 적어주면 된다.

1
<local:FrontPanel x:Name="FrontPan"/>

새로운 UserControl을 추가 생성하여 그 곳에 앞면 Panel을 만든 후에 정보를 불러왔기 때문에 별다른 정의 없이 위와 같은 방법으로 로드하면 된다.
예를 들어, 버튼을 Visual로 설정하려고 한다면

1
<Button x:Name="myButton" Width="100" Height="30" Content="Ok" />

이와 같이 한 줄만 추가하면 될 것이다.

자, 이제 뒷면 Panel을 추가해줘야 한다. 비로소 내가 화면에 보여주고 싶은 애들은 다 끄집어 낸 거다. (고작 2개뿐이지만...)
이 아이도 앞면 Panel과 같은 방식으로 Viewport2DVisual3D를 사용하여 만들어주면 되는데, 다른 점은 Transform 에서 미리 Y축으로 180도 회전 시킨 상태여야 한다는 것이다.

1
2
3
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="180" Axis="0,1,0"/>
</RotateTransform3D.Rotation>

위와 같이 앞면 Panel과는 다르게 RotateTransform의 Angle 정보가 바뀌어져 있다.
이렇게만 설정해 주면 뒷면 Panel은 앞면 Panel과 반대 방향으로 뒤집혀져 있게 될 것이다.

-ㅁ-) 후아.. 드디어 두 Panel들을 3D로 변환시켰다.

끗--------------------------!!
... 이라고 말하고 싶지만 아직 한 가지가 남았다.
조명 =ㅍ=) !!!!!! ... OTL
이전에도 말했겠지만 조명이 없으면 그대는 내내 시커먼 물체를 멀뚱멀뚱 바라보는 수밖에 없을 것이다.

간단하게 조명을 붙여주자.

1
2
3
4
5
<ModelVisual3D x:Name="Light">
<ModelVisual3D.Content>
<DirectionalLight Color="White" Direction="0,0,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>

나는 Panel의 일부만을 비출 것도 아니기 때문에 DirectionalLight나 AmbientLight 둘 중에 하나를 고를 수 있는데, AmbientLight는 모든 각도에서 빛을 비추기 때문에 Panel을 회전시켰을 때에 명암이 발생하지 않게 된다. 때문에 여기선 DirectionalLight를 사용하기로 한다.

Light의 Direction은 0의 값을 가지면 비추지 않는다. Direction의 "0,0,-1"은 기본값이다. 빛의 세기를 조절하고 싶다면 살짝살짝 수치를 조정해주면 된다. Color는 조명색을 의미하는데 빨간색으로 변경하면 정육점 분위기를 연출할 수 있다.

자! 이제 조명을 비춰주었기 때문에 내가 원하는 Panel의 모습이 보인다!

만쉐~~!! ' ㅁ')/

이제 남은 것은 Panel에 있는 버튼을 이용하여 회전하는 문제인데,
이것은 Storyboard를 이용한 애니메이션 효과이기 때문에 여기선 언급하지 않겠다.

오늘은 여기까지~ ^ㅁ^)v


Posted by 알 수 없는 사용자
Tech/WPF2009. 11. 12. 13:23
이전글 : [WPF 3D UI 구현하기 - 1]

우선 내가 WPF 3D를 이용하여 구현해보고 싶은 것은 앞면 뒷면 Panel 두 개를 만들어 버튼을 누르면 180도로 회전하여 뒤집기가 가능한 형태이다.



위와 같은 Panel 두 개를 만들어 놓았다고 가정했을 때, Front Panel에 우측 상단에 있는 노란색 버튼을 누르면 Front Panel이 180도 회전하면서 Back Panel이 뒤집어져 나와야 할 것이고, Back Panel 중앙에 있는 노란색 버튼을 누르면 반대로 180도 회전하면서 Front Panel이 뒤집어져 나와야 할 것이다.

자 이제 XAML 코드에서 Viewport3D 객체를 생성하고 카메라를 돌려보자!
이전에 두 종류의 Camera에 대해 말했을 것이다.
OrthographicCamera와 PerspectiveCamera가 있는데 그 둘의 차이를 쉽게 이해하기 위해 밑의 그림을 msdn에서 따왔다.




http://msdn.microsoft.com/ko-kr/library/system.windows.media.media3d.perspectivecamera.aspx

나는 PerspectiveCamera를 이용하도록 하겠다.

1
2
3
<Viewport3D.Camera>
    <PerspectiveCamera Position="0,0,4" />
</Viewport3D.Camera>

정면에서 비출 것이기 때문에 Position만 설정하였다.
Z축으로 물체로부터 4만큼 떨어져 있는 상태라고 보면 된다. 숫자가 작아질수록 물체에 근접한 상태라고 보면 된다.

이제 앞면 패널을 표현해보자.
패널에는 회전을 위한 버튼이 있기 때문에 Viewport2DVisual3D를 이용할 것이다.
Viewport2DVisual3D에서 설정해주면 되는 것은 Transform, Geometry, Material, Visual 4 가지이다.
코드 상에서만 확인을 하면 눈에 띄게 속성을 이해하기 어렵기 때문에 Blend를 열고 속성을 확인해보도록 하자.



Viewport2DVisual3D 객체의 속성을 살펴보면 위와 같은 모습을 볼 수 있다.
Transform, Geometry, Material, Visual ... 우리가 조작할 속성들이 고대로 보인다.


Transform에서는
1. 좌표 이동
2. 회전
3. 비율 크기 조정
4. 중심점
5. 대칭 이동
을 수정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<Viewport2DVisual3D.Transform>
    <Transform3DGroup>
        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
        <ScaleTransform3D ScaleX="1" ScaleY="2" ScaleZ="1"/>
        <RotateTransform3D d:EulerAngles="0,0,0">
            <RotateTransform3D.Rotation>
                <AxisAngleRotation3D Angle="0" Axis="0,1,0"/>
            </RotateTransform3D.Rotation>
        </RotateTransform3D>
        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
    </Transform3DGroup>
</Viewport2DVisual3D.Transform>

XAML상에서는 이런 식으로 표현할 수 있을 것이다.
중심점과 대칭 이동은 특정 용어로 표현되지 않는다. 하지만, Blend에서 확인을 해보면 쉽게 알 수 있다.

앞면 Panel은 Y축으로만 패널의 Scale을 2배로 조정했고, 회전을 시키지 않은채로 Y축으로 회전할 것임을 명시해뒀다.
굳이 ScaleY만을 2로 한 이유는 이 ScaleTransform은 비율로 계산되어 조절되기 때문이다.
즉 ScaleTransform을 (1,1,1)로 하면 바로 뒤에 설명이 나올 Gemetry에서 Y축 Position을 수정하지 않는 이상 1:1비율의 높이와 너비를 가진 정사각형 모양이 된다.
내가 원하는 형태의 앞면 Panel은 너비에 비해 높이가 2배이기 때문에 ScaleY를 2로 설정한 것이다.
만약 Geometry에서 지금의 ScaleTransform에서 ScaleY를 조작한 것처럼 높이를 2배로 설정하고 싶다면, Position에서 Y축에 관련된 좌표값을 2로 설정하면 된다.
그 외 나머지는 손대지 않았다.

Geometry는 대략 -ㅅ-) 세 개의 꼭지점을 정해주고 그 점들을 이어 만든 삼각형을 합쳐서 물체를 표현할 범위를 나타내준다고 생각하면 된다.
Geometry에서 조정할 수 있는 것들은 Positions, TextureCoordinates, TriangleIndices, Normals 들이 있다.
X, Y, Z축을 0,0,0으로 기준을 보았을 때, Positions에서 각 선을 이을 점들을 찍는다고 생각해야 한다.
Positions에서 정한 각 점들을 선으로  이어주는 순서를 정하는 것이 TriangleIndices이다.
그리고 TextureCoordinates가 2D의 좌표를 3D 좌표로 매핑해 준다.
예를 들어, 2D의 shape이 (0,0 0,1 1,0 1,1) 이런식으로 사각형 도형이 있다면 3D상으로 (-1,1,0 -1,1,0 1,-1,0 1,1,0)으로 변환될 수 있다는 말이다.

<Viewport2DVisual3D.Geometry>
    <MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0" TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0 1 2 0 2 3"/>
</Viewport2DVisual3D.Geometry>

0번째 점은 (-1,1,0) 이고 1번째 점은 (-1,-1,0), 2번째 점은 (1,-1,0), 3번째 점은 (1,1,0)이다.
0번째와 1번째와 2번째 점을 이어 삼각형을 만들고, 0번째와 2번째 3번째 점을 이어서 또 다른 삼각형을 만들면 두 삼각형이 합쳐서 사각형을 이루게 된다.
이제 앞면 패널이 보이게 될 영역이 확보가 되었다. ^ㅁ^)

남은 요소들인 Material, Visual, 중요한 조명을 담당할 Light는 다음으로 소개를 미루도록 하겠다.

슝~ ' ㅁ')/


Posted by 알 수 없는 사용자
Tech/WPF2009. 11. 11. 17:40


WPF는 Silverlight와는 3D 구현이 많이 다르다. Silverlight 에서는 Projection 속성을 이용하여 3D를 구현하는 반면에 WPF는 3차원 도형을 그리거나 모형을 만든 후에, 카메라의 위치와 시선을 조작하거나 그 이외의 각종 요소 등을 변경함으로 원하는 3D 효과를 얻어낸다. Silverlight 외의 3D 구현을 접한 경우가 없었기 때문에 이해하는데 조금 어려워었다.

WPF의 3D 구현은 마치 영화를 촬영하는 것과 느낌이 비슷하다.

우선 Viewport3D 객체를 만들고, Camera를 설정한다.
Viewport3D.Camera의  종류는 두 가지이다.
1. OrthographicCamera : 정사 방식, 거리와는 상관없이 동일한 크기로 물체가 보인다.
2. PerspectiveCamera : 투시 방식, 거리에 따라 물체가 원근감있게 보인다.

Camera 수정할 수 있는 속성
1. Position : 카메라의 위치
2. LookDirection : 카메라 시선
3. UpDirection : 카메라의 방향
4. Width / FieldOfView

자! 카메라는 준비했다.
그런데, 카메라가 있으면 뭐 하나? 주인공이 없는데 -ㅅ-);

귀하신 주인공님은 여러 가지 방법들(Model3D, Visual3D, Viewport2DVisual3D ... )로 표현할 수 있는데,
세부 사항을 제외하고 그 방법들의 큰 속성들은 같은 역할을 한다.
1. Transform : 위치 이동 및 회전
2. Geometry : 물체의 렌더링 결과물을 반영하는 범위를 설정할 수 있다.
3. Material : 카메라에서 물체에 반사시킬 색상과 형태를 설정할 수 있다.
4. Visual : 보여줄 물체의 정보

Model3D는 단순 이미지나 도형들은 이용할 경우에는 괜찮지만, 사용자와의 피드백이 불가능하다.
한 마디로 버튼을 Model3D로 만들었으면, 버튼 클릭을 할 수 없단 얘기다.
때문에 UIElement들 중 사용자와의 상호작용이 필요한 아이들이 있는 경우에는 Viewport2DVisual3D를 사용하길 바란다.

여기까지 다 설정을 완료하였다면, 카메라와 주인공까지 준비된 것이다.
다 된 것 같겠지만, 실제론 그렇지 않다.
바로! ... 조명이 빠졌다 =ㅁ=);

주인공님을 비춰줄 조명이 없으면 그대는 시커먼 물체와 맞닥뜨릴 수 밖에 없을 것이다.
진상이라고 짜증내지 말기를 바란다. 조명(Light)도 입맛따라 선택할 수 있다.
1. DirectionalLight : 평행 방향을 빛을 뿌린다.
2. PointLight : 하나의 포인트로부터 모든 방향으로 일정하게 빛을 뿌린다.
3. SpotLight : 지정된 포인트로부터 지정된 방향으로 빛을 뿌린다.
4. AmbientLight : 모든 면에 빛을 뿌린다.

이제 조명까지 완성되면 -ㅁ-) 주인공님이 쨔잔~! 하고 등장할 것이다.
우와아아아아아아아아아앙~ +ㅍ+)/ 으히히히히히 ... (...)

여기까지 기본내용이고, 실제 XAML에 쓰여지는 코드는 다음 기회로 미루도록 하겠다.
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 10. 28. 01:25
요즘 HLSL을 가지고 Pixel Shader를 만들고 있다. 따라서 여기서 얘기하는 경험은 HLSL로 된 *.fx 파일을 컴파일 할 때 적용되는 얘기이다. 셰이더 어셈블리 명령을 직접 써서 만드는 일은 전혀 해보지 않아서 얼마나 관련성이 있을지 모르겠다.

Silverlight 3와 WPF(.NET 3.5 SP1)에서는 Shader Model 2의 Pixel Shader(ps_2_0)를 지원한다.

Pixel Shader 2.0에서는 64개의 산술 instruction만을 사용할 수 있다. 문제는 64개를 넘어서 컴파일이 안 될 때만 인스트럭션 개수를 알려준다는 것. 기본적인 사용법만 배운 상태에서 한참 만들다가 "님, 인스트럭션 개수 초과했어염. 65개임."하는 에러 메시지를 받았을 때 어찌나 황당하던지.

인스트럭션 개수를 알 수 있는 방법을 찾아 헤매다가 발견한 것이 셰이더 어셈블리 파일을 만들어 내는 옵션이다. *.fx 파일을 fxc.exe로 컴파일할 때 /Fc 옵션을 사용하면 어셈블리 파일을 출력해준다. 여기에는 컴파일 결과물의 인스트럭션 개수가 표시되기 때문에 작업할 때 아주 유용하다. 만세! 인스트럭션 개수를 알 수 있는 다른 방법은 아직 찾지 못했다.

인스트럭션 개수를 알 수 있는 방법이 생기니 인스트럭션 개수 줄이는 삽질도 이제 좀 할 맛이 난다. 경험상 현재까지 작업중에 인스트럭션 줄이는데 제일 도움이 되는 것은 똑같은 산술 연산을 벡터 연산 하나로 합치는 거였다.

가령 이런 코드보다
float c1 = Const1 - color.r;
float c2 = Const2 - color.g;
float c3 = Const3 - color.b;
이런 코드의 인스트럭션 개수가 적었다.
float4 c4 = {Const1, Const2, Const3, 0.0f};
float4 c = c4 - color;

 

'Tech > Silverlight' 카테고리의 다른 글

Commands in Silverlight with SLExtensions - 2  (0) 2010.01.01
Commands in Silverlight with SLExtensions - 1  (0) 2009.12.26
[Element Binding]  (0) 2009.10.12
[Blend 3 Element Binding]  (0) 2009.10.12
Posted by wafe
Tech/Silverlight2009. 10. 12. 17:54

Blend 3에서 너무 쉽게 썼던 Element Binding~ 소스 코드 상에선 어떻게 쓰일까요?

이번엔 소스코드 상에서의 Element Binding을 짤막하고 간단하게 구현한 예를 들어보겠습니다.

일단 원하는 동작 내용은 ListBox에서 선택된 Item이 가지고 있는 이미지 정보에 따라 배경 이미지가 변하는 것입니다. Element Binding을 하기 위헤서 필요한 정보는 세 가지 입니다.

1. Element Binding할 FrameworkElement 개체
2. 그리고 그 개체에 관하여 Binding 할 속성 = Dependancy Property
3. Binding Mode

1
2
3
4
5
Binding bImg = new Binding("SelectedItem.Children[1].Source");
bImg.ElementName = "imgList";
bImg.Mode = BindingMode.TwoWay;
bColor.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
background.SetBinding(Image.SourceProperty, bImg);

우선 Binding 객체를 새
Binding할 속성의 주소를 주어 새로이 생성하고, ElementName에 imgList라는 이름의 ListBox의 이름을 부여함으로써 Binding할 개체라는 것을 알려줍니다.
Binding Mode는 TwoWay로 설정하고 UpdateTiming은 Expicit로 설정했습니다.
그 후에, SetBinding()를 이용하여 해당 객체의 속성과 연결 시켜줍니다. 원하는 것은 background 이미지의 sourcr속성과 연결시키는 것이기 때문에 Image.SourceProperty와 bImg를 바인딩 시켰습니다.

이걸로 뚝딱 Element Binding을 소스코드 상에서 구현하는 방법을 해치웠습니다!

' ㅅ')/ 참 쉽죠잉~.


'Tech > Silverlight' 카테고리의 다른 글

Commands in Silverlight with SLExtensions - 1  (0) 2009.12.26
Silverlight Pixel Shader 개발 팁  (0) 2009.10.28
[Blend 3 Element Binding]  (0) 2009.10.12
[SketchFlow를 만들자 2]  (0) 2009.10.09
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 10. 12. 15:59

자, 이제 Element Binding 사용법에 대해서 알아봅시다!

Element Binding은 FrameworkElement객체의 속성끼리 Binding을 시키는 방법인데요.
Binding하는 개체가 FrameworkElement여야 한다는 것이 제약점입니다.

우선 Blend 3에서 아주 간편하게 Element Binding을 하는 방법을 알아보겠습니다.



위와 같이 Background Image라는 타이틀을 갖고 각종 이미지들을 담고 있는 ListBox를 만들었습니다.

이 ListBox를 이용하여 수행하도록 만들고 싶은 동작은 ListBox에 있는 Item을 선택할 때, 선택된 Item에 따라 배경 이미지가 바뀌는 것입니다.



ListBox의 Properties로 가서 Source에 우측 조그만 사각형 박스를 클릭하여 Data Binding을 클릭하면,
(Data Binding이 되어 있으면 노란색으로 표시가 됩니다)



1. Data Field, Element Property, Explicit Data Context중에서 Element Property로 들어갑니다.
2. 제가 원하는 건 이미지 정보를 담고 있는 ListBox와 연결을 시키는 것이기 때문에 scene elements에서 "imgList"를 선택합니다.
3. scene elements에서 선택한 개체와 관련된 상세한 속성들이 우측 Properties목록에 좌르르륵~ 나오게 되는데요, 이중에 원하는 정보가 있으면 그대로 연결하면 됩니다. 하지만 제가 원하는 속성은 이 곳에 명시되어 있지 않습니다. 제가 원하는 속성은 ListBox에서 선택된 Item의 이미지 정보니까요.
4. Use a custom path expression을 체크하고, SelectedItem.Children[1].Source라고 적어준 후에 Binding direction을 'TwoWay'로 설정해 줍니다.

이제 OK버튼만 누르면 끝!

이렇게 만들어진 Element Binding은 xaml상에서 어떻게 쓰여져 있을까요?

Source="{Binding SelectedItem.Children[1].Source, ElementName=imgList, Mode=TwoWay, UpdateSourceTrigger=Explicit}"

Binding된 속성, FrameworkElement 객체, Binding Mode 등의 정보들이 그대로 설정한 것과 똑같이 쓰여져 있습니다.



1번 이미지를 클릭한 것이 보이시죠?  ^ㅁ^)/

참 쉽죠잉~ ' ㅍ')~

'Tech > Silverlight' 카테고리의 다른 글

Silverlight Pixel Shader 개발 팁  (0) 2009.10.28
[Element Binding]  (0) 2009.10.12
[SketchFlow를 만들자 2]  (0) 2009.10.09
[Blend에서 Behvaior 사용해보기]  (0) 2009.10.09
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 10. 9. 16:59

 
직접 SketchFlow를 만들어 보았습니다.
ImageSlidePlayer라는 프로그램을 프로토타이핑하기 위해 만들었는데요, 실제 ImageSlidePlayer라는 프로그램은 이미 만들어 두었고, SketchFlow는 실제 체험해 보기 위해 만들었습니다.

SketchFlow는 왜 사용하는가 ?
  - 실제 만들어질 프로그램의 UI와 기능과 흡사하게 만들 수 있다.
  - 실제 구현에 들어가기 전에 발표를 하고 시연을 하여 피드백을 판서로 기록하여 요구사항에 가깝게 SketchFlow를 수정할수록 요구사항들을 충족시키는 프로그램을 만들 수 있게 된다.
  - 구현할 프로그램의 기능들과 흡사하게 만들기 때문에 시연을 함으로써 각 기능들에 대한 이해와 필요성을 상대방에게 알리기 용이하다.
  - 실제 프로그램에 쓰일 각종 Control들과 Panel의 이름과 위치를 정하기 때문에 프로그램 구현에 들어가게 되면 디자이너와 개발자들은 SketchFlow 프로젝트에 쓰인 이름과 배치에 쓰인 정보들을 이용하면 된다.
  - Blend 3와 똑같이 사용할 수 있다.
  - MS Word문서로 내보내기 기능이 있어서 쉽게 보고서 형태로 작성할 수 있다.
  - 포토샵과 일러스트레이터의 프로젝트 파일과 연동이 된다.

ImageSlidePlayer?
  - Image를 큐브 모양으로 만들어서 회전 시키며 보여주는 Player입니다.

ImageSlidePlayer의 SketchFlow Map을 보면 보여질 화면이 두 개 뿐이라서 Screen이 두 개입니다. 참 썰렁하죠;



<SketchFlow Map>



<ImageSlidePlayer & ImageViewerOption>


ImageSlidePlayer에는 이미지들을 회전시키며 보여주는 ImageSlideViewer와 ImageSlideViewer의 size와 ImageViewerOption 의 배경 이미지와 색을 설정할 수 있는 ImageViewerOption이 있습니다.
SketchFlow에서는 종속되어있는 Screen의 Children에 대한 정보를 얻을 수가 없어 굉장히 많이 어려웠습니다.
(아예 안되는 것은 아니지만, 소스 코드를 만져야 하는 일이기 때문에 SketchFlow 내에서 수행 가능한 한도로 작업을 변경했습니다.)

ImageSlidePlayer SketchFlow의 동작구조

1. ImageSlidePlayer
  - 윗쪽 버튼 : [NavigateToScreen] Behavior를 이용하여 ImageViewerOption screen으로 이동
* [NavigateToScreen] Behavior란 ? 다른 Screen으로 이동 시켜준다.

  - 아랫쪽 버튼 : [ChangeRotation] Behavior를 이용하여 Player가 위로 뒤집히면서 ImageViewerOption이 등장
  - 왼쪽 버튼 : [ChangeRotation] Behavior를 이용하여 ImageViewer의 이미지들이 왼쪽으로 90도씩 회전
  - 오른쪽 버튼 : [ChangeRotation] Behavior를 이용하여 ImageViewer의 이미지들이 오른쪽으로 -90도씩 회전

2. ImageViewerOption
  - Ok 버튼 : Width, Height를 입력하고 Ok버튼을 누르면 ImageSlideViewer의 size가 변경되며, [NavigateToScreen] Behavior를 이용하여 ImageSlidePlayer screen으로 이동
* Blend 상에서 Player로의 접근의 불가하여 실제 변경은 불가하다.

  - Background Image 리스트 박스 : Element Binding을 통해 Item을 선택하면 해당 Item의 이미지가 ImageViewerOption와 ImageSlidePlayer의 배경 이미지로 변경
* Blend 상에서 Player로의 접근의 불가하여 실제 변경은 불가하다.
* Background Image 리스트 박스의 내용을 Sample Data  Source를 생성하여 채우려고 했지만, Sample Data Source의 내용에 접근하여 Element Binding을 할 수 있는 방법이 없어서 포기하고 Item들을 직접 StackPanel로 만들어서 채웠다.

  - Color 콤보 박스 : Element Binding을 통해 Item을 선택하면 해당 Item의 배경 색이 ImageViewerOption와 ImageSlidePlayer의 배경 색으로 변경
* Blend 상에서 Player로의 접근의 불가하여 실제 변경은 불가하다.

  - 아랫쪽 버튼 : [NavigateToScreen] Behavior를 이용하여 ImageSlidePlayer screen으로 이동

SketchFlow의 단점 ?
  - 사용자가 SketchFlow를 사용할 수 있는 수준이어야 한다.
* 적어도 각종 Control에 대한 지식이 있어야 하며, Blend 3 사용 경험자일 수록 쉽다.
  - SketchFlow Project를 그대로 실제 프로젝트에 대입하거나 재활용할 수 없다.
* SketchFlow에서 쓰이는 클래스의 type은 Screen이며, 이 type은 SketchFlow 전용이다.
  - 구현할 프로그램의 모든 기능을 SketchFlow내에서만 실현시키기엔 어느 정도의 한계가 있다.


SketchFlow에서 부딪히는 문제들 때문에 삽질을 많이했던 것 같은데요, 중간중간 MVVM/Command Pattern, Behavior, Element Binding 등도 같이 접하면서 공부할 수 있는 기회들이 있어서 좋았습니다.
아직 SketchFlow에서 state와 SketchFlowAnimation을 이용하는 방법을 알지 못해서 좀 아쉽습니다.

아직 공부하지 못한 것은 픽셀 셰이더 이펙트입니다.

이상 박경민이었습니다! -ㅁ-)/



참고하면 좋은 사이트 -
http://www.uxfactory.com/752
[Expression Blend 3] 스케치 플로우(SketchFlow), 어떻게 사용할까? - 1
[Expression Blend 3] 스케치 플로우(SketchFlow), 어떻게 사용할까? - 2
[Expression Blend 3] 스케치 플로우(SketchFlow), 어떻게 사용할까? - 3


'Tech > Silverlight' 카테고리의 다른 글

[Element Binding]  (0) 2009.10.12
[Blend 3 Element Binding]  (0) 2009.10.12
[Blend에서 Behvaior 사용해보기]  (0) 2009.10.09
[Sketch Flow를 만들자]  (0) 2009.10.06
Posted by 알 수 없는 사용자