Опубликован: 13.07.2010 | Доступ: свободный | Студентов: 889 / 20 | Оценка: 4.40 / 4.20 | Длительность: 77:34:00
Самостоятельная работа 10:

Введение в DirectX

Обработка события изменения размеров окна

Если попробовать в запущенном на данном этапе приложении изменять размер окна формы, то в какие-то моменты треугольник исчезает и не хочет прорисовываться, либо начинает изменять размеры пропорционально размерам окна (попробуйте это!). Приложение Direct3D пытается сброситься или продолжить рендеринг с тем же самым пространственным разрешением. В результате изображение будет скопировано и вытянуто, чтобы заполнить измененное окно.

Управляемый DirectX способен контролировать процедуру изменения окна формы и автоматически перезапускать устройство при изменении окна. Для этого устройство имеет событие Microsoft.DirectX.Direct3D.Device. DeviceResizing, в обработчике которого можно сформировать код автоматического сброса устройства.

  • Добавьте в конец класса Form1 код регистрации и обработки события DeviceResizing
public void InitializeGraphics()
    {
      // Создание объекта и настройка параметров представления
      // Создать объект параметров представления
      PresentParameters presentParams = new PresentParameters();
      // Установить оконный режим
      presentParams.Windowed = true;
      // Сбрасывать содержимое буфера, если он не готов к представлению
      presentParams.SwapEffect = SwapEffect.Discard;
      // Создать объект устройства и сохранить ссылку на него
      device = new Device(0, DeviceType.Hardware, this,
        CreateFlags.SoftwareVertexProcessing, presentParams);
  
      // Перехват события изменения формы для сброса устройства
      device.DeviceResizing +=new CancelEventHandler(device_DeviceResizing);
    }
  
    // Обработчик события изменения формы для сброса устройства
    private void device_DeviceResizing(object sender, CancelEventArgs e)
    {
      e.Cancel = true;
    }
Листинг 10.19. Код сброса устройства при изменении размеров формы
  • Запустите приложение и максимизируйте окно

Мы видим, что у граней треугольника появились неровные края, что портит картину.

  • Уберите только что добавленный код, потому что DirectX сам отрабатывает по умолчанию процедуру изменения размеров окна оптимальным образом

Создание освещения сцены

Ранее, после того, как мы перевели модель треугольника в непреобразованные координаты, он стал черным и нам пришлось временно отключить освещение. Теперь мы займемся настройками источника света. Класс устройства имеет прикрепленный световой массив, каждый член которого определяет различные свойства света. Первое, что нужно сделать - включить освещение. Для этого необходимо либо явно установить флаг device.RenderState. Lighting в состояние true, либо просто убрать этот код из функции SetupCamera(), учитывая, что устройство device по умолчанию настроено с включенным освещением.

  • Включите свет, удалив или закомментировав соответствующую строку в функции SetupCamera() (или просто установите этот флаг device.RenderState. Lighting в значение true )

Если сейчас запустить приложение, то треугольник опять станет черным. Настроим освещение в нашей сцене.

  • Добавьте в метод OnPaint() формы перед формированием сцены следующий код
protected override void OnPaint(PaintEventArgs e)
        {
            // Очистить цветом клиентскую область формы
            device.Clear(ClearFlags.Target,
                System.Drawing.Color.CornflowerBlue,
                1.0F, 0);
    
            // Вызов нашей функции установки камеры
            SetupCamera();
    
            // Содать массив структур непреобразованных координат
            CustomVertex.PositionColored[] verts = new
                CustomVertex.PositionColored[3];
    
            // Задать параметры треугольника
            verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
            verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
            verts[1].Color = System.Drawing.Color.Black.ToArgb();
            verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
            verts[2].Color = System.Drawing.Color.Purple.ToArgb();
    
            // Настроить параметры света источника с номером 0
            device.Lights[0].Type = LightType.Point;    // Точечный источник
            // По умолчанию (0,0,0) - источник в начале координат
            device.Lights[0].Position = new Vector3();  
            // Свет диффузионный белый
            device.Lights[0].Diffuse = System.Drawing.Color.White;
            // Затухание света при удалении
            device.Lights[0].Attenuation0 = 0.2f;
            // Дальность освещения, поддерживаемая устройством
            device.Lights[0].Range = 1000.0f;
            // Принять настройки
            device.Lights[0].Commit();
            // Установить активным 
            device.Lights[0].Enabled = true;
    
            // Сформировать сцену
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts);
            device.EndScene();
    
            // Перерисовать
            device.Present();
    
            // Принудительно перерисовать
            this.Invalidate();
    
            // Вызвать обработчики, подписавшиеся на событие Paint
            // base.OnPaint(e);
        }
Листинг 10.20. Настройки освещения сцены

Вначале определяется, какой тип освещения мы хотим отобразить. Мы выбрали точечный источник света (Point), который излучает во всех направлениях одинаково. Существуют также направленное освещение, параллельное освещение, и световое пятно.

Мы поместили по умолчанию источник в центр треугольника с координатами ( 0,0,0 ) с помощью конструктора Vector3() класса параметров. Мы установили диффузионный компонент осветителя в режим получения рассеянного белого света, чтобы поверхность нормально освещалась. Мы установили параметр затухания ( Attenuation0 ), определяющий изменение интенсивности света при удалении. Диапазон освещения ( Range ) - это максимальное расстояние, в пределах которого распространяется свет.

  • Запустите приложение и убедитесь, что треугольник по прежнему остается черным

Причина в том, что Direct3D не может освещать объект, не имея нормали к каждому примитиву его поверхности. Нормаль представляет собой вектор, перпендикулярный к передней стороне каждой вершины примитива, описывающего поверхность освещаемого объекта.

  • Добавьте нормали к каждой вершине примитива-треугольника, а также новый формат построения сцены с учетом введенных дополнительных параметров нормали, заменив старый код на следующий
protected override void OnPaint(PaintEventArgs e)
        {
            // Очистить цветом клиентскую область формы
            device.Clear(ClearFlags.Target,
                System.Drawing.Color.CornflowerBlue,
                1.0F, 0);
    
            // Вызов нашей функции установки камеры
            SetupCamera();
    
            /*
            // Создать массив структур непреобразованных координат
            CustomVertex.PositionColored[] verts = new
                CustomVertex.PositionColored[3];
            */
    
            // Создать массив структур непреобразованных координат
            // треугольника с возможностью определения нормали к нему
            CustomVertex.PositionNormalColored[] verts = new
                CustomVertex.PositionNormalColored[3];
    
            // Задать параметры треугольника
            verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
            verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
            verts[1].Color = System.Drawing.Color.Black.ToArgb();
            verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
            verts[2].Color = System.Drawing.Color.Purple.ToArgb();
    
            // Дополнить вершины параметрами нормалей
            verts[0].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
            verts[1].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
            verts[2].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
    
            // Настроить параметры света источника с номером 0            
            device.Lights[0].Type = LightType.Point;    // Точечный источник
            // По умолчанию (0,0,0) - источник в начале координат
            device.Lights[0].Position = new Vector3();  
            // Свет диффузионный белый
            device.Lights[0].Diffuse = System.Drawing.Color.White;
            // Затухание света при удалении
            device.Lights[0].Attenuation0 = 0.2f;
            // Дальность освещения, поддерживаемая устройством 
            device.Lights[0].Range = 1000.0f;
            // Принять настройки
            device.Lights[0].Commit();
            // Установить активным 
            device.Lights[0].Enabled = true;
    
            // Сформировать сцену с учетом параметров 
            // "положение-нормаль-цвет"
            device.BeginScene();
            // Установить формат обработки вершин при отображении
            // device.VertexFormat = CustomVertex.PositionColored.Format;
            device.VertexFormat = CustomVertex.PositionNormalColored.Format;
            // Нарисовать в буфере кадра треугольник по вершинам 
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts);
            device.EndScene();
    
            // Показать буфер кадра 
            device.Present();
    
            // Принудительно перерисовать
            this.Invalidate();
    
            // Вызвать обработчики, подписавшиеся на событие Paint
            // base.OnPaint(e);
        }
Листинг 10.21. Добавление нормалей к треугольнику

Мы создали массив вершин треугольника, способных хранить информацию "положение-нормаль-цвет". К прежним параметрам вершин треугольника и их цвета мы добавили еще для каждой вершины параметры вектора нормали. Мы настроили устройство на работу с новым форматом вершин, чтобы учесть дополнительные параметры, описывающие нормали.

Следует помнить, что свет расчитывается применительно к вершине, поэтому при использовании аппроксимирующих полигонов с малым количеством вершин, освещение будет менее реалистичным. В таких случаях применяют более совершенный метод освещения - попиксельное освещение.

  • Постройте проект и полюбуйтесь на наше простое мультимедиа
  • Поизменяйте размеры окна и убедитесь, что пропорции треугольника сохраняются