Pergunta

Como se usaria os componentes 3D do WPF ou usando um efeito pseudo -3D para criar um efeito "tigela", onde o usuário está olhando para baixo em uma tigela e pode arrastar os retângulos e fazer com que os retângulos mudem de perspectiva para que pareça que pareça Como se eles subissem, para baixo e ao redor da tigela? Não estou atrás de nenhum efeito de gravidade ou nada, exatamente quando os itens se movem, preciso que a perspectiva deles seja ajustada ...

EDIT: Eu tenho analisado os efeitos 3D reais disponíveis no WPF, que parecem muito poderosos, então talvez alguém possa ajudar a obter meia esfera no meu aplicativo e depois fazer algumas malhas em 3D (retângulos) para sua superfície?

Alguma ideia?

Obrigado, Mark

Foi útil?

Solução

Ahh, certo, aqui vai você então - você pode arrastar o retângulo vermelho ao redor da tigela agora - aproveite!

<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>

e o código atrás ...

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;
    }

}
}

Outras dicas

Aqui está, eu não tinha certeza do que você quis dizer sobre os retângulos, então acabei de adicionar quatro retângulos vermelhos ao redor da abertura de uma tigela verde.

Saúde,

Andy

Xaml primeiro ...

<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>

... e aqui está o código atrás ...

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

}
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top