Обзор трехмерной графики

Обновлен: Ноябрь 2007

В этом разделе приведен обзор функциональных возможностей трехмерный в графической системе Windows Presentation Foundation (WPF). Реализация трехмерный в приложении WPF позволяет разработчикам осуществлять рисование, преобразование и анимацию трехмерной графики, как в разметке, так и в процедурном коде, используя предоставляемые платформой возможности двумерной графики. Разработчики могут сочетать графику двухмерный и трехмерный для создания многофункциональных элементов управления, предоставления сложных отображений данных или расширения возможностей взаимодействия пользователей с интерфейсом приложения. Поддержка трехмерный в приложении WPF не предназначена для использования в качестве полнофункциональной платформы разработки игр.

В этом разделе содержатся следующие подразделы.

  • 3-D в контейнере 2-D

  • Координаты трехмерного пространства

  • Камеры и проекции

  • Примитивы модели и сетки

  • Применение материалов к модели

  • Освещение сцены

  • Преобразование моделей

  • Анимация моделей

  • Добавление трехмерного содержимого к окну

  • См. также

3-D в контейнере 2-D

Графическое содержимое трехмерный в приложении WPF инкапсулировано в элементе Viewport3D, который может участвовать в структуре двумерного элемента. Графическая система рассматривает объект Viewport3D как двумерный визуальный элемент в ряду других элементов приложения WPF. Объект Viewport3D функционирует как окно — окно просмотра — на трехмерной сцене. Говоря точнее, это поверхность, на которую проецируется сцена трехмерный.

В традиционном приложении двухмерный элемент Viewport3D используется как любой другой контейнерный элемент, например «Grid» или «Canvas». Хотя элемент Viewport3D можно использовать с другими графическими объектами двухмерный в том же графе сцены, нельзя сочетать объекты двухмерный и трехмерный внутри элемента Viewport3D. Этот раздел будет посвящен рисованию трехмерный графики внутри объекта Viewport3D.

Координаты трехмерного пространства

Начало системы координат WPF для графики двухмерный отсчитывается от левого верхнего угла области отрисовки (обычно экрана). В системе двухмерный положительные значения оси x откладываются вправо, а положительные значения оси y — сверху вниз. Однако в системе координат трехмерный начало располагается в центре отрисовываемой области, положительные значения оси x откладываются вправо, оси y — снизу вверх, а оси z — из центра к наблюдателю.

Представления традиционных двумерных и трехмерных систем координат
Системы координат

Пространство, определяемое этими осями, является стационарной системой отсчета координат для объектов трехмерный в приложении WPF. При построении моделей в этом пространстве и создании источников света и камер для их отображения необходимо отличать стационарную систему отсчета координат (или «мировую систему координат») от локальной системы отсчета, которая создается для каждой модели при применении к ней преобразований. Помните, что в зависимости от настройки освещения и камеры, объекты в мировой системе координат могут выглядеть совсем по-другому или вообще быть невидимыми, но положение камеры не изменяет расположения объектов в мировой системе координат.

Камеры и проекции

Разработчики, работающие в координатах двухмерный, привыкли к размещению графических примитивов на двухмерном экране. При создании сцены трехмерный важно помнить, что фактически создается представление двухмерный объектов трехмерный. Поскольку сцена трехмерный выглядит по-разному в зависимости от точки наблюдения, необходимо указать эту точку наблюдения. Указать эту точку наблюдения для сцены трехмерный позволяет класс Camera.

Другой способ понимания того, как представляется сцена трехмерный на поверхности двухмерный, — это описание сцены как проекции на поверхность просмотра. Камера ProjectionCamera позволяет указать различные проекции и их свойства для изменения того, как наблюдатель видит модели трехмерный. Камера PerspectiveCamera указывает проекцию сцены в перспективе. Другими словами, камера PerspectiveCamera предоставляет точку схода перспективы. Можно указать положение камеры в пространстве координат сцены, направление и поле зрения камеры и вектор, определяющий направление «вверх» в сцене. Следующая схема иллюстрирует проекции PerspectiveCamera.

Свойства NearPlaneDistance и FarPlaneDistance камеры ProjectionCamera ограничивают диапазон проекции камеры. Поскольку камеры могут быть расположены в любом месте сцены, фактически можно расположить камеру внутри модели или очень близко от нее, что усложняет правильное распознавание объекта. Свойство NearPlaneDistance позволяет указать минимальное расстояние от камеры, до которого объекты не будут нарисованы. И наоборот, свойство FarPlaneDistance позволяет задать расстояние от камеры, дальше которого объекты не будут нарисованы; это гарантирует, что объекты, расположенные слишком далеко для распознавания, не будут включены в сцену.

Позиция камеры
Настройка камеры

Камера OrthographicCamera указывает ортогональную проекцию модели трехмерный на визуальную поверхность двухмерный. Подобно другим камерам, она указывает позицию, направление просмотра и направление «вверх». Однако в отличие от камеры PerspectiveCamera, камера OrthographicCamera описывает проекцию, которая не включает ракурс перспективы. Другими словами, камера OrthographicCamera описывает призму, стороны которой параллельны, вместо призмы, стороны которой сходятся в точке камеры. На следующем рисунке показана одна модель, отображенная с использованием камер PerspectiveCamera и OrthographicCamera.

Перспективная и ортогональная проекции
Ортогональная и перспективная проекции

В следующем коде показано несколько обычных параметров камеры.

           <!-- Add a camera. -->
            <Viewport3D.Camera>
                <PerspectiveCamera FarPlaneDistance="20" LookDirection="5,-2,-3" UpDirection="0,1,0" NearPlaneDistance="1" Position="-5,2,3" FieldOfView="45" />
            </Viewport3D.Camera>
// Defines the camera used to view the 3D object. In order to view the 3D object,
// the camera must be positioned and pointed such that the object is within view 
// of the camera.
PerspectiveCamera myPCamera = new PerspectiveCamera();

// Specify where in the 3D scene the camera is.
myPCamera.Position = new Point3D(0, 0, 2);

// Specify the direction that the camera is pointing.
myPCamera.LookDirection = new Vector3D(0, 0, -1);

// Define camera's horizontal field of view in degrees.
myPCamera.FieldOfView = 60;

// Asign the camera to the viewport
myViewport3D.Camera = myPCamera;
// Defines the camera used to view the 3D object. In order to view the 3D object,
// the camera must be positioned and pointed such that the object is within view 
// of the camera.
PerspectiveCamera myPCamera = new PerspectiveCamera();

// Specify where in the 3D scene the camera is.
myPCamera.Position = new Point3D(0, 0, 2);

// Specify the direction that the camera is pointing.
myPCamera.LookDirection = new Vector3D(0, 0, -1);

// Define camera's horizontal field of view in degrees.
myPCamera.FieldOfView = 60;

// Asign the camera to the viewport
myViewport3D.Camera = myPCamera;

Примитивы модели и сетки

Model3D — это абстрактный базовый класс, представляющий универсальный объект трехмерный. Чтобы построить сцену трехмерный, необходимо, чтобы некоторые объекты для отображения и объекты, составляющие граф сцены, наследовали от класса Model3D. В настоящее время приложение WPF поддерживает моделирование геометрических объектов с помощью класса GeometryModel3D. Свойство Geometry данной модели принимает примитив сетки.

Начните построение модели с создания примитива, или сетки. Примитив трехмерный представляет собой набор вершин, образующих одну сущность трехмерный. Большинство систем трехмерный предоставляют примитивы, смоделированные на основе простейшей замкнутой фигуры: треугольника, определенного тремя вершинами. Поскольку три точки треугольника лежат в одной плоскости, можно добавлять треугольники для моделирования более сложных фигур, называемых сетками.

Текущая система трехмерный приложения WPF предоставляет класс MeshGeometry3D, позволяющий определить любую геометрическую форму; в настоящее время не поддерживаются примитивы трехмерный, такие как сферы или кубические формы. Начните создание класса MeshGeometry3D с определения списка вершин треугольников в качестве свойства Positions. Каждая вершина задается как свойство Point3D. (В Язык XAML (Extensible Application Markup Language) укажите это свойство в виде списка чисел, сгруппированных тройками и представляющих координаты каждой вершины.) В зависимости от геометрического объекта, сетка может состоять из множества треугольников, некоторые из которых совместно используют общие углы (вершины). Чтобы нарисовать сетку правильно, приложению WPF требуются данные о том, какие вершины треугольников являются общими. Предоставить эти данные можно, указав список индексов треугольников в свойстве TriangleIndices. Этот список определяет порядок, в котором точки, указанные в списке Positions, будут определять треугольник.

<GeometryModel3D>
  <GeometryModel3D.Geometry>
          <MeshGeometry3D 
              Positions="-1 -1 0  1 -1 0  -1 1 0  1 1 0"
              Normals="0 0 1  0 0 1  0 0 1  0 0 1"
              TextureCoordinates="0 1  1 1  0 0  1 0   "
              TriangleIndices="0 1 2  1 3 2" />
      </GeometryModel3D.Geometry>
      <GeometryModel3D.Material>
          <DiffuseMaterial>
              <DiffuseMaterial.Brush>
                  <SolidColorBrush Color="Cyan" Opacity="0.3"/>
              </DiffuseMaterial.Brush>
          </DiffuseMaterial>
      </GeometryModel3D.Material>
  <!-- Translate the plane. -->
      <GeometryModel3D.Transform>
          <TranslateTransform3D
            OffsetX="2" OffsetY="0" OffsetZ="-1"   >
          </TranslateTransform3D>
      </GeometryModel3D.Transform>
  </GeometryModel3D>

В предыдущем примере список Positions задает восемь вершин для определения сетки кубической формы. Свойство TriangleIndices указывает список двенадцати групп по три индекса. Каждое число в списке определяет смещение в списке Positions. Например, первыми тремя вершинами, определенными списком Positions, являются (1,1,0), (0,1,0) и (0,0,0). Первыми тремя индексами, указанными в списке TriangleIndices, являются 0, 2 и 1, которые соответствуют первой, третьей и второй точкам в списке Positions. В результате, первый треугольник, формирующий модель куба, будет составлен из вершин (1,1,0), (0,1,0) и (0,0,0), а оставшиеся одиннадцать треугольников будут определяться аналогичным образом.

Можно продолжить определение модели путем указания значений свойств Normals и TextureCoordinates. Для отображения поверхности модели графической системе требуются данные о том, какое направление поверхности является лицевым для любого данного треугольника. Система использует эти сведения для вычислений освещения модели: поверхности, обращенные к источнику освещения, отображаются ярче, чем поверхности, расположенные под углом к освещению. Хотя приложение WPF может определить векторы нормали по умолчанию, используя координаты позиции, можно задавать различные векторы нормали для аппроксимации вида кривых поверхностей.

Свойство TextureCoordinates указывает коллекцию объектов Point, сообщающую графической системе, каким образом сопоставлять координаты, определяющие отображение текстуры, с вершинами сетки. Свойства TextureCoordinates задаются как значение от нуля до 1 включительно. Также как и со свойством Normals, графическая система может вычислить координаты текстуры по умолчанию, но можно установить различные координаты текстуры, например, для управления отображением текстуры, содержащей часть повторяющегося узора. Дополнительные сведения о координатах текстуры можно найти в последующих разделах или в пакете Managed Direct3D SDK.

В следующем примере показано создание одной грани модели куба в процедурном коде. Обратите внимание, что можно нарисовать весь куб как один объект GeometryModel3D; в этом примере грань куба отображается как отдельная модель для того, чтобы далее применить отдельные текстуры для каждой грани.

MeshGeometry3D side1Plane = new MeshGeometry3D();
side1Plane.Positions.Add(new Point3D(-0.5, -0.5, -0.5));
side1Plane.Positions.Add(new Point3D(-0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, -0.5, -0.5));
side1Plane.Positions.Add(new Point3D(-0.5, -0.5, -0.5));

side1Plane.TriangleIndices.Add(0);
side1Plane.TriangleIndices.Add(1);
side1Plane.TriangleIndices.Add(2);
side1Plane.TriangleIndices.Add(3);
side1Plane.TriangleIndices.Add(4);
side1Plane.TriangleIndices.Add(5);

side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));

side1Plane.TextureCoordinates.Add(new Point(1, 0));
side1Plane.TextureCoordinates.Add(new Point(1, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 0));
side1Plane.TextureCoordinates.Add(new Point(1, 0));

Применение материалов к модели

Чтобы сетка выглядела как объект в трехмерном пространстве, к ней необходимо применить текстуру, которая покрывает поверхность, определенную ее вершинами и треугольниками. В этом случае можно осветить эту поверхность и создать ее проекцию с помощью камеры. В объектах двухмерный для применения цветов, узоров, градиентов или другого визуального содержимого к участкам экрана можно использовать класс Brush. Однако вешний вид объектов трехмерный является функцией модели освещения, а не только примененного к ним цвета или узора. Реальные объекты отражают свет неодинаково, в зависимости от качества поверхностей: гладкие и глянцевые поверхности выглядят иначе, чем неровные и матовые, также одни объекты поглощают свет, в то время как другие — отражают. К объектам трехмерный можно применить те же кисти, что и к объектам двухмерный, но применить их напрямую невозможно.

Для определения характеристик поверхности модели приложение WPF использует абстрактный класс Material. Конкретные подклассы класса «Material» определяют некоторые характеристики внешнего вида поверхности модели, и каждый из них предоставляет свойство «Brush», которому можно передать значение «SolidColorBrush», «TileBrush» или «VisualBrush».

  • Класс DiffuseMaterial определяет, что кисть будет применена к модели, как если бы она была освещена рассеянным светом. Использование класса «DiffuseMaterial» больше всего напоминает применение кистей непосредственно в моделях двухмерный; поверхности модели не отражают свет, как блестящие поверхности.

  • Класс SpecularMaterial определяет, что кисть будет применена к модели, как если бы поверхность модели была твердой или блестящей, способной отражать блики. Можно установить степень гладкости или «глянца» текстуры, задав значение свойства SpecularPower.

  • Класс EmissiveMaterial позволяет указать, что текстура будет применена, как если бы модель излучала свет, эквивалентный цвету кисти. Это не делает модель светящейся; однако это иначе влияет на затенение, чем если бы текстура была создана с помощью класса «DiffuseMaterial» или «SpecularMaterial».

Для повышения производительности противоположные поверхности объекта GeometryModel3D (грани, которые невидимы, поскольку находятся на противоположной стороне модели относительно камеры) удаляются из сцены. Чтобы указать класс Material для применения к противоположной поверхности модели, например плоскости, задайте свойство BackMaterial модели.

Для достижения некоторых свойств поверхности, таких как свечение или эффект отражения, можно последовательно применить к модели несколько различных кистей. Можно применять и повторно использовать несколько материалов с помощью класса MaterialGroup. Дочерние элементы класса «MaterialGroup» применяются от первого к последнему в нескольких проходах отрисовки.

Следующий пример кода демонстрирует применение сплошного цвета и рисования с помощью кистей к модели трехмерный.

<GeometryModel3D.Material>
    <DiffuseMaterial>
        <DiffuseMaterial.Brush>
            <SolidColorBrush Color="Cyan" Opacity="0.3"/>
        </DiffuseMaterial.Brush>
    </DiffuseMaterial>
</GeometryModel3D.Material>
<DrawingBrush x:Key="patternBrush" Viewport="0,0,0.1,0.1" TileMode="Tile">
  <DrawingBrush.Drawing>
    <DrawingGroup>
      <DrawingGroup.Children>
        <GeometryDrawing Geometry="M0,0.1 L0.1,0 1,0.9, 0.9,1z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.9,0 L1,0.1 0.1,1 0,0.9z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.25,0.25 L0.5,0.125 0.75,0.25 0.5,0.5z"
          Brush="#FFFF00" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.5,0.875 0.75,0.75 0.5,0.5z"
          Brush="Black" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.125,0.5 0.25,0.25 0.5,0.5z"
          Brush="#FF0000" />
        <GeometryDrawing Geometry="M0.75,0.25 L0.875,0.5 0.75,0.75 0.5,0.5z"
          Brush="MediumBlue" />
      </DrawingGroup.Children>
    </DrawingGroup>
  </DrawingBrush.Drawing>
</DrawingBrush>
<DrawingBrush x:Key="patternBrush" Viewport="0,0,0.1,0.1" TileMode="Tile">
  <DrawingBrush.Drawing>
    <DrawingGroup>
      <DrawingGroup.Children>
        <GeometryDrawing Geometry="M0,0.1 L0.1,0 1,0.9, 0.9,1z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.9,0 L1,0.1 0.1,1 0,0.9z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.25,0.25 L0.5,0.125 0.75,0.25 0.5,0.5z"
          Brush="#FFFF00" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.5,0.875 0.75,0.75 0.5,0.5z"
          Brush="Black" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.125,0.5 0.25,0.25 0.5,0.5z"
          Brush="#FF0000" />
        <GeometryDrawing Geometry="M0.75,0.25 L0.875,0.5 0.75,0.75 0.5,0.5z"
          Brush="MediumBlue" />
      </DrawingGroup.Children>
    </DrawingGroup>
  </DrawingBrush.Drawing>
</DrawingBrush>
DiffuseMaterial side5Material = new DiffuseMaterial((Brush)Application.Current.Resources["patternBrush"]);

Освещение сцены

Источники света в графике трехмерный выполняют ту же роль, что и реальные источники света: они делают поверхности видимыми. Более того, источники света определяют, какая часть сцены будет включена в проекцию. Объекты источников света в приложении WPF создают различные эффекты света и тени. Они смоделированы на основе поведения различных реальных источников света. Сцена должна включать, как минимум, один источник света, иначе модели будут невидимыми.

Указанные ниже источники света являются производными от базового класса Light:

  • AmbientLight: создает рассеянное освещение, при котором все объекты освещены одинаково, независимо от их расположения или ориентации.

  • DirectionalLight: создает освещение, аналогичное удаленному источнику света. Направленные источники света имеют свойство Direction, которое указывается как объект Vector3D, но без заданного местоположения.

  • PointLight создает освещение, как ближний источник света. Источники света «PointLights» занимают определенное положение и испускают свет из этого положения. Объекты сцены освещаются в зависимости от их расположения и расстояния по отношению к источнику света. Класс PointLightBase предоставляет свойство Range, которое определяет расстояние, за пределами которого модели не будут освещаться источником света. Класс «PointLight» также предоставляет свойства затухания, определяющие интенсивность ослабления источника света в зависимости от расстояния. Можно указать константу, линейную или квадратичную интерполяцию затухания источника света.

  • Класс SpotLight наследует от класса PointLight. Источники света «Spotlights» освещают сцену подобно источникам света PointLight и также имеют расположение и направление. Они проектируют свет в конусообразную область, задаваемую свойствами InnerConeAngleOuterConeAngle, значения которых указываются в градусах.

Источники света являются объектами Model3D, поэтому можно преобразовывать и анимировать свойства источников света, включая положение, цвет, направление и диапазон.

<ModelVisual3D.Content>
    <AmbientLight Color="#333333" />
</ModelVisual3D.Content>
DirectionalLight myDirLight = new DirectionalLight();
myDirLight.Color = Colors.White;
myDirLight.Direction = new Vector3D(-3, -4, -5);
modelGroup.Children.Add(myDirLight);

Преобразование моделей

При создании моделей они имеют определенное расположение в сцене. Для перемещения этих моделей внутри сцены, поворота или изменения размера нецелесообразно изменять вершины, определяющие сами модели. Вместо этого, как и в моделировании двухмерный, применяются преобразования моделей.

Каждый объект модели имеет свойство Transform, с помощью которого можно перемещать модель, изменять ее направление или размер. При применении преобразования фактически смещаются все точки модели с помощью вектора или значения, заданного преобразованием. Другими словами, выполняется преобразование координатного пространства, в котором определена модель («модельное пространство»), но значения, составляющие геометрию модели в системе координат всей сцены («мировое пространство»), не изменяются.

Дополнительные сведения о преобразовании моделей см. в разделе Общие сведения о трехмерных преобразованиях.

Анимация моделей

Реализация модели трехмерный в приложении WPF действует в той же системе анимации и времени, что и графика двухмерный. Другими словами, для анимации трехмерной сцены анимируйте свойства ее моделей. Можно непосредственно анимировать свойства примитивов, но обычно проще анимировать преобразования, изменяющие позицию или внешний вид моделей. Поскольку преобразования можно применить к объектам Model3DGroup также как и к отдельным моделям, то возможно применение одного набора анимаций к дочернему элементу Model3DGroup, а другого набора — к группе дочерних объектов. Также можно добиться разнообразных визуальных эффектов, анимируя свойства элементов освещения сцены. Наконец, можно анимировать саму проекцию, изменяя положение камеры или поле зрения. Общие сведения о системе времени и анимации в приложении WPF см. в разделах Общие сведения об эффектах анимации, Общие сведения о Storyboard и Общие сведения об объектах класса Freezable.

Для анимации объекта в приложении WPF создайте временную шкалу, определите анимацию (которая изменяет значение некоторого свойства во времени) и укажите свойство, к которому применяется анимация. Поскольку все объекты в сцене трехмерный являются дочерними элементами объекта Viewport3D, свойства, к которым применяется анимация, являются свойствами «Viewport3D».

Предположим, требуется создать качающуюся на месте модель. Можно применить свойство RotateTransform3D к модели и анимировать ее ось вращения от одного вектора к другому. В следующем примере кода показано применение объекта «Vector3DAnimation» к свойству «Axis» для «Rotation3D» преобразования, предполагая, что «RotateTransform3D» будет одним из нескольких преобразований, примененных к модели с помощью «TransformGroup».

//Define a rotation
RotateTransform3D myRotateTransform = 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;
myRotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AxisProperty, myVectorAnimation);
//Add transformation to the model
cube1TransformGroup.Children.Add(myRotateTransform);

Добавление трехмерного содержимого к окну

Для отображения сцены добавьте модели и источники света к объекту Model3DGroup, затем задайте объект Model3DGroup как свойство Content объекта ModelVisual3D. Добавьте ModelVisual3D к коллекции Children объекта Viewport3D. Добавьте камеры к объекту Viewport3D, задав его свойство Camera.

Наконец, добавьте объект Viewport3D к окну. При включении объекта Viewport3D в качестве содержимого элемента макета, такого как «Canvas», укажите размер объекта «Viewport3D», задав его свойства Height и Width(наследуемые от объекта FrameworkElement).

См. также

Основные понятия

Общие сведения о трехмерных преобразованиях

Обзор фигур и базовых средств рисования в приложении WPF

Рисование с помощью объектов Image, Drawing и Visual