Одной из отличительных особенностей WPF при работе с графикой была поддержка 3D. Однако в отличие от WPF в Silverlight долгое время отсутствовала подобная функциональность. Но в Silverlight 5 была добавлена частичная поддержка XNA 4.0, которая позволила разработчикам также работать и с трехмерной графикой.
Однако перед началом работы с 3D надо отметить некоторые ограничения. Так, как было сказано, была добавлена частичная поддержка XNA, то есть вы знакомы с XNA, то вы не сможете реализовать в проекте на Silverlight 5 абсолютно все. Например, Silverlight 5 поддерживает только режим Reach. Также Silverlight поддерживает только модель Shader Model 2.0, но не поддерживает Shader Model 3.0.
Чтобы работать с 3D, нам надо настроить проект. Во-первых, добавим в него все необходимые сборки, которые нам потребуются:
System.Windows.Xna.dll. Включает такие ключевые классы, как DrawingSurface и DrawEventArgs
Microsoft.Xna.Framework.dll. Содержит классы, используемые при работе с трехмерной графикой
Microsoft.Xna.Framework.Graphics.dll. Содержит общие структуры и классы, например, Color и Rectangle
Microsoft.Xna.Framework.Graphics.Extensions.dll. Включает различные расширения для работы с графикой
Microsoft.Xna.Framework.Graphics.Shaders.dll. Включает классы для работы с эффектами, в частности, PixelShader и VertexShader
Microsoft.Xna.Framework.Math.dll. Содержит ряд вспомогательных классов для вычислений и разных математических опереций, в том числе над матрицами.
При работе с 3D используется аппаратное ускорение, поэтому нам надо его включить. Для этого нам надо установить в html-страничке, которая запускает наше приложение параметр EnableGPUAcceleration в true:
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="3DSLApplication.xap"/> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="5.0.61118.0" /> <param name="autoUpgrade" value="true" /> <param name="EnableGPUAcceleration" value="true" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style="text-decoration:none"> <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/> </a> </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
В основе работы с 3D-графикой в Silverlight лежит класс DrawingSurface. Он представляет обычный элемент Silverlight, обеспечивающий рендеринг графики.
Этот класс содержит событие Draw, которое возникает, когда система готова к отрисовке следующего кадра. В обработчике этого события происходит обновление матриц и отрисовка графических примитивов.
Добавим в элемент Grid новый элемент DrawingSurface:
<Grid x:Name="LayoutRoot" Background="White"> <DrawingSurface Width="400" Height="300" Draw="DrawingSurface_Draw" /> </Grid>
Вообще весь алгоритм создания трехмерной графики в Silverlight в общем случае может быть представлен следующим образом:
Создание в XAML элемента DrawingSurface
Создание обработчика события Draw элемента DrawingSurface
Создание вершин трехмерного объекта
Создание объекта VertexBuffer и использование метода SetData для добавления данных о вершинах в буфер
Создание пиксельного (PixelShader) и вершинного шейдеров (VertexShader)
Если для вершинного шейдера необходимы матрицы, то создаем мировую матрицу, а также матрицы вида и проекции
Затем в обработчике события Draw надо прописать следующие моменты:
Очистка графического устройства (класс GraphicsDevice) с помощью метода Clear
Установка для графического устройства буфера вершин (VertexBuffer) с помощью метода SetVertexBuffer
Установка для графического устройства вершинного шейдера (VertexShader) с помощью метода SetVertexShader
Установка для графического устройства пиксельного шейдера (PixelShader) с помощью метода SetPixelShader
Вызов DrawPrimitives
В конце вызов метода InvalidateSurface, чтобы система знала, что пора опять вызывать данный обработчик
Очистка графического устройства (класс GraphicsDevice) с помощью метода Clear
Вызов метода Invalidate
В XNA используется правосторонняя координатная система, то есть ось Z при такой системе направлена на нас:
Прежде чем перейти к созданию первого 3d-приложения, надо затронуть тему разрешений. По умолчанию для приложений Silverlight блокируется доступ к аппаратному ускорению графики. Чтобы обойти блокировку, пользователь должен установить разрешения для приложения на вкладке Permissions (Разрешения). Кроме того, самое главное - пользователь должен знать, что ему надо сделать. Ведь, если мы просто создадим вращающийся куб и запустим приложение, мы ничего не увидим. Поэтому добавим в обработчик события запуска приложения Application_Startup следующий код:
private void Application_Startup(object sender, StartupEventArgs e) { if (GraphicsDeviceManager.Current.RenderMode != RenderMode.Hardware) { string message; switch (GraphicsDeviceManager.Current.RenderModeReason) { case RenderModeReason.Not3DCapable: message = "Графическое устройство не поддерживает приложение"; break; case RenderModeReason.GPUAccelerationDisabled: message = "Для данного приложения не задано аппаратное ускорение графики"; break; case RenderModeReason.TemporarilyUnavailable: message = "Графическое устройство временно недоступно. Попробуйте перезагрузить страницу"; break; case RenderModeReason.SecurityBlocked: message = "Выполните следующие действия для просмотра приложения:\n\n" + " 1. Нажмите правой кнопкой мыши на страницу\n" + " 2. Выберите 'Silverlight'\n" + " (Отобразится диалоговое окно конфигурации Silverlight)\n" + " 3. Выберите вкладку Разрешения (Permissions)\n" + " 4. Найдите в списке текущий сайт и измените его разрешения с 'Deny' на 'Allow'\n" + " 5. Нажмите 'OK'\n" + " 6. Перезагрузите страницу"; break; default: message = "Неизвестная ошибка"; break; } } else { this.RootVisual = new MainPage(); } }
В случае возникновения соответствующих проблем на экране должно отобразится одно из прописанных нами сообщений, которое известит пользователя о его дальнейших действиях и проблеме.