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(); } } }
看看效果