none
WPF, Viewport3D композиция из прозрачных объектов RRS feed

  • Вопрос

  • День добрый - рисую прозрачные 3D объекты в Viewport3D. Появилась проблема:

    1) Создаю два прозрачных объекта - "объект 1" и "объект 2". Прозрачность задаю через свойство кисти Opacity - делаю меньше 1

    2) Добавляю в Viewport3D "объект 1" после добавляю "объект 2" (свойство Viewport3D.children); Кручу камеру - сквозь объект "объект 2" вижу "объект 1", но сквозь "объект 1" не вижу "объект 2". Камера смотрит в точку между объектами; "объект 1" ведёт себя как не прозрачный - за его пределами виден "объект 2"

    3) Меняю порядок добавления - сначала добавляю "объект 2", потом "объект 1", остальное по прежнему (3D сетка объектов, текстуры, свет).  Картина полностью противоположная: сквозь "объект 1" вижу "объект 2, но не наоборот.

    Как быть? Перерисовывать композицию в зависимости от положения камеры или есть, какое-нибудь свойство кисти, текстуры?


    22 марта 2013 г. 8:34

Ответы

  • Подтверждается для любых типов кисти, света, камеры. Пока использую такой алгоритм, так сказать реализация "на пролом":

    1) выполнил рефаторнинг своего примера согласно рекомендациям  http://msdn.microsoft.com/ru-ru/library/bb613553.aspx

    2) При инициализации списка viewport3D.children - добавляю элементы в отсортированном порядке. Порядок: первыми добавляю самые дальние относительно камеры, последними самые ближние.

    3) Как только камера разворачивается относительно своей оси на 180 градусов:

       a) Запоминаю все объекты композиции в переменную типа List<Visual3D>;

       б) Удаляю объекты композиции;

       в) Заполняю объекты композиции в обратном порядке (цикл от count-1 до 0);

    В примере ниже два листинга - код для конструктора и код для редактора кода. Содаём новый проект WPF и заменяем в нём код на код из листингов. Компилируем - по клику на одном из объектов правой клавишей мышки происходит вращение по оси y, при клике левой клавишей по оси X.

    Если найдёте стандартный вариант (за счёт изменеия настроек ViewPort3D, кисти или геометрии объектов) буду признателен.

    <!-- скопировать в окно конструктора MainWindow.xaml -->
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="446"
            xmlns:my="clr-namespace:WpfApplication1">
        
        <Window.Resources>
            <ResourceDictionary>
                <!-- материал 1 -->
                <MaterialGroup  x:Key="myMaterial1">
                    <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                            <SolidColorBrush  Opacity="0.5" Color="LightGreen"/>
                        </DiffuseMaterial.Brush>
                    </DiffuseMaterial>
                </MaterialGroup>
                <!-- материал 2 -->
                <MaterialGroup  x:Key="myMaterial2">
                    <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                            <SolidColorBrush  Opacity="0.5" Color="LightPink"/>
                        </DiffuseMaterial.Brush>
                    </DiffuseMaterial>
                </MaterialGroup>
                <!-- геометрия объекта -->
                <MeshGeometry3D x:Key="MyGeometry"
                                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 0.5,-0.5,0 0.5,0.5,0 0.5,0.5,0 -0.5,0.5,0 -0.5,-0.5,0 " />
            </ResourceDictionary>
        </Window.Resources>
        
        <Grid>
            <Viewport3D Name="vp3d" IsHitTestVisible="True">
                <!-- камера -->
                <Viewport3D.Camera>
                    <PerspectiveCamera x:Name="camera" 
                                       Position="0,0,5" 
                                       Changed="camera_Changed">
                    </PerspectiveCamera>
                </Viewport3D.Camera>
                <!-- детки Viewport3D-->
                <Viewport3D.Children>
                    
                    <ModelVisual3D >
                        <ModelVisual3D.Content>
                            <!--компоозиция в целом-->
                            <Model3DGroup x:Name="Composit">
                                
                                <!--свет-->
                                <DirectionalLight Color="#FFFFFF" Direction="0, 0, -1" />
                                <DirectionalLight Color="#FFFFFF" Direction="0, 0, 1" />
                                <!--объекты композиции-->
                                <Model3DGroup x:Name="objects">
                                    
                                    <!--объект 1 (дальний)-->
                                    <Model3DGroup x:Name="object1">
                                        <GeometryModel3D Material="{StaticResource myMaterial1}" 
                                                         BackMaterial="{StaticResource myMaterial1}"
                                                         Geometry="{StaticResource MyGeometry}">
                                            <!--задаю смещение объекта-->
                                            <GeometryModel3D.Transform>
                                                <TranslateTransform3D OffsetZ="-0.5"/>
                                            </GeometryModel3D.Transform>
                                        </GeometryModel3D>
                                        
                                    </Model3DGroup>
                                    <!--объект 2 (ближний)-->
                                    <Model3DGroup x:Name="object2">
                                        <GeometryModel3D Material="{StaticResource myMaterial2}" 
                                                         BackMaterial="{StaticResource myMaterial2}"
                                                         Geometry="{StaticResource MyGeometry}">
                                                <!--задаю смещение объекта-->
                                                <GeometryModel3D.Transform>
                                                    <TranslateTransform3D OffsetZ="0.5"/>
                                                </GeometryModel3D.Transform>
                                        </GeometryModel3D>
                                    </Model3DGroup>
                                    <!--трансформация объектов общий поворт для наглядного представления-->
                                    <Model3DGroup.Transform>
                                        <RotateTransform3D>
                                            <RotateTransform3D.Rotation>
                                                <AxisAngleRotation3D Axis="0,3,0" Angle="40" />
                                            </RotateTransform3D.Rotation>
                                        </RotateTransform3D>
                                    </Model3DGroup.Transform>
                                </Model3DGroup>
                                
                            </Model3DGroup>
                        </ModelVisual3D.Content>
                    </ModelVisual3D>
                </Viewport3D.Children>
                <!-- триггеры-->
                <Viewport3D.Triggers>
                    
                    <!-- полёт камеры на левый клик - вокруг оси x. Чтобы камера могла оставаться в положении "вверхногами" - приходится задавать свойство UpDirection-->
                    <EventTrigger RoutedEvent="MouseLeftButtonDown">
                        <BeginStoryboard>
                            <Storyboard>
                                <Vector3DAnimationUsingKeyFrames Storyboard.TargetName="camera"
                                                                Storyboard.TargetProperty="UpDirection">
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:0.9"/>
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:1.9"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:2.1"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:3.5"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:4.5"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:5.5"/>
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:6.5"/>
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:7.5"/>
                                </Vector3DAnimationUsingKeyFrames>
                                
                                <Point3DAnimationUsingKeyFrames Storyboard.TargetName="camera"
                                                                Storyboard.TargetProperty="Position">
                                    <LinearPoint3DKeyFrame Value="0,-3.54,3.54" KeyTime="0:0:1"/>
                                    <LinearPoint3DKeyFrame Value="0,-5   ,0" KeyTime="0:0:2"/>
                                    <LinearPoint3DKeyFrame Value="0,-3.54,-3.54" KeyTime="0:0:3"/>
                                    <LinearPoint3DKeyFrame Value="0,0    ,-5" KeyTime="0:0:4"/>
                                    <LinearPoint3DKeyFrame Value="0,3.54,-3.54" KeyTime="0:0:5"/>
                                    <LinearPoint3DKeyFrame Value="0,5   ,0" KeyTime="0:0:6"/>
                                    <LinearPoint3DKeyFrame Value="0,3.54,3.54" KeyTime="0:0:7"/>
                                    <LinearPoint3DKeyFrame Value="0,0   ,5" KeyTime="0:0:8"/>
                                </Point3DAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <!-- полёт камеры на правый клик - вокруг оси y-->
                    <EventTrigger RoutedEvent="MouseRightButtonDown">
                        <BeginStoryboard>
                            <Storyboard>
                                <Point3DAnimationUsingKeyFrames Storyboard.TargetName="camera"
                                                            Storyboard.TargetProperty="Position">
                                        
                                <LinearPoint3DKeyFrame Value="-3.54,0,3.54" KeyTime="0:0:1"/>
                                <LinearPoint3DKeyFrame Value="-5,0,0" KeyTime="0:0:2"/>
                                <LinearPoint3DKeyFrame Value="-3.54,0,-3.54" KeyTime="0:0:3"/>
                                <LinearPoint3DKeyFrame Value="0,0,-5" KeyTime="0:0:4"/>
                                <LinearPoint3DKeyFrame Value="3.54,0,-3.54" KeyTime="0:0:5"/>
                                <LinearPoint3DKeyFrame Value="5,0,0" KeyTime="0:0:6"/>
                                <LinearPoint3DKeyFrame Value="3.54,0,3.54" KeyTime="0:0:7"/>
                                <LinearPoint3DKeyFrame Value="0,0,5" KeyTime="0:0:8"/>
                                </Point3DAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                     </EventTrigger>
                </Viewport3D.Triggers>
            </Viewport3D>
        </Grid>
    </Window>
    //скопировать в окно кода MainWindow.xaml.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    namespace WpfApplication1
    {
        
        /// <summary>
        /// Логика взаимодействия для MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            
            public MainWindow()
            {
                InitializeComponent();
            }
            #region [обработка события - изменения камеры]
            private void camera_Changed(object sender, EventArgs e)
            {
                //проверяем кто чтоб обработчик использывала камера
                if (sender is System.Windows.Media.Media3D.PerspectiveCamera)
                {
                    //задаём точку куда смотрит камера
                    System.Windows.Media.Media3D.Point3D camera_anchor = new System.Windows.Media.Media3D.Point3D(0.0, 0.0, 0.0);
                    //вычисляем вектор - направление камеры
                    System.Windows.Media.Media3D.Vector3D new_look_dir = (camera_anchor - (sender as System.Windows.Media.Media3D.PerspectiveCamera).Position);
                    //нормируем вектор - получаем еденичный вектор
                    System.Windows.Media.Media3D.Vector3D new_look_dir_norm = new System.Windows.Media.Media3D.Vector3D(Math.Sign(new_look_dir.X), Math.Sign(new_look_dir.Y), Math.Sign(new_look_dir.Z));
                    //задаём вектор камере
                    (sender as System.Windows.Media.Media3D.PerspectiveCamera).LookDirection = new_look_dir;
                    #region [если композиция содержит более 2 объектов]
                    if (this.objects != null
                                && this.objects.Children.Count >= 2)
                    {
                        //вычисляем единичный вектор между первым и последним объектом композиции
                        System.Windows.Media.Media3D.Vector3D vec = this.objects.Children[0].Bounds.Location - this.objects.Children[this.objects.Children.Count - 1].Bounds.Location;
                        vec = new System.Windows.Media.Media3D.Vector3D(Math.Sign(vec.X), Math.Sign(vec.Y), Math.Sign(vec.Z));
                        //вычисляем разницу еденичных векторов
                        System.Windows.Media.Media3D.Vector3D delta_vec = new_look_dir_norm - vec;
                        /*так как камера в момент построения композиции при инициализации окна распологалась на оси Z ( Position="0,0,5" ) -
                          проверяем Z кординату разности векторов. Если разница есть - то перестраиваем компзицию в обратном порядке - дальний объект становится ближним, а ближний дальним*/
                        if (delta_vec.Z != 0)
                        {
                            ReverseComposition();
                        }
                    } 
                    #endregion
                }
            } 
            #endregion
            /// <summary>
            /// перестроение композиции
            /// </summary>
            private void ReverseComposition()
            {
                //получаем список объктов композиции
                List<System.Windows.Media.Media3D.Model3D> l = new List<System.Windows.Media.Media3D.Model3D>(this.objects.Children.ToArray());
                //чистим композицию
                this.objects.Children.Clear();
                //заполняем в обратном порядке
                for (int i = l.Count - 1; i >= 0; i--)
                {
                    this.objects.Children.Add(l[i]);
                }
            }
        }
    }







    23 марта 2013 г. 4:43

Все ответы

  • А вы прозрачность задаете именно объекту, а не его заливке? Просто Opacity есть у всех типов заливок, так как он член базового Brush от которого унаследуются остальные заливки.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    22 марта 2013 г. 8:51
    Отвечающий
  • Насколько я помню Opacity болжно быть в пределах 0-1, 0 полностью прозрачный, 1- полностью не прозрачный
    22 марта 2013 г. 9:06
  • прозрачность задаю через свойство кисти материала (заливки):

    GeometryModel3D модель;

    SolidColorBrush кисть;

    DiffuseMaterial материал;

    MaterialGroup группа_материалов;

    //задаю геометрию для модель

    .....

    //задаю материал

    кисть.Opacity = 0.5;

    материал.Brush = кисть;

    группа_материалов.Children.Add(материал)

    модель.Material = группа_материалов; 


    22 марта 2013 г. 9:10
  • Может вам набросать небольшой пример и дать код. Так будет проще понять в чем проблема. А еще создание тестовых примеров иногда позволяет выявить проблемы кода. В тестовом работает, а полном проекте нет, бывает и такое.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    22 марта 2013 г. 9:17
    Отвечающий
  • 1. создать проект wpf

    2. вставить код (см. ниже)

    Тест 1: поменять местами объект 1 и 2 (чтобы xaml ModelVisual3D для объект 1 шёл ниже объекта 2

    Тест 2: после теста 1 развернуть камеру:  заменить  

    <PerspectiveCamera Position="0,0,5" LookDirection="0,0,-1" FieldOfView="60" />

    на  

    <PerspectiveCamera Position="0,0,-5" LookDirection="0,0, 1" FieldOfView="60" />

    Тест 3: поменять местами объект 2 и 1

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Viewport3D>
                <!-- камера -->
                <Viewport3D.Camera>
                    <PerspectiveCamera Position="0,0,5" LookDirection="0,0,-1" FieldOfView="60" />
                </Viewport3D.Camera>
                <!-- The ModelVisual3D children contain the 3D models -->
                <Viewport3D.Children>
                    <!--свет-->
                    <ModelVisual3D>
                        <ModelVisual3D.Content>
                            <DirectionalLight Color="#FFFFFF" Direction="-1,-1,-1" />
                        </ModelVisual3D.Content>
                    </ModelVisual3D>
                    
                    <!--объект 1-->
                    <ModelVisual3D>
                        <ModelVisual3D.Content>
                            
                            <GeometryModel3D>
                                <!--геометрия объект 1-->
                                <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>
                                <!--материал объект 1-->
                                <GeometryModel3D.Material>
                                    <MaterialGroup>
                                        <DiffuseMaterial>
                                            <DiffuseMaterial.Brush>
                                                <LinearGradientBrush Opacity="0.5" StartPoint="0,0.5" EndPoint="1,0.5">
                                                    <LinearGradientBrush.GradientStops>
                                                        <GradientStop Color="LightGreen" Offset="0" />
                                                        <GradientStop Color="LightGreen" Offset="1" />
                                                    </LinearGradientBrush.GradientStops>
                                                </LinearGradientBrush>
                                            </DiffuseMaterial.Brush>
                                        </DiffuseMaterial>
                                    </MaterialGroup>
                                </GeometryModel3D.Material>
                                <GeometryModel3D.BackMaterial>
                                    <MaterialGroup>
                                        <DiffuseMaterial>
                                            <DiffuseMaterial.Brush>
                                                <LinearGradientBrush Opacity="0.5" StartPoint="0,0.5" EndPoint="1,0.5">
                                                    <LinearGradientBrush.GradientStops>
                                                        <GradientStop Color="LightGreen" Offset="0" />
                                                        <GradientStop Color="LightGreen" Offset="1" />
                                                    </LinearGradientBrush.GradientStops>
                                                </LinearGradientBrush>
                                            </DiffuseMaterial.Brush>
                                        </DiffuseMaterial>
                                    </MaterialGroup>
                                </GeometryModel3D.BackMaterial>
                                <!--трансформация объект 1-->
                                <GeometryModel3D.Transform>
                                    <RotateTransform3D>
                                        <RotateTransform3D.Rotation>
                                            <AxisAngleRotation3D Axis="0,3,0" Angle="40" />
                                        </RotateTransform3D.Rotation>
                                    </RotateTransform3D>
                                </GeometryModel3D.Transform>
                            </GeometryModel3D>
                        </ModelVisual3D.Content>
                    </ModelVisual3D>
                    <!--объект 2-->
                    <ModelVisual3D>
                        <ModelVisual3D.Content>
                            <GeometryModel3D>
                                <!--геометрия объект 2-->
                                <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,1 0.5,-0.5,1 0.5,0.5,1 0.5,0.5,1 -0.5,0.5,1 -0.5,-0.5,1 " />
                                </GeometryModel3D.Geometry>
                                <!--материал объект 2-->
                                <GeometryModel3D.Material>
                                    <MaterialGroup>
                                        <DiffuseMaterial>
                                            <DiffuseMaterial.Brush>
                                                <LinearGradientBrush Opacity="0.5" StartPoint="0,0.5" EndPoint="1,0.5">
                                                    <LinearGradientBrush.GradientStops>
                                                        <GradientStop Color="LightGreen" Offset="0" />
                                                        <GradientStop Color="LightGreen" Offset="1" />
                                                    </LinearGradientBrush.GradientStops>
                                                </LinearGradientBrush>
                                            </DiffuseMaterial.Brush>
                                        </DiffuseMaterial>
                                    </MaterialGroup>
                                </GeometryModel3D.Material>
                                <GeometryModel3D.BackMaterial>
                                    <MaterialGroup>
                                        <DiffuseMaterial>
                                            <DiffuseMaterial.Brush>
                                                <LinearGradientBrush Opacity="0.5" StartPoint="0,0.5" EndPoint="1,0.5">
                                                    <LinearGradientBrush.GradientStops>
                                                        <GradientStop Color="LightGreen" Offset="0" />
                                                        <GradientStop Color="LightGreen" Offset="1" />
                                                    </LinearGradientBrush.GradientStops>
                                                </LinearGradientBrush>
                                            </DiffuseMaterial.Brush>
                                        </DiffuseMaterial>
                                    </MaterialGroup>
                                </GeometryModel3D.BackMaterial>
                                <!--трансформация объект 2-->
                                <GeometryModel3D.Transform>
                                    <RotateTransform3D>
                                        <RotateTransform3D.Rotation>
                                            <AxisAngleRotation3D Axis="0,3,0" Angle="40" />
                                        </RotateTransform3D.Rotation>
                                    </RotateTransform3D>
                                </GeometryModel3D.Transform>
                            </GeometryModel3D>
                        </ModelVisual3D.Content>
                    </ModelVisual3D>
                </Viewport3D.Children>
            </Viewport3D>
        </Grid>
    </Window>


    22 марта 2013 г. 9:58
  • Подтверждаю. Порядок объектов и положение камеры сказывается на прозрачности, но пока нет идей в чем может быть дело.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    22 марта 2013 г. 10:10
    Отвечающий
  • Подтверждается для любых типов кисти, света, камеры. Пока использую такой алгоритм, так сказать реализация "на пролом":

    1) выполнил рефаторнинг своего примера согласно рекомендациям  http://msdn.microsoft.com/ru-ru/library/bb613553.aspx

    2) При инициализации списка viewport3D.children - добавляю элементы в отсортированном порядке. Порядок: первыми добавляю самые дальние относительно камеры, последними самые ближние.

    3) Как только камера разворачивается относительно своей оси на 180 градусов:

       a) Запоминаю все объекты композиции в переменную типа List<Visual3D>;

       б) Удаляю объекты композиции;

       в) Заполняю объекты композиции в обратном порядке (цикл от count-1 до 0);

    В примере ниже два листинга - код для конструктора и код для редактора кода. Содаём новый проект WPF и заменяем в нём код на код из листингов. Компилируем - по клику на одном из объектов правой клавишей мышки происходит вращение по оси y, при клике левой клавишей по оси X.

    Если найдёте стандартный вариант (за счёт изменеия настроек ViewPort3D, кисти или геометрии объектов) буду признателен.

    <!-- скопировать в окно конструктора MainWindow.xaml -->
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="446"
            xmlns:my="clr-namespace:WpfApplication1">
        
        <Window.Resources>
            <ResourceDictionary>
                <!-- материал 1 -->
                <MaterialGroup  x:Key="myMaterial1">
                    <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                            <SolidColorBrush  Opacity="0.5" Color="LightGreen"/>
                        </DiffuseMaterial.Brush>
                    </DiffuseMaterial>
                </MaterialGroup>
                <!-- материал 2 -->
                <MaterialGroup  x:Key="myMaterial2">
                    <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                            <SolidColorBrush  Opacity="0.5" Color="LightPink"/>
                        </DiffuseMaterial.Brush>
                    </DiffuseMaterial>
                </MaterialGroup>
                <!-- геометрия объекта -->
                <MeshGeometry3D x:Key="MyGeometry"
                                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 0.5,-0.5,0 0.5,0.5,0 0.5,0.5,0 -0.5,0.5,0 -0.5,-0.5,0 " />
            </ResourceDictionary>
        </Window.Resources>
        
        <Grid>
            <Viewport3D Name="vp3d" IsHitTestVisible="True">
                <!-- камера -->
                <Viewport3D.Camera>
                    <PerspectiveCamera x:Name="camera" 
                                       Position="0,0,5" 
                                       Changed="camera_Changed">
                    </PerspectiveCamera>
                </Viewport3D.Camera>
                <!-- детки Viewport3D-->
                <Viewport3D.Children>
                    
                    <ModelVisual3D >
                        <ModelVisual3D.Content>
                            <!--компоозиция в целом-->
                            <Model3DGroup x:Name="Composit">
                                
                                <!--свет-->
                                <DirectionalLight Color="#FFFFFF" Direction="0, 0, -1" />
                                <DirectionalLight Color="#FFFFFF" Direction="0, 0, 1" />
                                <!--объекты композиции-->
                                <Model3DGroup x:Name="objects">
                                    
                                    <!--объект 1 (дальний)-->
                                    <Model3DGroup x:Name="object1">
                                        <GeometryModel3D Material="{StaticResource myMaterial1}" 
                                                         BackMaterial="{StaticResource myMaterial1}"
                                                         Geometry="{StaticResource MyGeometry}">
                                            <!--задаю смещение объекта-->
                                            <GeometryModel3D.Transform>
                                                <TranslateTransform3D OffsetZ="-0.5"/>
                                            </GeometryModel3D.Transform>
                                        </GeometryModel3D>
                                        
                                    </Model3DGroup>
                                    <!--объект 2 (ближний)-->
                                    <Model3DGroup x:Name="object2">
                                        <GeometryModel3D Material="{StaticResource myMaterial2}" 
                                                         BackMaterial="{StaticResource myMaterial2}"
                                                         Geometry="{StaticResource MyGeometry}">
                                                <!--задаю смещение объекта-->
                                                <GeometryModel3D.Transform>
                                                    <TranslateTransform3D OffsetZ="0.5"/>
                                                </GeometryModel3D.Transform>
                                        </GeometryModel3D>
                                    </Model3DGroup>
                                    <!--трансформация объектов общий поворт для наглядного представления-->
                                    <Model3DGroup.Transform>
                                        <RotateTransform3D>
                                            <RotateTransform3D.Rotation>
                                                <AxisAngleRotation3D Axis="0,3,0" Angle="40" />
                                            </RotateTransform3D.Rotation>
                                        </RotateTransform3D>
                                    </Model3DGroup.Transform>
                                </Model3DGroup>
                                
                            </Model3DGroup>
                        </ModelVisual3D.Content>
                    </ModelVisual3D>
                </Viewport3D.Children>
                <!-- триггеры-->
                <Viewport3D.Triggers>
                    
                    <!-- полёт камеры на левый клик - вокруг оси x. Чтобы камера могла оставаться в положении "вверхногами" - приходится задавать свойство UpDirection-->
                    <EventTrigger RoutedEvent="MouseLeftButtonDown">
                        <BeginStoryboard>
                            <Storyboard>
                                <Vector3DAnimationUsingKeyFrames Storyboard.TargetName="camera"
                                                                Storyboard.TargetProperty="UpDirection">
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:0.9"/>
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:1.9"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:2.1"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:3.5"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:4.5"/>
                                    <LinearVector3DKeyFrame Value="0,-1, 0" KeyTime="0:0:5.5"/>
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:6.5"/>
                                    <LinearVector3DKeyFrame Value="0, 1, 0" KeyTime="0:0:7.5"/>
                                </Vector3DAnimationUsingKeyFrames>
                                
                                <Point3DAnimationUsingKeyFrames Storyboard.TargetName="camera"
                                                                Storyboard.TargetProperty="Position">
                                    <LinearPoint3DKeyFrame Value="0,-3.54,3.54" KeyTime="0:0:1"/>
                                    <LinearPoint3DKeyFrame Value="0,-5   ,0" KeyTime="0:0:2"/>
                                    <LinearPoint3DKeyFrame Value="0,-3.54,-3.54" KeyTime="0:0:3"/>
                                    <LinearPoint3DKeyFrame Value="0,0    ,-5" KeyTime="0:0:4"/>
                                    <LinearPoint3DKeyFrame Value="0,3.54,-3.54" KeyTime="0:0:5"/>
                                    <LinearPoint3DKeyFrame Value="0,5   ,0" KeyTime="0:0:6"/>
                                    <LinearPoint3DKeyFrame Value="0,3.54,3.54" KeyTime="0:0:7"/>
                                    <LinearPoint3DKeyFrame Value="0,0   ,5" KeyTime="0:0:8"/>
                                </Point3DAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <!-- полёт камеры на правый клик - вокруг оси y-->
                    <EventTrigger RoutedEvent="MouseRightButtonDown">
                        <BeginStoryboard>
                            <Storyboard>
                                <Point3DAnimationUsingKeyFrames Storyboard.TargetName="camera"
                                                            Storyboard.TargetProperty="Position">
                                        
                                <LinearPoint3DKeyFrame Value="-3.54,0,3.54" KeyTime="0:0:1"/>
                                <LinearPoint3DKeyFrame Value="-5,0,0" KeyTime="0:0:2"/>
                                <LinearPoint3DKeyFrame Value="-3.54,0,-3.54" KeyTime="0:0:3"/>
                                <LinearPoint3DKeyFrame Value="0,0,-5" KeyTime="0:0:4"/>
                                <LinearPoint3DKeyFrame Value="3.54,0,-3.54" KeyTime="0:0:5"/>
                                <LinearPoint3DKeyFrame Value="5,0,0" KeyTime="0:0:6"/>
                                <LinearPoint3DKeyFrame Value="3.54,0,3.54" KeyTime="0:0:7"/>
                                <LinearPoint3DKeyFrame Value="0,0,5" KeyTime="0:0:8"/>
                                </Point3DAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                     </EventTrigger>
                </Viewport3D.Triggers>
            </Viewport3D>
        </Grid>
    </Window>
    //скопировать в окно кода MainWindow.xaml.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    namespace WpfApplication1
    {
        
        /// <summary>
        /// Логика взаимодействия для MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            
            public MainWindow()
            {
                InitializeComponent();
            }
            #region [обработка события - изменения камеры]
            private void camera_Changed(object sender, EventArgs e)
            {
                //проверяем кто чтоб обработчик использывала камера
                if (sender is System.Windows.Media.Media3D.PerspectiveCamera)
                {
                    //задаём точку куда смотрит камера
                    System.Windows.Media.Media3D.Point3D camera_anchor = new System.Windows.Media.Media3D.Point3D(0.0, 0.0, 0.0);
                    //вычисляем вектор - направление камеры
                    System.Windows.Media.Media3D.Vector3D new_look_dir = (camera_anchor - (sender as System.Windows.Media.Media3D.PerspectiveCamera).Position);
                    //нормируем вектор - получаем еденичный вектор
                    System.Windows.Media.Media3D.Vector3D new_look_dir_norm = new System.Windows.Media.Media3D.Vector3D(Math.Sign(new_look_dir.X), Math.Sign(new_look_dir.Y), Math.Sign(new_look_dir.Z));
                    //задаём вектор камере
                    (sender as System.Windows.Media.Media3D.PerspectiveCamera).LookDirection = new_look_dir;
                    #region [если композиция содержит более 2 объектов]
                    if (this.objects != null
                                && this.objects.Children.Count >= 2)
                    {
                        //вычисляем единичный вектор между первым и последним объектом композиции
                        System.Windows.Media.Media3D.Vector3D vec = this.objects.Children[0].Bounds.Location - this.objects.Children[this.objects.Children.Count - 1].Bounds.Location;
                        vec = new System.Windows.Media.Media3D.Vector3D(Math.Sign(vec.X), Math.Sign(vec.Y), Math.Sign(vec.Z));
                        //вычисляем разницу еденичных векторов
                        System.Windows.Media.Media3D.Vector3D delta_vec = new_look_dir_norm - vec;
                        /*так как камера в момент построения композиции при инициализации окна распологалась на оси Z ( Position="0,0,5" ) -
                          проверяем Z кординату разности векторов. Если разница есть - то перестраиваем компзицию в обратном порядке - дальний объект становится ближним, а ближний дальним*/
                        if (delta_vec.Z != 0)
                        {
                            ReverseComposition();
                        }
                    } 
                    #endregion
                }
            } 
            #endregion
            /// <summary>
            /// перестроение композиции
            /// </summary>
            private void ReverseComposition()
            {
                //получаем список объктов композиции
                List<System.Windows.Media.Media3D.Model3D> l = new List<System.Windows.Media.Media3D.Model3D>(this.objects.Children.ToArray());
                //чистим композицию
                this.objects.Children.Clear();
                //заполняем в обратном порядке
                for (int i = l.Count - 1; i >= 0; i--)
                {
                    this.objects.Children.Add(l[i]);
                }
            }
        }
    }







    23 марта 2013 г. 4:43