вторник, 21 февраля 2012 г.

Экспортирование FBX модели из 3D Studio max 2011 Design в XNA 4.0 c любым расположением Pivot point.


Здравствуйте. Достаточно часто при построении модели приходиться выбирать точку опоры (вращения) модели. В максе есть для этого специальные инструменты. Для того что бы поменять точку опоры модели необходимо воспользоваться панелью макса с права и выбрать вкладку Hierarchy-> Affect Pivot Only. При экспорте из макса FBX модели Pivot point модели экспортируется не так как хотелось бы. А точнее ее новое положение совсем не экспортируется. Что бы увидеть в редакторе какая же точка реально экспортируется нужно нажать на кнопку Reset Pivot на вкладке макса Hierarchy.  Для того что бы экспортировать другую точку опоры из редактора можно воспользоваться небольшой хитростью. Выделяем наш объект, и переводи его в режим редактирования мешей. Далее выделяем все точки модели и переносим их в то место, относительно которого будет наш Pivot point.То есть на самом дели в редакторе мы перемещаем не саму опору, а все точки модели относительно стандартной Pivot point. Далее как обычно экспортируем нашу модель. И вуаля при перемножении с матрицей мира на матрицу вращения в XNA наша моделька вращается вокруг нужной нам точки.

понедельник, 20 февраля 2012 г.

Быстрое создание GUI для XNA 4.0

Здравствуйте.
Сейчас я расскажу, как можно быстро создать GUI для игрового приложения на XNA 4.0.  Специально к этой статье я написал свой конвертор для конвертирования Windows Form класса в класс Neoforce Control.
Начнем сразу с примера и добавим GUI в приложения с домиком из этой статьи.

Этап I
Создадим Windows Form Application и построим следующую форму.






На этой форме имеется три TrackBar и три Label. У каждого TrackBar установим свойства Maximum в 360. Эта форма будет отвечать за вращение нашего домика.

Из этого проекта c только что созданной формой нам понадобиться только один файл Form1.Disigner.cs .
Далее откроем программу для конвертирования классов(Neoforce GUI Builder) и в качестве input file выберем класс из только что созданного проекта Windows Form, а именно Form1.Disigner.cs. Далее укажем, куда сохранить сконвертированный класс. И нажмем на кнопку Convert. Таким образом, мы создадим наш класс GUI для приложения XNA 4.0.







 Этап II
Наша форма готова теперь осталось лишь только в проекте с игрой добавить в качестве контента скин формы и две ссылки.  Шаблон скина и собственно сам скин и все DLL я приложу ко всем файлам. В проект Home нужно добавить две ссылки как показано на рисунке. В этот же проект нужно добавить в контент всю папку Skins и в качестве импортера файла Skin.xml выбрать Skin neoforce controls.








Далее в проект добавим сконвертированный класс из этапа I.



using TomShane.Neoforce.Controls;
using Microsoft.Xna.Framework;
namespace GUI
{
    sealed class Dialog1 : Window
    {
        public Label label1;
        public Label label2;
        public Label label3;
        public TrackBar trackBarRotX;
        public TrackBar trackBarRotY;
        public TrackBar trackBarRotZ;
        public Dialog1(Manager manager)
            : base(manager)
        {
            label1 = new Label(manager);
            this.label1.Text = "Rotation X";
            label1.Init();
            label1.Left = 12;
            label1.Top = 19;
            label1.Width = 57;
            label1.Height = 13;
            label1.Parent = this;

            label2 = new Label(manager);
            this.label2.Text = "Rotation Y";
            label2.Init();
            label2.Left = 15;
            label2.Top = 86;
            label2.Width = 57;
            label2.Height = 13;
            label2.Parent = this;

            label3 = new Label(manager);
            this.label3.Text = "Ratation Z";
            label3.Init();
            label3.Left = 9;
            label3.Top = 150;
            label3.Width = 57;
            label3.Height = 13;
            label3.Parent = this;

            trackBarRotX = new TrackBar(manager);
            this.trackBarRotX.Range = 360;
            trackBarRotX.Init();
            trackBarRotX.Left = 12;
            trackBarRotX.Top = 35;
            trackBarRotX.Width = 258;
            trackBarRotX.Height = 45;
            trackBarRotX.Parent = this;

            trackBarRotY = new TrackBar(manager);
            this.trackBarRotY.Range = 360;
            trackBarRotY.Init();
            trackBarRotY.Left = 15;
            trackBarRotY.Top = 102;
            trackBarRotY.Width = 258;
            trackBarRotY.Height = 45;
            trackBarRotY.Parent = this;

            trackBarRotZ = new TrackBar(manager);
            this.trackBarRotZ.Range = 360;
            trackBarRotZ.Init();
            trackBarRotZ.Left = 12;
            trackBarRotZ.Top = 179;
            trackBarRotZ.Width = 258;
            trackBarRotZ.Height = 45;
            trackBarRotZ.Parent = this;

            this.Width = 313;
            this.Height = 268;
            this.Text = "Game Panel";
        }
    }
}



Этап III
Далее подключим пространство имен в GUI в файле MyGame.cs.


using GUI;
 using TomShane.Neoforce.Controls;


И добавим следующие переменные
private float _rotX;
 private float _rotY;
 private float _rotZ;
 private Dialog1 _gamePanel;
 private Manager _guiManager;


Далее инициализируем наши переменные в методе Initialize
_guiManager = new Manager(this, graphics, "Green");
_guiManager.Initialize();
_gamePanel = new Dialog1(_guiManager);
_gamePanel.Init();


Этап IV


using GUI;
using TomShane.Neoforce.Controls;


И добавим следующие переменные


private float _rotX;
private float _rotY;
private float _rotZ;
private Dialog1 _gamePanel;
private Manager _guiManager;


Далее инициализируем наши переменные в методе Initialize
_guiManager = new Manager(this, graphics, "Green");
_guiManager.Initialize();
_gamePanel = new Dialog1(_guiManager);
_gamePanel.Init();


Не забудьте в менеджер добавить форму


_guiManager.Add(_gamePanel);
IsMouseVisible = true


В методе Update нужно добавить
_guiManager.Update(gameTime);


В метод Draw


protected override void Draw(GameTime gameTime)
{
   _guiManager.BeginDraw(gameTime);
   //Рисуем GUI
   _guiManager.Draw(gameTime);
   //Рисуем модель
   GraphicsDevice.DepthStencilState = DepthStencilState.Default;
   DrawModel(_home, _world, _view, _proj);

   spriteBatch.Begin();
   spriteBatch.DrawString(_font, "Hello word", new Vector2(10, 10), Color.Red);
   spriteBatch.End();
 
   _guiManager.EndDraw();
   base.Draw(gameTime);
}


Метод вращения


void Rotate(out Matrix parWorld, float parRotX, float parRotY, float parRotZ) 
{
   parWorld = Matrix.Identity;
   parWorld = Matrix.CreateRotationZ(MathHelper.ToRadians(parRotZ)) * 
   Matrix.CreateRotationY(MathHelper.ToRadians(parRotY)) * 
   Matrix.CreateRotationX(MathHelper.ToRadians(parRotX)); ;
}


Далее напишем обработчики событий.


void trackBarRotZ_ValueChanged(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
  _rotZ = _gamePanel.trackBarRotZ.Value;
  Rotate(out _world,_rotX, _rotY, _rotZ);          
}

void trackBarRotY_ValueChanged(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
   _rotY = _gamePanel.trackBarRotY.Value;
   Rotate(out _world, _rotX, _rotY, _rotZ);
}
void trackBarRotX_ValueChanged(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
   _rotX = _gamePanel.trackBarRotX.Value;
   Rotate(out _world, _rotX, _rotY, _rotZ);
}


Материалы к статье


  • HomeGUI.rar исходник к этой статье. ( Все сборки содержаться в архиве в /Home/bin)
  • Neoforce GUI Builder. Конвертер классов.  


Все это можно скачать по ссылке.


На этом все.

Neoforce GUI Builder

Конвертор из Window Form Class в Neoforce Window Class. 


Это только первая бета программки, но уже есть результат.
Скачать ее можно по ссылке.
Жду ваших комментариев по поводу программки.



среда, 15 февраля 2012 г.

Iniciative. Игра на XNA 4.0




Основные реализованные моменты :
  • Генерация ландшафта из карты высот
  • Текстурирование  ландшафта  по карте весов
  • Прозрачная водная поверхность
  • Ориентированные модели столкновений
  • Система частиц
  • Отрисовка прозрачных объектов
Видео в высоком разрешении
Комментируйте и задавайте вопросы.

понедельник, 30 мая 2011 г.

XNA 4.0 и 3ds Max Design 2011

Достаточно часто  у начинающих гейм девелоперов возникают трудности с выбором формата 3D моделей и последующей их загрузкой в свою игру. В XNA  4.0  существует 2 стандартных импортера 3D моделей. Это модели в формате x и fbx. В контексте использования XNA между этими форматами нет никакой разницы, так как XNA импортер все равно преобразует эти модели в свой внутренний формат xnb. Я лично предпочитаю использовать fbx формат, так как экспортер этого формата уже встроен в такие редакторы как 3D Studio Max и Blender. При необходимости можно отдельно скачать конвертор fbx с оф сайта.

И так рассмотрим процесс создание 3D модели в 3ds Max Design 2011.
Для простоты примера будем рисовать простую модель дома.
Открываем наш Max и рисуем куб со следующими параметрами:

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

Переведем наш бокс в режим редактирования мешей и смещаем верхние 8 вертиксов вверх.

Далее делаем крышу и сужаем 4 верхних вертикса:

Применим к нашему боксу модификатор Boolean и с помощью этого модификатора выдавим поочередно наши окна и дверь.

Вот результат:

Далее наложим текстуру на наш домик. Накладывать текстуру мы будем при помощи модификатора Unwrap UVW. При помощи данного модификатора выделяем стены нашего дома
и жмахаем на кнопку Edit.

Как вы, наверное, уже догадались то весь наш домик развернулся на плоскости в окне Edit UVWs. Все части нашего домика обязательно должны поместиться в черный квадрат(окна Edit UVWs). После нажатия кнопки Flatten mapping выделенные части автоматически про масштабируются и поместятся в этот самый черный квадрат (масштаб в окне Edit меняется колесом мышки.). Подобные операции необходимо проделать и с остальными частями домика. В результате должно получиться, что то вроде этого:

Далее отрендерим нашу текстуру. Жмахаем на кнопку Render UV Template и сохраняем картинку. Которая нам будет служить заготовкой нашей текстуры.

В любом графическом редакторе нарисуем нашу текстуру. У меня получилась вот такая текстура.

Следующим шагом будет наложение текстуры на модель. Открываем в максе Material Editor(кнопка M) и делаем как на скриншотах ниже.

Выбираем созданную текстуру и нажимаем кнопку OK.
Далее выделяем наш домик и нажимаем в редакторе материалов на кнопку Assign Material to Selection.

Для просмотра реального результата можно отрендерить картинку нажав на кнопку с изображением чайника на панели инструментов 3DS. Напоследок нужно сконвертировать нашу созданную модель в меши. (Левая кнопка и Convert to ->editible Mesh).
Для полной ясности разъясняю:
Vertex (Вертекс) это точка.
Edge это грань.
Mesh это треугольник.
Если же модель в максе находиться в режиме редактирования Poly то модель экспортировать в формат fbx не удасться. Нужно перевести в Editible  Mesh. Все материалы наложенные на нашу модель должны быть стандартными.
И наконец, экспортируем модель в формат fbx.(File -> Export).
С максом все, теперь осталось загрузить нашу модель в проект XNA.

Открываем студию и создаем проект XNA 4.0.  Cразу первым делом добавляем нашу модель и текстуру в проект в раздел для контента. Для отрисовки нашей модели нам понадобиться обьявить 4 матрицы и класс модели в главном классе нашей игры.
Model _home;
Matrix _world;
Matrix _view;
Matrix _proj;
Matrix _gameWorldRotation;
В методе Initialize() проинициализируем наши матрицы.
_world = Matrix.Identity;
Заполняем мировую матрицу _world по главной диагоняли еденицами. Эта матрица необходима нам для хранения положения обьекта в пространстве. Эта матрица размерностью 4 на 4 то есть получается 16 переменных типа float. Из них 9 задают ориентацию объекта в пространстве, а ещё 3 - его позицию. Оставшиеся четыре всегда неизменны и нужны для корректного выполнения операции умножения. Внутри она выглядит так:

Rotx1 Roty1 Rotz1 0
Rotx2 Roty2 Rotz2 0
Rotx3 Roty3 Rotz3 0
PosX PosY PosZ 1
Где PosX, PosY, PosZ - позицию объекта, а Rotx1, Roty1, Rotz1 - вектор-направление оси X объекта, Rotx2, Roty2, Rotz2 - вектор-направление оси Y объекта, Rotx3, Roty3, Rotz3 - вектор-направление оси Z объекта.

Далее инициализируем видовую матрицу.Матрица вида хранит местоположение и ориентацию камеры в мире.

_view = Matrix.CreateLookAt(new Vector3(0, 700, 500), Vector3.Zero, Vector3.Up);

Матрица проекции нужна нам для того чтобы получить проекции всех 3D обьектов на нашем экране. Вообщем для рисования 2D графики.

_proj = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), GraphicsDevice.Viewport.AspectRatio, 1.0f, 1000);

С инициализацией все. Теперь прогрузим нашу модель при помощи контент менеджера.
_home = Content.Load<Model>(@"Home");

Осталось теперь отрисовать нашу модель на экране.
Делать мы это будем при помощи отдельного метода.

private void DrawModel(Model model, Matrix world, Matrix view, Matrix proj)
{
//локальная мировая матрица
Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
 effect.EnableDefaultLighting();
 effect.View = view;
 effect.World = world * transforms[mesh.ParentBone.Index];
 effect.Projection = proj;
}
mesh.Draw();
 }
}
Для вращения обьекта на сцене в методе Update будем обновлять матрицу _gameWorldRotation следующим образом
_gameWorldRotation = Matrix.CreateRotationZ(MathHelper.ToRadians((float)gameTime.ElapsedGameTime.TotalMilliseconds / 100));
В метод Update вкачестве входного параметра приходит обьект gameTime. Этот обьект содержит свойство ElapsedGameTime. Т.е время с последнего вызова метода Update.
И наконец осталось только прорисовать нашу модель в методе Draw.
//Вращаем вокруг оси Z (локальных координат) нашу модель
_world = _world * _gameWorldRotation;
//Рисуем модель
DrawModel(_home, _world, _view, _proj);

Полный проект и модель можно скачать по ссылке