Используйте Matrix3DProjection и установите преобразование на основе матрицы, предоставленной в конце этой функции из Direct3D. Вам нужно ваше FOV в радианах, соотношение сторон для экрана и два расстояния для отсечения (вы определяете конечную усеченную дробь). Если вы ищете дальнейшее объяснение, почему это так, вы должны получить книгу о компьютерной графике. Также обычно, что матрица для проекционного преобразования устанавливает только видимость. Поворотные объекты вокруг оси X выполняются путем отдельного преобразования, но это обычная практика для компьютерной графики, и я не уверен, работает ли он так же в Silverlight.
Edit:
Если вам нужно использовать как вращение, так и
проекцию в одной матрице попробуйте использовать
вот этот:
xScale 0 0 0
0 cos(X)*yScale -sin(X)*z*zf/(zf-zn) -sin(X)
0 sin(X)*yScale cox(X)*z*zf/(zf-zn) cos(X)
0 0 (-zn*zf)/(zf-zn) 0
Где X в cos (X) и sin (X) - это ваш
вращение вокруг оси X в радианах
z - перевод в направлении Z
потому что вам придется двигаться с
Ваше изображение, чтобы увидеть его целиком.
yScale = cot (FOV / 2) FOV находится в
радиан
xScale = yScale / aspectRatio Aspect
соотношение определяется высотой и шириной
панели, используемой для рендеринга изображений
zn = Z рядом - все до этого
обрезается. ZF = Z далеко - все
после этого обрезается. Знать, что г
координата изображения должна быть между
те два.
Давно я не делал этого в последний раз
время, поэтому я надеюсь, что я рассчитал
преобразование правильно. матрица
умножение должно быть правильным, но
есть вероятность, что я умножил это
в неправильном порядке.
Edit2:
Мое предыдущее предложение не работает. Первые матрицы, используемые для вычислений, неверны, потому что Silverlight использует транспонированные версии. Второе преобразование изображения в центр и преобразование области просмотра не используется. Я объединил предложенный Элисон код (также можно найти здесь ) с модификацией, чтобы иметь приложение Silverlight для FovX и HiTech Magic. Я никогда раньше не писал приложение Silverlight ... Вот рабочий пример:
<Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid x:Name="Canvas" Background="White" Height="150" Width="200">
<Image x:Name="SampleImage" Source="Penguins.jpg" Stretch="Fill" VerticalAlignment="Center" HorizontalAlignment="Center" Height="120" Width="160" RenderTransformOrigin="0.5,0.5" >
<Image.Projection>
<Matrix3DProjection x:Name="Matrix" ProjectionMatrix="1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1"/>
</Image.Projection>
</Image>
</Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text=""X-Angle"" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<TextBox x:Name="XAngleTextBox" d:LayoutOverrides="Height" Grid.ColumnSpan="2" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="40" Text="{Binding Value, ElementName=XValueSlider}" TextChanged="XAngleTextBox_TextChanged"/>
<Slider x:Name="XValueSlider" Grid.Row="1" Grid.ColumnSpan="2" LargeChange="10" Maximum="80" SmallChange="1"/>
<TextBlock Text="Perspective Angle" VerticalAlignment="Top" Grid.Row="2" HorizontalAlignment="Right"/>
<TextBox x:Name="PerspectiveAngleTextBox" d:LayoutOverrides="Height" Grid.ColumnSpan="2" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="40" Text="{Binding Value, ElementName=PerspectiveSlider}" TextChanged="PerspectiveAngleTextBox_TextChanged" />
<Slider x:Name="PerspectiveSlider" Grid.Row="3" Grid.ColumnSpan="2" Maximum="120" SmallChange="1" LargeChange="10" Value="60"/>
</Grid>
</StackPanel>
</Grid>
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void UpdateMatrix()
{
double val;
double X = double.TryParse(XAngleTextBox.Text, NumberStyles.Any,
CultureInfo.InvariantCulture, out val) ? val : 0.0;
double FOV = double.TryParse(PerspectiveAngleTextBox.Text, NumberStyles.Any,
CultureInfo.InvariantCulture, out val) ? val : 0.0;
ApplyProjection(FOV, X);
}
private double DegreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
private void XAngleTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
UpdateMatrix();
}
private void PerspectiveAngleTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
UpdateMatrix();
}
private void ApplyProjection(double FOV, double X)
{
// Translate the image along the negative Z-axis such that it occupies 50% of the
// vertical field of view.
double fov = DegreeToRadian(FOV);
double translationZ = -SampleImage.Width / Math.Tan(fov / 2.0);
double theta = DegreeToRadian(X);
// You can create a 3D effect by creating a number of simple
// tranformation Matrix3D matrixes and then multiply them together.
Matrix3D centerImageAtOrigin = TranslationTransform(
-SampleImage.Width / 2.0,
-SampleImage.Height / 2.0, 0);
Matrix3D invertYAxis = CreateScaleTransform(1.0, -1.0, 1.0);
Matrix3D rotateAboutY = RotateYTransform(theta);
Matrix3D translateAwayFromCamera = TranslationTransform(0, 0, translationZ);
Matrix3D perspective = PerspectiveTransformFovRH(fov,
Canvas.ActualWidth / Canvas.ActualHeight,
1.0, // near plane
1000.0); // far plane
Matrix3D viewport = ViewportTransform(Canvas.ActualWidth, Canvas.ActualHeight);
Matrix3D m = centerImageAtOrigin * invertYAxis;
m = m * rotateAboutY;
m = m * translateAwayFromCamera;
m = m * perspective;
m = m * viewport;
Matrix3DProjection m3dProjection = new Matrix3DProjection();
m3dProjection.ProjectionMatrix = m;
SampleImage.Projection = m3dProjection;
}
private Matrix3D TranslationTransform(double tx, double ty, double tz)
{
Matrix3D m = new Matrix3D();
m.M11 = 1.0; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
m.M21 = 0.0; m.M22 = 1.0; m.M23 = 0.0; m.M24 = 0.0;
m.M31 = 0.0; m.M32 = 0.0; m.M33 = 1.0; m.M34 = 0.0;
m.OffsetX = tx; m.OffsetY = ty; m.OffsetZ = tz; m.M44 = 1.0;
return m;
}
private Matrix3D CreateScaleTransform(double sx, double sy, double sz)
{
Matrix3D m = new Matrix3D();
m.M11 = sx; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
m.M21 = 0.0; m.M22 = sy; m.M23 = 0.0; m.M24 = 0.0;
m.M31 = 0.0; m.M32 = 0.0; m.M33 = sz; m.M34 = 0.0;
m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
return m;
}
private Matrix3D RotateYTransform(double theta)
{
double sin = Math.Sin(theta);
double cos = Math.Cos(theta);
Matrix3D m = new Matrix3D();
m.M11 = cos; m.M12 = 0.0; m.M13 = -sin; m.M14 = 0.0;
m.M21 = 0.0; m.M22 = 1.0; m.M23 = 0.0; m.M24 = 0.0;
m.M31 = sin; m.M32 = 0.0; m.M33 = cos; m.M34 = 0.0;
m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
return m;
}
private Matrix3D RotateZTransform(double theta)
{
double cos = Math.Cos(theta);
double sin = Math.Sin(theta);
Matrix3D m = new Matrix3D();
m.M11 = cos; m.M12 = sin; m.M13 = 0.0; m.M14 = 0.0;
m.M21 = -sin; m.M22 = cos; m.M23 = 0.0; m.M24 = 0.0;
m.M31 = 0.0; m.M32 = 0.0; m.M33 = 1.0; m.M34 = 0.0;
m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
return m;
}
private Matrix3D PerspectiveTransformFovRH(double fieldOfView, double aspectRatio, double zNearPlane, double zFarPlane)
{
double width = 1.0 / Math.Tan(fieldOfView / 2.0);
double height = width * aspectRatio;
double d = zNearPlane - zFarPlane;
Matrix3D m = new Matrix3D();
m.M11 = width; m.M12 = 0; m.M13 = 0; m.M14 = 0;
m.M21 = 0; m.M22 = height; m.M23 = 0; m.M24 = 0;
m.M31 = 0; m.M32 = 0; m.M33 = zFarPlane / d; m.M34 = -1;
m.OffsetX = 0; m.OffsetY = 0; m.OffsetZ = zNearPlane * zFarPlane / d; m.M44 = 0;
return m;
}
private Matrix3D ViewportTransform(double width, double height)
{
Matrix3D m = new Matrix3D();
m.M11 = width / 2.0; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
m.M21 = 0.0; m.M22 = -height / 2.0; m.M23 = 0.0; m.M24 = 0.0;
m.M31 = 0.0; m.M32 = 0.0; m.M33 = 1.0; m.M34 = 0.0;
m.OffsetX = width / 2.0; m.OffsetY = height / 2.0; m.OffsetZ = 0.0; m.M44 = 1.0;
return m;
}
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
UpdateMatrix();
}
}