다음을 통해 공유


3D 변환 개요

이 항목에서는 Windows Presentation Foundation(WPF) 그래픽 시스템에서 3D 모델에 변환을 적용하는 방법을 설명합니다. 변환을 사용하면 개발자가 해당 항목을 정의하는 기준 값을 변경하지 않고도 모델의 위치, 크기 및 방향을 변경할 수 있습니다.

3D 좌표 공간

Windows Presentation Foundation(WPF)의 3D 그래픽 콘텐츠는 2차원 요소 구조에 참여할 수 있는 요소인 Viewport3D에 캡슐화됩니다. 이 그래픽 시스템은 Windows Presentation Foundation(WPF)에서 다른 여러 요소처럼 2차원 시각 요소로 Viewport3D를 처리합니다. Viewport3D는 3차원 장면을 보여 주는 창(뷰포트)으로 작동합니다. 정확히 말해 이는 3D 장면이 프로젝션되는 표면입니다. 동일한 장면 그래프에서 Viewport3D를 다른 2D 그리기 개체와 함께 사용할 수 있지만 Viewport3D 내에서 2D 및 3D 개체가 상호 침투할 수 없습니다. 다음에서 설명하는 좌표 공간은 Viewport3D 요소에 의해 포함됩니다.

2D 그래픽의 Windows Presentation Foundation(WPF) 좌표계는 렌더링 표면(일반적으로 화면)의 왼쪽 위에서 원점을 찾습니다. 2D 시스템에서는 양의 x-축 값은 오른쪽으로 진행되고 양의 y-축 값은 아래로 진행됩니다. 그러나 3D 좌표계에서는 원점이 화면의 중앙에 있습니다. 여기서 양의 x-축 값은 오른쪽으로 진행되고 양의 y-축 값은 위로 진행되며 양의 z-축 값은 원점에서 뷰어를 향해 바깥쪽으로 진행됩니다.

좌표계
좌표계 비교

이러한 축으로 정의되는 공간은 Windows Presentation Foundation(WPF)의 3D 개체에 대한 고정 참조 프레임입니다. 이 공간에서 모델을 빌드하고 이를 보기 위한 광원과 카메라를 만들 때는 변환 적용 시 각 모델에 대해 만드는 로컬 참조 프레임을 이 고정 참조 프레임 또는 "월드 공간"과 구분하면 유용합니다. 또한 월드 공간의 개체는 광원 및 카메라 설정에 따라 완전히 다르게 보이거나 전혀 보이지 않을 수 있지만 카메라의 위치는 월드 공간에서 개체의 위치를 변경하지 않습니다.

모델 변환

모델을 만들 때 모델에는 장면에서의 특정 위치가 지정됩니다. 장면에서 이러한 모델을 이동하거나, 회전하거나, 크기를 변경하기 위해 모델 자체를 정의하는 꼭짓점을 변경하는 것은 비효율적입니다. 대신 2D에서와 같이 모델에 변환을 적용합니다.

각 모델 개체에는 모델을 옮기거나, 방향이나 크기를 바꿀 수 있는 Transform 속성이 있습니다. 변환을 적용할 때는 변환에 의해 지정된 벡터 또는 값이 무엇이든 실제적으로 모델의 모든 점을 오프셋합니다. 즉, 모델이 정의된 좌표 공간("모델 공간")은 변환하지만 장면 전체("월드 공간")의 좌표계에서 모델의 기하 도형을 구성하는 값은 변경하지 않습니다.

좌표 이동 변환

3D 변환은 추상 기본 클래스 Transform3D에서 상속됩니다. 여기에는 아핀 변환 클래스 TranslateTransform3D, ScaleTransform3D, RotateTransform3D가 포함됩니다. Windows Presentation Foundation(WPF) 3D 시스템은 더 간결한 행렬 연산으로 동일한 변환을 지정하는 데 사용할 수 있는 MatrixTransform3D 클래스도 제공합니다.

TranslateTransform3D는 Model3D의 모든 포인트를 OffsetX, OffsetY, OffsetZ 속성으로 지정하는 오프셋 벡터 방향으로 옮깁니다. 예를 들어 큐브의 꼭짓점 하나가 (2,2,2)에 있고 오프셋 벡터가 (0,1.6,1)인 경우 해당 꼭짓점 (2,2,2)가 (2,3.6,3)으로 이동합니다. 모델 공간에서 큐브의 꼭짓점은 계속 (2,2,2)이지만 이제 모델 공간의 (2,2,2)가 월드 공간의 (2,3.6,3)이 되도록 모델 공간과 월드 공간의 관계가 변경되었습니다.

좌표 이동 그림
오프셋을 사용한 좌표 이동

다음 코드 예제에서는 좌표 이동을 적용하는 방법을 보여 줍니다.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <DockPanel>
    <Viewbox>
      <Canvas Width="600" Height="201">

        <!-- The Viewport3D provides a rendering surface for 3-D visual content. -->
        <Viewport3D Name="MyAnimatedObject"
          ClipToBounds="True" Width="600" Height="150"
          Canvas.Left="0" Canvas.Top="10">

          <!-- Defines the camera used to view the 3D object. -->
          <Viewport3D.Camera>
            <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" 
             FieldOfView="60" />
          </Viewport3D.Camera>

          <!-- The ModelVisual3D children contain the 3D models -->
          <Viewport3D.Children>

            <!-- This ModelVisual3D defines the light cast in the scene. Without light, the
                 3D object cannot be seen. -->
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
              </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <GeometryModel3D>

                  <!-- The geometry specifes the shape of the 3D plane. In this case, a flat sheet is created. -->
                  <GeometryModel3D.Geometry>
                    <MeshGeometry3D
                     TriangleIndices="0,1,2 3,4,5 "
                     Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
                     TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "
                     Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " />
                  </GeometryModel3D.Geometry>

                  <!-- The material specifies the material applied to the plane. In this case it is a linear gradient.-->
                  <GeometryModel3D.Material>
                    <MaterialGroup>
                      <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                          <SolidColorBrush Color="Cyan" Opacity="0.3"/>
                        </DiffuseMaterial.Brush>
                      </DiffuseMaterial>
                    </MaterialGroup>
                  </GeometryModel3D.Material>
                  <!-- The Transform specifies how to transform the 3D object. The OffsetX property is animated
                       in the Storyboard below. -->
                  <GeometryModel3D.Transform>
                    <TranslateTransform3D x:Name="myTranslateTransform3D" OffsetX="0" OffsetY="0" OffsetZ="0" />
                  </GeometryModel3D.Transform>
                </GeometryModel3D>
              </ModelVisual3D.Content>
            </ModelVisual3D>
          </Viewport3D.Children>
          <!-- Trigger the TranslateTransform3D animation when the 3D object loads. -->
          <Viewport3D.Triggers>
            <EventTrigger RoutedEvent="Viewport3D.Loaded">
              <BeginStoryboard>
                <Storyboard>

                  <!-- This animation animates the OffsetX property of the TranslateTransform3D. -->
                  <DoubleAnimation
                   Storyboard.TargetName="myTranslateTransform3D" 
                   Storyboard.TargetProperty="OffsetX" 
                   To="-0.8" 
                   AutoReverse="True" RepeatBehavior="Forever" />

                  <!-- If you want to animate OffsetY and/or OffsetZ, create similar DoubleAnimations
                       respectively. -->

                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Viewport3D.Triggers>
        </Viewport3D>
      </Canvas>
    </Viewbox>
  </DockPanel>
</Page>

배율 변환

ScaleTransform3D는 중심점을 기준으로 지정한 배율 벡터에 따라 모델의 배율을 변경합니다. X, Y 및 Z축에서 모델의 배율을 같은 값으로 조정하는 균일한 배율을 지정하면 모델의 크기를 비례적으로 변경할 수 있습니다. 예를 들어, 변환의 ScaleX, ScaleY, ScaleZ 속성을 0.5로 설정하면 모델의 크기가 절반이 되고, 2로 설정하면 3개 축 모두 배율이 두 배가 됩니다.

Uniform ScaleTransform3D
ScaleVector 예제

균일하지 않은 배율 변환(X, Y 및 Z 값이 모두 같지 않은 배율 변환)을 지정하면 다른 모델에 영향을 주지 않으면서 모델을 1차원 또는 2차원에서 늘리거나 줄일 수 있습니다. 예를 들어, ScaleX를 1로, ScaleY를 2로, ScaleZ를 1로 설정하면 변환 모델의 높이가 두 배가 되지만 X 및 Z 축은 달라지지 않을 것입니다.

기본적으로 ScaleTransform3D에서는 꼭짓점이 원점 (0,0,0)을 기준으로 확장 또는 축소됩니다. 그러나 변환하려는 모델이 원본에서 그려지지 않은 경우 원본에서 모델 배율을 조정해도 모델의 크기가 "원본 위치"로 조정되지 않습니다. 대신 모델의 꼭짓점에 배율 벡터를 곱하면 배율 연산으로 모델이 변환되고 배율도 조정되는 효과가 납니다.

중심점이 지정되어 배율 조정된 세 개의 큐브
ScaleCenter 예제

모델 배율을 "원본 위치"로 조정하려면 ScaleTransform3D의 CenterX, CenterY, CenterZ 속성을 설정하여 모델 중심을 지정합니다. 이렇게 하면 그래픽 시스템에서는 모델 공간의 배율을 조정한 다음 지정한 Point3D의 중심으로 모델을 좌표 이동합니다. 반대로 모델을 원점을 기준으로 빌드한 경우 다른 중심점을 지정하면 모델이 원점에서 먼 쪽으로 좌표 이동합니다.

회전 변환

3D에서 모델을 여러 방법으로 회전할 수 있습니다. 일반적인 회전 변환에서는 축과 해당 축을 기준으로 하는 회전 각도를 지정합니다. RotateTransform3D 클래스를 사용하면 해당 Rotation 속성을 사용하여 Rotation3D를 정의할 수 있습니다. 그런 다음 Rotation3D에서 AxisAngle 속성을 지정하여(이 경우는 AxisAngleRotation3D) 변환을 정의합니다. 다음 예제에서는 모델을 Y축을 기준으로 60도 회전시킵니다.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <DockPanel>
    <Viewbox>
      <Canvas Width="321" Height="201">

        <!-- The Viewport3D provides a rendering surface for 3-D visual content. -->
        <Viewport3D Name="MyAnimatedObject"
          ClipToBounds="True" Width="150" Height="150"
          Canvas.Left="0" Canvas.Top="10">

          <!-- Defines the camera used to view the 3D object. -->
          <Viewport3D.Camera>
            <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" 
             FieldOfView="60" />
          </Viewport3D.Camera>

          <!-- The ModelVisual3D children contain the 3D models -->
          <Viewport3D.Children>

            <!-- Two ModelVisual3D define the lights cast in the scene. Without light, the
                 3D object cannot be seen. Also, the direction of the lights affect shadowing. -->
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
              </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <DirectionalLight Color="#FFFFFF" Direction="0.612372,-0.5,-0.612372" />
              </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
              <ModelVisual3D.Content>
                <GeometryModel3D>

                  <!-- The geometry specifes the shape of the 3D plane. In this case, a flat sheet is created. -->
                  <GeometryModel3D.Geometry>
                    <MeshGeometry3D
                     TriangleIndices="0,1,2 3,4,5 "
                     Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
                     TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "
                     Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " />
                  </GeometryModel3D.Geometry>

                  <!-- The material specifies the material applied to the plane. In this case it is a linear gradient.-->
                  <GeometryModel3D.Material>
                    <MaterialGroup>
                      <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                          <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                            <LinearGradientBrush.GradientStops>
                              <GradientStop Color="Yellow" Offset="0" />
                              <GradientStop Color="Red" Offset="0.25" />
                              <GradientStop Color="Blue" Offset="0.75" />
                              <GradientStop Color="LimeGreen" Offset="1" />
                            </LinearGradientBrush.GradientStops>
                          </LinearGradientBrush>
                        </DiffuseMaterial.Brush>
                      </DiffuseMaterial>
                    </MaterialGroup>
                  </GeometryModel3D.Material>

                  <!-- The Transform specifies how to transform the 3D object. The properties of the
                        Rotation object are animated causing the 3D object to rotate and "wobble" (see Storyboard below).-->
                  <GeometryModel3D.Transform>
                    <RotateTransform3D>
                      <RotateTransform3D.Rotation>
                        <AxisAngleRotation3D x:Name="myAngleRotation" Axis="0,3,0" Angle="40" />
                      </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                  </GeometryModel3D.Transform>
                </GeometryModel3D>
              </ModelVisual3D.Content>
            </ModelVisual3D>
          </Viewport3D.Children>

          <!-- Trigger the rotation animation when the 3D object loads. -->
          <Viewport3D.Triggers>
            <EventTrigger RoutedEvent="Viewport3D.Loaded">
              <BeginStoryboard>
                <Storyboard>

                  <!-- This animation animates the Angle property of the AxisAngleRotation3D
                       making the 3D object rotate from -60 degrees to 60 degrees. -->
                  <DoubleAnimation 
                   Storyboard.TargetName="myAngleRotation" 
                   Storyboard.TargetProperty="Angle" 
                   From="-60" To="60" Duration="0:0:4" AutoReverse="True"  RepeatBehavior="Forever"/>

                  <!-- This animation animates the Axis property of the AxisAngleRotation3D
                       making the 3D wobble as it rotates. -->
                  <Vector3DAnimation 
                   Storyboard.TargetName="myAngleRotation" 
                   Storyboard.TargetProperty="Axis" 
                   From="0,3,0" To="1,0,1" Duration="0:0:4" AutoReverse="True"  RepeatBehavior="Forever"/>

                </Storyboard>
              </BeginStoryboard>
            </EventTrigger>
          </Viewport3D.Triggers>
        </Viewport3D>
      </Canvas>

    </Viewbox>
  </DockPanel>
</Page>

참고: Windows Presentation Foundation(WPF) 3D는 오른손 시스템입니다. 즉, 회전 각도 값이 양이면 축을 중심으로 시계 반대 방향으로 회전됩니다.

축-각 회전은 RotateTransform3에서 CenterX, CenterY, CenterZ 속성에 값이 지정되지 않은 경우에 원본을 중심으로 회전하는 것입니다. 배율 조정과 마찬가지로 회전도 모델의 전체 좌표 공간을 변환한다는 점에 유의합니다. 모델이 원점을 기준으로 만들어지지 않았거나 이전에 모델을 좌표 이동한 경우 회전시키면 현재 위치에서 회전되는 것이 아니라 원점을 기준으로 "피벗"할 수 있습니다.

새 중심점으로 회전
새 중심을 지정하여 회전

모델을 "현재 위치"에서 회전시키려면 모델의 실제 중심을 회전 중심으로 지정합니다. 기하 도형은 일반적으로 원점을 기준으로 모델링되므로 먼저 모델의 크기를 조정하고(배율 조정) 방향을 설정한 다음(회전) 마지막으로 원하는 위치로 이동하면(좌표 이동) 대부분의 경우 예상한 일련의 변환 결과를 얻을 수 있습니다.

x- 및 y-축에서 60도 회전
회전 예제

축-각도 회전은 정적 변환 및 일부 애니메이션에서 잘 작동합니다. 그러나 큐브 모델을 X축을 기준으로 60도 회전시킨 다음 Z축을 기준으로 45도 회전시키는 경우를 가정합니다. 이 변환은 두 개의 개별 유사 변환 또는 행렬로 설명할 수 있습니다. 그러나 이 방식으로 정의한 회전에 애니메이션 효과를 원활하게 적용하기가 어려울 수 있습니다. 어느 방법을 사용하든 모델의 시작 및 끝 위치는 동일하게 계산되지만 모델이 이동하는 중간 위치는 확실하게 계산되지 않습니다. 쿼터니언은 회전의 시작 및 끝 사이의 보간을 계산하는 다른 방법을 나타냅니다.

사원수는 3D 공간의 축 그리고 해당 축을 기준으로 하는 회전을 나타냅니다. 예를 들어 쿼터니언은 (1,1,2) 축과 50도 회전을 나타낼 수 있습니다. 회전을 정의할 때 쿼터니언을 사용하면 컴퍼지션과 보간이라는 두 가지 작업을 수행할 수 있는 이점이 있습니다. 기하 도형에 적용된 쿼터니언 두 개의 컴퍼지션은 "axis2를 중심으로 기하 도형을 rotation2만큼 회전한 다음 axis1을 중심으로 rotation1만큼 회전하는 것"을 의미합니다. 컴퍼지션으로 기하 도형의 두 회전을 결합하여 결과를 나타내는 단일 쿼터니언을 가져올 수 있습니다. 쿼터니언 보간은 한 축 및 방향에서 다른 축 및 방향으로 부드럽고 합리적인 경로를 계산할 수 있으므로 원본에서 구성된 쿼터니언으로 보간하여 한 위치에서 다른 위치로 부드럽게 전환하여 변환에 애니메이션 효과를 줄 수 있습니다. 애니메이션할 모델의 경우 Rotation 속성에 QuaternionRotation3D를 사용하여 회전할 대상 Quaternion를 지정할 수 있습니다.

변환 컬렉션 사용

장면을 빌드할 때 일반적으로 둘 이상의 변환을 모델에 적용합니다. Transform3DGroup 클래스의 Children 컬렉션에 변환을 추가하여 장면에 있는 다양한 모델에 적용할 변환을 간편하게 분류합니다. 여러 다른 그룹에서 변환을 다시 사용하면 편리한 경우가 많으며, 대부분의 경우 각 인스턴스에 여러 변환 집합을 적용하여 모델을 다시 사용할 수 있습니다. 컬렉션에 변환을 추가하는 순서는 중요합니다. 컬렉션의 변환은 추가한 순서대로 적용됩니다.

변환에 애니메이션 효과 주기

WPF(Windows Presentation Foundation) 3D 구현은 2D 그래픽과 동일한 타이밍 및 애니메이션 시스템에 참여합니다. 즉, 3D 장면에 애니메이션 효과를 주려면 해당 모델의 속성에 애니메이션 효과를 줍니다. 기본 형식의 속성에 직접 애니메이션 효과를 줄 수도 있지만 일반적으로 모델의 위치나 모양을 변경하는 변환에 애니메이션 효과를 주는 것이 보다 쉽습니다. 변환은 개별 모델뿐만 아니라 Model3DGroup 개체에도 적용될 수 있으므로 Model3Dgroup의 자식에 한 애니메이션 집합을 적용하고 개체 그룹에는 또 다른 애니메이션 집합을 적용할 수 있습니다. Windows Presentation Foundation(WPF) 타이밍 및 애니메이션 시스템에 대한 배경 정보는 애니메이션 개요Storyboard 개요를 참조하세요.

Windows Presentation Foundation(WPF)에서 개체에 애니메이션 효과를 주려면 타임라인을 만들고 애니메이션(시간이 지남에 따른 일부 속성 값의 변경)을 정의한 다음 애니메이션을 적용할 속성을 지정합니다. 이 속성은 FrameworkElement의 속성이어야 합니다. 3D 장면의 모든 개체는 Viewport3D의 자식이므로 장면에 적용하려는 모든 애니메이션에 사용되는 속성은 Viewport3D의 속성입니다. 구문이 너무 길어질 수 있으므로 애니메이션의 속성 경로를 주의해서 처리해야 합니다.

개체를 현재 위치에서 회전시킬 뿐 아니라 진동 동작을 적용하여 볼 개체의 더 많은 부분을 노출하려 한다고 가정합니다. 모델에 RotateTransform3D를 적용하고 한 벡터에서 다른 벡터로 회전 축에 애니메이션 효과를 주도록 선택할 수 있습니다. 다음 코드 예제에서는 RotateTransform3D가 TransformGroup이 있는 모델에 적용된 여러 변환 중 하나라는 가정 하에 변환의 Rotation3D에 대한 Axis 속성에 Vector3DAnimation을 적용하는 방법을 보여 줍니다.

//Define a rotation
RotateTransform3D myRotateTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 1));
'Define a rotation
Dim myRotateTransform As New RotateTransform3D(New AxisAngleRotation3D(New Vector3D(0, 1, 0), 1))
Vector3DAnimation myVectorAnimation = new Vector3DAnimation(new Vector3D(-1, -1, -1), new Duration(TimeSpan.FromMilliseconds(5000)));
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever;
Dim myVectorAnimation As New Vector3DAnimation(New Vector3D(-1, -1, -1), New Duration(TimeSpan.FromMilliseconds(5000)))
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever

다른 변환 속성을 대상으로 비슷한 구문을 사용하여 개체를 이동하거나 배율 조정할 수 있습니다. 예를 들어, 배율 변환의 ScaleCenter 속성에 Point3DAnimation을 적용하여 모델의 모양을 부드럽게 비틀 수 있습니다.

앞의 예제에서는 GeometryModel3D의 속성을 변환하지만 장면의 다른 모델에 대한 속성도 변환할 수 있습니다. 예를 들어 Light 개체에 적용된 변환에 애니메이션 효과를 주면 이동하는 명암 효과를 만들어 모델의 모양을 인상 깊게 변경할 수 있습니다.

카메라도 모델이므로 카메라 속성 또한 변환할 수 있습니다. 카메라 위치나 평면 거리를 변환하면 결과적으로 전체 장면 프로젝션을 변환하여 장면의 모양을 확실히 변경할 수 있지만 이와 같은 방법으로 얻는 효과 대부분은 장면에서 모델의 위치에 적용하는 변환만큼의 "시각적" 효과를 만들 수 없습니다.

참고 항목