سؤال

كيف يمكن للمرء أن يستخدم إما استخدام المكونات ثلاثية الأبعاد من WPF أو استخدام تأثير Pseudo 3D لإنشاء تأثير "وعاء" ، حيث ينظر المستخدم على وعاء ويمكن أن يتجول حول المستطيلات وتغيير منظور المستطيلات بحيث يبدو مثل يتحركون لأعلى ولأسفل وحول الوعاء؟ أنا لست بعد أي تأثيرات الجاذبية أو أي شيء ، فقط عندما تتحرك العناصر ، أحتاج إلى تعديل منظورها ...

تحرير: لقد كنت أبحث في التأثيرات ثلاثية الأبعاد الفعلية المتوفرة في WPF والتي تبدو قوية للغاية ، لذلك ربما يمكن أن يساعد شخص ما في الحصول على نصف كرة على تطبيقي ثم نقل بعض الشبكات ثلاثية الأبعاد (مستطيلات) على سطحه؟

أي أفكار؟

شكرا مارك

هل كانت مفيدة؟

المحلول

آه ، أليس كذلك ، هنا تذهب - يمكنك سحب المستطيل الأحمر حول الوعاء الآن - الاستمتاع!

<Window x:Class="wpfbowl.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="500" Width="500"
    DataContext="{Binding RelativeSource={RelativeSource Self}}" MouseDown="Window_MouseDown" MouseMove="Window_MouseMove" MouseUp="Window_MouseUp" >
<Window.Resources>
    <Transform3DGroup x:Key="WorldTrans">

        <RotateTransform3D>
            <RotateTransform3D.Rotation>
                <AxisAngleRotation3D x:Name="myAngleRotation" Axis="0,0,1" Angle="{Binding RotationLeftRight}" />

            </RotateTransform3D.Rotation>

        </RotateTransform3D>
        <RotateTransform3D>
            <RotateTransform3D.Rotation>
                <AxisAngleRotation3D x:Name="myAngleRotation2" Axis="1,0,0" Angle="{Binding RotationUpDown}" />

            </RotateTransform3D.Rotation>

        </RotateTransform3D>
    </Transform3DGroup>
</Window.Resources>
    <StackPanel>
    <Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Margin="0" Height="500" >
        <Viewport3D.Camera>
            <PerspectiveCamera 
          LookDirection="0,5,0"
          UpDirection="0,0,1"
          Position="0,-10,0" 
          />
        </Viewport3D.Camera>

        <ModelVisual3D  >
        <ModelVisual3D>
            <ModelVisual3D.Content>

                <Model3DGroup>

                    <PointLight Position="0,-10,0" Range="150" Color="White" />


                    </Model3DGroup>

            </ModelVisual3D.Content>
        </ModelVisual3D>
    </ModelVisual3D>


    <ModelVisual3D Transform="{StaticResource WorldTrans}">
        <ModelVisual3D Content="{Binding Models}">

        </ModelVisual3D>
    </ModelVisual3D>
        <ModelVisual3D >
            <ModelVisual3D Content="{Binding BowlModel}">

            </ModelVisual3D>
        </ModelVisual3D>

    </Viewport3D>
    </StackPanel>
</Window>

والرمز وراء ...

using System;
using System.ComponentModel;
using System.Timers;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Input;

namespace wpfbowl
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : INotifyPropertyChanged
{
    public Window1()
    {
        InitModels();
        InitializeComponent();

    }

    private Model3DGroup _cube;
    private bool _cubeSelected;
    private bool _cubeMoving;
    private Point3D _startPoint;
    private Point3D _currentPoint;

    public void InitModels()
    {
        const int bowlQuality = 20;
        Models = new Model3DGroup();
        BowlModel = new Model3DGroup();

        _cube = GetCube(GetSurfaceMaterial(Colors.Red), new Point3D(0, 2.6, 0), new Size3D(1.5, 0.2, 2));
        Models.Children.Add(_cube);

        var bowl = CreateBowl(new Point3D(0, 0, 0), 3, bowlQuality, bowlQuality, GetSurfaceMaterial(Colors.Green));
        BowlModel.Children.Add(bowl);
    }


    private readonly Timer _timer;

    public Model3DGroup Models { get; set; }

    public Model3DGroup BowlModel { get; set; }

    private double _rotationLeftRight;
    public double RotationLeftRight
    {
        get { return _rotationLeftRight; }
        set
        {
            if (_rotationLeftRight == value) return;
            _rotationLeftRight = value;
            OnPropertyChanged("RotationLeftRight");
        }
    }

    private double _rotationUpDown;
    public double RotationUpDown
    {
        get { return _rotationUpDown; }
        set
        {
            if (_rotationUpDown == value) return;
            _rotationUpDown = value;
            OnPropertyChanged("RotationUpDown");
        }
    }


    public static Model3DGroup CreateBowl(Point3D center, double radius, int u, int v, MaterialGroup materialGroup)
    {
        var bowl = new Model3DGroup();
        if (u < 2 || v < 2) return null;
        var pts = new Point3D[u, v];
        for (var i = 0; i < u; i++)
        {
            for (var j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius, i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        var p = new Point3D[4];
        for (var i = 0; i < (u /2) - 1; i++)
        {
            for (var j = 0; j <  v   - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[0], p[1], p[2]));
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[2], p[1], p[0]));
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[2], p[3], p[0]));
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[0], p[3], p[2]));
            }
        }
        return bowl;
    }


    private static Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

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

    private static Point3D GetPosition(double radius, double theta, double phi)
    {
        var pt = new Point3D();
        var snt = Math.Sin(theta * Math.PI / 180);
        var cnt = Math.Cos(theta * Math.PI / 180);
        var snp = Math.Sin(phi * Math.PI / 180);
        var cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public static MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public static Model3DGroup GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));
        var cube = new Model3DGroup();

        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        return cube;
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion

    private void Window_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {

            var mousePos = e.GetPosition(mainViewport);
            var hitParams = new PointHitTestParameters(mousePos);
            VisualTreeHelper.HitTest(mainViewport, null, ResultCallback, hitParams);


    }

    public HitTestResultBehavior ResultCallback(HitTestResult result)
    {
        // Did we hit 3D?
        var rayResult = result as RayHitTestResult;
        if (rayResult != null)
        {
            // Did we hit a MeshGeometry3D?
            var rayMeshResult = rayResult as RayMeshGeometry3DHitTestResult;

            if (rayMeshResult != null)
            {
                if (_cubeSelected)
                {
                    _cubeMoving = true;
                    _currentPoint = rayMeshResult.PointHit;
                    RotationLeftRight = (_startPoint.X - _currentPoint.X) * 15;
                    RotationUpDown = (_currentPoint.Z -_startPoint.Z)*15;
                }
                else
                {
                    var model = rayMeshResult.ModelHit;
                    foreach (var c in _cube.Children)
                    {
                        if (c.GetType() != typeof(Model3DGroup)) continue;
                        var model3DGroup = (Model3DGroup)c;
                        foreach (var sc in model3DGroup.Children)
                        {
                            if (model != sc) continue;

                            _cubeSelected = true;
                            _startPoint = rayMeshResult.PointHit;

                        }
                    } 
                }

            }
        }
        return HitTestResultBehavior.Continue;
    }

    private void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (!_cubeSelected) return;
        var mousePos = e.GetPosition(mainViewport);
        var hitParams = new PointHitTestParameters(mousePos);
        VisualTreeHelper.HitTest(mainViewport, null, ResultCallback, hitParams);
    }

    private void Window_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (!_cubeSelected) return;
        _cubeSelected = false;
        _cubeMoving = false;
    }

}
}

نصائح أخرى

هنا تذهب ، لم أكن متأكدًا تمامًا مما قصدته حول المستطيلات ، لذا فقد أضفت للتو أربعة مستطيلات حمراء حول فتح وعاء أخضر.

هتافات،

أندي

XAML أولاً ...

<Window x:Class="wpfbowl.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="500" Width="500"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
    <Transform3DGroup x:Key="WorldTrans">

        <RotateTransform3D>
            <RotateTransform3D.Rotation>
                <AxisAngleRotation3D x:Name="myAngleRotation" Axis="0,0,1" Angle="{Binding Rotation}" />
            </RotateTransform3D.Rotation>
        </RotateTransform3D>
    </Transform3DGroup>
</Window.Resources>
    <StackPanel>
    <Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Margin="0" Height="500" >
        <Viewport3D.Camera>
            <PerspectiveCamera 
          LookDirection="0,5,0"
          UpDirection="0,0,1"
          Position="0,-10,0" 
          />
        </Viewport3D.Camera>

        <ModelVisual3D  >
        <ModelVisual3D>
            <ModelVisual3D.Content>

                <Model3DGroup>

                    <PointLight Position="0,-10,0" Range="150" Color="White" />


                    </Model3DGroup>

            </ModelVisual3D.Content>
        </ModelVisual3D>
    </ModelVisual3D>


    <ModelVisual3D Transform="{StaticResource WorldTrans}">
        <ModelVisual3D Content="{Binding Models}">

        </ModelVisual3D>
    </ModelVisual3D>

</Viewport3D>
    </StackPanel>
</Window>

... و Heres الكود وراء ...

using System;
using System.ComponentModel;
using System.Timers;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace wpfbowl
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : INotifyPropertyChanged
{
    public Window1()
    {
        InitModels();
        InitializeComponent();

        _timer = new Timer(100);
        _timer.Elapsed += TimerElapsed;
        _timer.Enabled = true;
    }

    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action<double>(Transform), 2);
    }

    private void Transform(double value)
    {
        Rotation += value;
    }

    public void InitModels()
    {
        const int bowlQuality = 20;
        Models = new Model3DGroup();
        var sphere = CreateBowl(new Point3D(0, 0, 0), 3, bowlQuality, bowlQuality, GetSurfaceMaterial(Colors.Green));

        Models.Children.Add(GetCube(GetSurfaceMaterial(Colors.Red), new Point3D(3, 0, 0), new Size3D(1.5, 0.2, 2)));
        Models.Children.Add(GetCube(GetSurfaceMaterial(Colors.Red), new Point3D(-3, 0, 0), new Size3D(1.5, 0.2, 2)));
        Models.Children.Add(GetCube(GetSurfaceMaterial(Colors.Red), new Point3D(0, 0, 3), new Size3D(1.5, 0.2, 2)));
        Models.Children.Add(GetCube(GetSurfaceMaterial(Colors.Red), new Point3D(0, 0, -3), new Size3D(1.5, 0.2, 2)));
        Models.Children.Add(sphere);
    }


    private readonly Timer _timer;

    public Model3DGroup Models { get; set; }
    private double _rotation;
    public double Rotation
    {
        get { return _rotation; }
        set
        {
            if (_rotation == value) return;
            _rotation = value;
            OnPropertyChanged("Rotation");
        }
    }

    public static Model3DGroup CreateBowl(Point3D center, double radius, int u, int v, MaterialGroup materialGroup)
    {
        var bowl = new Model3DGroup();
        if (u < 2 || v < 2) return null;
        var pts = new Point3D[u, v];
        for (var i = 0; i < u; i++)
        {
            for (var j = 0; j < v; j++)
            {
                pts[i, j] = GetPosition(radius, i * 180 / (u - 1), j * 360 / (v - 1));
                pts[i, j] += (Vector3D)center;
            }
        }

        var p = new Point3D[4];
        for (var i = 0; i < (u /2) - 1; i++)
        {
            for (var j = 0; j <  v   - 1; j++)
            {
                p[0] = pts[i, j];
                p[1] = pts[i + 1, j];
                p[2] = pts[i + 1, j + 1];
                p[3] = pts[i, j + 1];
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[0], p[1], p[2]));
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[2], p[1], p[0]));
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[2], p[3], p[0]));
                bowl.Children.Add(CreateTriangleModel(materialGroup, p[0], p[3], p[2]));
            }
        }
        return bowl;
    }


    private static Model3DGroup CreateTriangleModel(Material material, Point3D p0, Point3D p1, Point3D p2)
    {
        var mesh = new MeshGeometry3D();
        mesh.Positions.Add(p0);
        mesh.Positions.Add(p1);
        mesh.Positions.Add(p2);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        var normal = CalculateNormal(p0, p1, p2);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);
        mesh.Normals.Add(normal);

        var model = new GeometryModel3D(mesh, material);

        var group = new Model3DGroup();
        group.Children.Add(model);
        return group;
    }

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

    private static Point3D GetPosition(double radius, double theta, double phi)
    {
        var pt = new Point3D();
        var snt = Math.Sin(theta * Math.PI / 180);
        var cnt = Math.Cos(theta * Math.PI / 180);
        var snp = Math.Sin(phi * Math.PI / 180);
        var cnp = Math.Cos(phi * Math.PI / 180);
        pt.X = radius * snt * cnp;
        pt.Y = radius * cnt;
        pt.Z = -radius * snt * snp;
        return pt;
    }

    public static MaterialGroup GetSurfaceMaterial(Color colour)
    {
        var materialGroup = new MaterialGroup();
        var emmMat = new EmissiveMaterial(new SolidColorBrush(colour));
        materialGroup.Children.Add(emmMat);
        materialGroup.Children.Add(new DiffuseMaterial(new SolidColorBrush(colour)));
        var specMat = new SpecularMaterial(new SolidColorBrush(Colors.White), 30);
        materialGroup.Children.Add(specMat);
        return materialGroup;
    }

    public static Model3DGroup GetCube(MaterialGroup materialGroup, Point3D point, Size3D size)
    {
        var farPoint = new Point3D(point.X - (size.X / 2), point.Y - (size.Y / 2), point.Z - (size.Z / 2));
        var nearPoint = new Point3D(point.X + (size.X / 2), point.Y + (size.Y / 2), point.Z + (size.Z / 2));
        var cube = new Model3DGroup();

        var p0 = new Point3D(farPoint.X, farPoint.Y, farPoint.Z);
        var p1 = new Point3D(nearPoint.X, farPoint.Y, farPoint.Z);
        var p2 = new Point3D(nearPoint.X, farPoint.Y, nearPoint.Z);
        var p3 = new Point3D(farPoint.X, farPoint.Y, nearPoint.Z);
        var p4 = new Point3D(farPoint.X, nearPoint.Y, farPoint.Z);
        var p5 = new Point3D(nearPoint.X, nearPoint.Y, farPoint.Z);
        var p6 = new Point3D(nearPoint.X, nearPoint.Y, nearPoint.Z);
        var p7 = new Point3D(farPoint.X, nearPoint.Y, nearPoint.Z);
        //front side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p2, p6));
        cube.Children.Add(CreateTriangleModel(materialGroup, p3, p6, p7));
        //right side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p1, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p5, p6));
        //back side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p0, p4));
        cube.Children.Add(CreateTriangleModel(materialGroup, p1, p4, p5));
        //left side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p3, p7));
        cube.Children.Add(CreateTriangleModel(materialGroup, p0, p7, p4));
        //top side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p6, p5));
        cube.Children.Add(CreateTriangleModel(materialGroup, p7, p5, p4));
        //bottom side triangles
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p3, p0));
        cube.Children.Add(CreateTriangleModel(materialGroup, p2, p0, p1));
        return cube;
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion

}
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top