天天看點

WPF 透視相機的UpDirection(向上方向)

透視相機的updirection,是具有三個參數的的屬性(X,Y,Z),不過Z屬性是沒有作用的。

那麼X,Y是什麼呢?

是用來确定角度的。

注意H邊,

我們知道機關圓上的一點都是可以用XY表示,用Y/X,即tan函數就可以求出圓心角的弧度,然後轉角度就可以了。

比如說UpDirection我們設定為 1 1 0,Y/X=1,tan等于1弧度,等于57.29度。

但是這麼做隻能先設定計算好XY的比值才能确定角度,不友善。

********************************************************************************************

是以我們使用極坐标,這樣我們就可以先設定角度又程式計算XY的值。

所謂極坐标即直角坐标系内使用角度和長度作為表示方式,比如 直角坐标系内的某點是(x,y)在極坐标内就是(p,θ)注意這裡面的θ是弧度。p是長度。

程式的UpDirection是用直角坐标系,是以我們給定好角度和長度後需要從極坐标轉到直角坐标系,使得我們的角度換算成直角坐标系内的表達方式,好在是,我們使用機關圓的預設長度即可也就是1;

極坐标換算直角坐标系方式為

x=p*cosθ

y=p*sinθ;

直角坐标系換算極坐标

p=根号下X的平凡+Y的平方

θ=Arctan(Y/X);

假設,XY坐标系内畫一個直徑為1的圓(圓心[0,0])

确定好圓上的點連接配接圓心之後和Y軸之間的夾角之後再用反三角函數求出角度即可

比如說我用tan函數

當确定X,Y值後,點連接配接圓心,長度為1,圓心角的對邊長度為X坐标,斜邊長度為1(不知道為什麼直接寫1不好使,必須用勾股定理求一下斜邊),之後再Arctan函數轉角度就好了。

上代碼:

<Window.Resources>
        <local:AngleConverter x:Key="Angle"/>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Viewport3D>
            <Viewport3D.Camera>
                <PerspectiveCamera LookDirection="0 0 -1" 
                                   FieldOfView="90"  
                                   UpDirection="{Binding ElementName=AngleSlider, Path=Value, Converter={StaticResource Angle}, Mode=TwoWay}"
                                   Position="0 0 400"/>
            </Viewport3D.Camera>
            <Viewport2DVisual3D>
                <Viewport2DVisual3D.Material>
                    <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True"/>
                </Viewport2DVisual3D.Material>
                <Viewport2DVisual3D.Geometry>
                    <MeshGeometry3D>
                        <MeshGeometry3D.Positions>
                            -100  100 0,
                            -100 -100 0,
                             100 -100 0,
                             100 100 0
                        </MeshGeometry3D.Positions>
                        <MeshGeometry3D.TextureCoordinates>
                            0 0,
                            0 1,
                            1 1,
                            1 0
                        </MeshGeometry3D.TextureCoordinates>
                        <MeshGeometry3D.TriangleIndices>
                            0 ,1 ,2 ,0 ,2 ,3
                        </MeshGeometry3D.TriangleIndices>
                    </MeshGeometry3D>
                </Viewport2DVisual3D.Geometry>
                <Viewport2DVisual3D.Visual>
                    <Button Content="旋轉" Height="150" Width="150"/>
                </Viewport2DVisual3D.Visual>
            </Viewport2DVisual3D>
            <ModelVisual3D>
                <ModelVisual3D.Content>
                    <DirectionalLight Color="White"/>
                </ModelVisual3D.Content>
            </ModelVisual3D>
        </Viewport3D>
        <StackPanel Grid.Row="1">
            <Slider Minimum="-360" Maximum="360" Value="0" x:Name="AngleSlider"/>
            <TextBlock  Text="{Binding ElementName=AngleSlider, Path=Value, Mode=OneWay}" />
        </StackPanel>
    </Grid>      

背景

namespace 向上鏡頭
{
    class AngleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            
            double angle , x,y;
            //轉換為弧度
            angle = Math.PI / 180*System.Convert.ToDouble(value);
            //極坐标轉為直角坐标系
            x = Math.Cos(angle);

            y = Math.Sin(angle);

            return new Vector3D(x, y, 0);


        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var point = (Vector3D)value;

            return Math.Atan2(point.X, point.Y) / Math.PI * 180;
        }
    }

    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}      

 看看效果