|
Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Игровой мир, освещение, тени
Управление освещением, тени
Рассмотрим управление освещением и отображением теней в XNA. Существуют различные техники работы с тенями, мы рассмотрим отрисовку теней с использованием так называемого буфера трафаретов, или, по-английски - Stencil Buffer. В частности, мы модифицируем проект P16_2 таким образом, чтобы шарики, падающие на плоскость, отбрасывали тени.
Stencil Buffer является стандартным устройством, входящим в состав современных видеокарт. Однако, различные видеокарты могут иметь различный размер этого буфера, поэтому, перед его использованием, необходимо определить, какой именно буфер доступен на видеокарте, используемой в данный момент.
Для создания тени мы воспользуемся методом CreateShadow объекта Matrix. Он позволяет создавать тень от объекта на основе информации об источнике освещения и плоскости, на которую должна проецироваться тень.
После того, как создана матрица, представляющая собой тень, мы используем эту матрицу для вывода тени. Причем, техника работы такова: сначала вывести сцену, освещенную так, как нужно, после этого соответствующим образом настроить буфер трафаретов и вывести ту же сцену без освещения, модифицировав мировую матрицу с помощью полученной матрицы тени.
В этом же примере мы рассмотрим настройку источника света. В частности, мы применим для рисования объектов один направленный источник света, направление которого можно менять с помощью клавиш клавиатуры – координата Z изменяется с помощью клавиш-стрелок вверх-вниз, координата X – клавишами вправо-влево, координата Y – клавишами W и S. Изменение направления освещения влияет не только на освещение объектов, но и на тень.
Создадим новый проект – P17_2.
На рис. 22.3. вы можете видеть его окно Project Explorer.
Для представления моделей, выводимых на экран, мы используем класс modCls, в качестве ресурсов игры используем шар ball2 и плоскость plane.
Рассмотрим код класса modCls (листинг. 22.2.) В проекте P16_2 этот класс отвечал за вывод изображений на экран. Сейчас он выполняет ту же функцию, дополнив вывод изображений визуализацией теней.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
namespace P17_2
{
/// <summary>
/// This is a game component that implements IUpdateable.
/// </summary>
public class modCls : Microsoft.Xna.Framework.DrawableGameComponent
{
//Модель
public Model myModel;
//Мировая матрица, матрицы вида и проекции
public Matrix WorldMatrix;
public Matrix ViewMatrix;
public Matrix ProjectMatrix;
//Направление света
public Vector3 LightDirection;
//Матрица для отображения тени
Matrix shadow;
//Плоскость, на которой отображается тень
Plane sPlane;
//Соотношение сторон экрана
public float aspectRatio;
//Для управления графическим устройством
GraphicsDeviceManager graphics;
//Конструктор получает на вход
//игровой класс, модель, объект для управления графическим устройством и плоскость для вывода тени
public modCls(Game game, Model mod, GraphicsDeviceManager grf, Plane pl)
: base(game)
{
myModel = mod;
graphics = grf;
sPlane = pl;
aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
(float)graphics.GraphicsDevice.Viewport.Height;
LightDirection = new Vector3();
}
public override void Initialize()
{
// TODO: Add your initialization code here
base.Initialize();
}
public override void Draw(GameTime gameTime)
{
//Выводим объект
foreach (ModelMesh mesh in myModel.Meshes)
{
//Для каждого эффекта в сети
foreach (BasicEffect effect in mesh.Effects)
{
//Включить источник направленного света №0
effect.DirectionalLight0.Enabled = true;
//Настроить параметры
effect.DirectionalLight0.DiffuseColor = Vector3.One;
effect.DirectionalLight0.SpecularColor = Vector3.One;
//Направление света - в класса Game1 мы меняем направление
//по клавиатурным командам
effect.DirectionalLight0.Direction = Vector3.Normalize(LightDirection);
//Включить освещение
effect.LightingEnabled = true;
//Установка матриц
effect.World = WorldMatrix;
effect.View = ViewMatrix;
effect.Projection = ProjectMatrix;
}
mesh.Draw();
}
//Создать матрицу тени
shadow = Matrix.CreateShadow(-LightDirection, sPlane);
//Очистить буфер трафаретов
graphics.GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0, 0);
//Включть буфер трафаретов
graphics.GraphicsDevice.RenderState.StencilEnable = true;
// Вывод на экран элемента буфера в том случае, если он установлен в 0
graphics.GraphicsDevice.RenderState.ReferenceStencil = 0;
graphics.GraphicsDevice.RenderState.StencilFunction = CompareFunction.Equal;
//При выводе применяем операцию увеличения
graphics.GraphicsDevice.RenderState.StencilPass = StencilOperation.Increment;
//Включаем альфа-смешивание для того, чтобы сделать тень полупрозрачной
graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
//Выводим тень
foreach (ModelMesh mesh in myModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.AmbientLightColor = Vector3.Zero;
effect.Alpha = 0.5f;
effect.DirectionalLight0.Enabled = false;
effect.DirectionalLight1.Enabled = false;
effect.DirectionalLight2.Enabled = false;
effect.View = ViewMatrix;
effect.Projection = ProjectMatrix;
//При выводе тени умножаем мировую матрицу
//на матрицу вывода тени
effect.World = WorldMatrix*shadow;
}
mesh.Draw();
}
//Отключить буфер
graphics.GraphicsDevice.RenderState.StencilEnable = false;
//Отключить альфа-смешивание
graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
base.Draw(gameTime);
}
}
}
Листинг
22.2.
Код класса modCls
