Быть может кто-то из Вас знает игру 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