我需要在Viewport3D
显示以下图片:
图像纹理以(0,0)为中心,其角坐标为(-1,-1,0),(1,-1,0),( - 1,1,0),(1, 1,0)。
由于我使用具有固定视野的PerspectiveCamera
,我必须计算足够的距离才能将整个图像放入视图中:
图像用蓝线表示, w 是图像宽度(w = 2)。
相机位置为(0,0,d),因此形成三角形:
tan(fov/2) = (w/2) / d
d = (w/2) / tan(fov/2)
现在我将3D模型的XAML代码和用于计算相机距离的代码混合放在一起:
XAML
<Window x:Class="Render3DTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="256" Width="256" Loaded="Window_Loaded">
<Grid>
<Viewport3D Name="viewport">
<Viewport3D.Camera>
<PerspectiveCamera Position="0,0,1" LookDirection="0,0,-1" FieldOfView="90" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="image.jpg"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0" TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0 1 2, 0 2 3" />
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</Window>
代码隐藏
private void Window_Loaded(object sender, RoutedEventArgs e)
{
PerspectiveCamera camera = (PerspectiveCamera)this.viewport.Camera;
double d = (1.0 / Math.Tan(camera.FieldOfView / 2.0));
camera.Position = new Point3D(0.0, 0.0, d);
}
但是,Viewport3D
不会显示整个图像:
还有其他因素在起作用吗?我不想在计算中使用任何调整或软糖因素。
请注意,调整窗口大小对水平视野范围没有影响,因为这是由相机FOV及其距离决定的,因此问题与控制尺寸无关 - 它与WPF项目指向的方式有关从3D到2D。
答案 0 :(得分:1)
你走在正确的轨道上。 PerspectiveCamera视野(fov)基于Viewport3D宽度,tan(fov / 2)以弧度接受fov。所以相机z是:
double fieldOfViewInRadians = perspectiveCamera.FieldOfView * (Math.PI / 180.0);
var z = (0.5 * _viewport3D.Width) / Math.Tan(0.5 * fieldOfViewInRadians);
perspectiveCamera.Position = new Point3D(0.0, 0.0, z);
确保控制面板&gt;显示设置为小100%。有一个部分允许您设置小(100%),中等和大缩放。这也有影响。
答案 1 :(得分:0)
我找到了一种利用透视相机线性度的可能解决方案。
Visual3D.TransformToAncestor
换句话说,如果相机再两次,图像会小两倍......
PerspectiveCamera camera = (PerspectiveCamera)this.viewport.Camera;
// set camera to a known distance
camera.Position = new Point3D(0.0, 0.0, 100.0);
Point3D[] points3D = new[]
{
new Point3D(-1.0, -1.0, 0.0),
new Point3D(1.0, -1.0, 0.0),
new Point3D(-1.0, 1.0, 0.0),
new Point3D(1.0, 1.0, 0.0)
};
double minX = Double.MaxValue;
double maxX = Double.MinValue;
double minY = Double.MaxValue;
double maxY = Double.MinValue;
GeneralTransform3DTo2D transform = this.viewport.Children[1].TransformToAncestor(this.viewport);
foreach (var point3D in points3D)
{
Point point2D = transform.Transform(point3D);
minX = Math.Min(minX, point2D.X);
maxX = Math.Max(maxX, point2D.X);
minY = Math.Min(minY, point2D.Y);
maxY = Math.Max(maxY, point2D.Y);
}
Size currentSize = new Size(maxX - minX, maxY - minY);
Size desiredSize = new Size(this.viewport.ActualWidth, this.viewport.ActualHeight);
double scaleFactor = Math.Max(
currentSize.Width / desiredSize.Width,
currentSize.Height / desiredSize.Height);
camera.Position = new Point3D(0.0, 0.0, 100.0 * scaleFactor); // the known distance of 100.0 is multiplied by scaleFactor