Возможно вы искали: 'DanceDanceRevolution H...'

May 12 2025 01:23:28
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96030355
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18346
• Обзор The Walking ... 18789
• Обзор DMC: Devil M... 19864
• Обзор на игру Valk... 15867
• Обзор на игру Stars! 17754
• Обзор на Far Cry 3 17935
• Обзор на Resident ... 16012
• Обзор на Chivalry:... 17495
• Обзор на игру Kerb... 17970
• Обзор игры 007: Fr... 16604
Превью о играх
• Превью к игре Comp... 17946
• Превью о игре Mage... 14451
• Превью Incredible ... 14706
• Превью Firefall 13462
• Превью Dead Space 3 16325
• Превью о игре SimC... 14717
• Превью к игре Fuse 15432
• Превью Red Orche... 15532
• Превью Gothic 3 16334
• Превью Black & W... 17345
Главная » Статьи » Всё о XNA » Создание графа сцены для XNA

Создание графа сцены для XNA

Что такое граф сцены

Граф сцены – логическая структура, которая упорядочивает объекты сцены в древовидную зависимость. Текущая реализация графа сцены немного отличается от распространенных подходов решения подобных задач, он позволяет легко размещать элементы в пространстве, изменять и отрисовывать их. В дополнение, реализована фильтрация элементов, которые не попадают в поле зрения камеры.

Данная статья подразумевает знакомство читателя с C#, XNA и базовым пониманием принципов 3Dграфики.


Понимание Матриц и Кватернионов

Вся математическая «поднаготная» матриц и кватернионов может оказаться слишком сложным материалом для новичков, поэтому тут будут рассмотрены основные их характеристики и достоинства.

На самом деле матрицы и кватернионы можно использовать без углубления в математические дебри их реализаций, но желательно все же знать математику этих объектов, тогда их поведение для вас будет более предсказуемым. Если объясняться простым языком, то эти объекты инкапсулируют комбинации операции, которые можно произвести над трехмерным объектом. Матричные операции включают в себя перемещение (translation), вращение (rotation) и масштабирование (scaling). Кватернионы в основном ограничиваются только вращением.

Перемещение, как нетрудно догадаться, реализует изменение объектом своего местоположения в пространстве. В XNA Framework за перемещение отвечает свойство «Translation» структуры Matrix, через это свойство можно с легкостью как устанавливать так получать данные о перемещении объекта в пространстве. Для получения матрицы получения можно воспользоваться статичным методом Matrix.CreateTranslation.

Вращение – оно собственно и в Африке вращение. Обе структуры и матрицы, и кватернионы могут вращать объект как по одной, так и по всем остальным осям. В XNA также можно создавать матрицы и кватернионы вращения, указывая классические yaw, pitch, и roll значения.

Масштабирование отвечает за изменение размера объекта по одной или нескольким осям. Матрица масштабирования может быть создана статичным методом Matrix.CreateScale.

Иногда возникает необходимость, чтобы матрица или кватернион не оказывали воздействия на объект, для этого используется «единичная» (identity) матрица (кватернион). Умножение на единичную структуру матрицы или кватерниона, не приводит ни к какому изменению объекта. В XNA получить единичные экземпляры можно через Matrix.Identity и Quaternion.Identity.

Основное свойство матриц и кватернионов заключается в том, что несколько операций можно объединить в одну структуру, к примеру в место того чтобы к модели по очереди применять перемещение, вращение и масштабирование и хранить все три матрицы трансформации их можно объединить в одну и работать только с одной структурой. Объединение и матриц, и кватернионов производится операцией перемножения, умножение на единичную структуру не приводит к изменению объекта, это фактически операция «*1».

Для отрисовки модели используются три основные матрицы: world, view и projection. Мировая матрица (world) предназначена для позиционирования модели в пространстве, это может быть не обязательно пространство сцены, это может быть мировое пространство другой модели. После позиционирования модели в пространстве, он подвергается трансформации в пространство камеры (view), это позволяет перемещать камеру без изменения трансформаций самой модели. И наконец, производится перевод трехмерного пространства сцены в двумерное, для вывода на экран, при помощи матрицы проекции (projection).


Фундамент графа сцены

Построение дерева графа

Как уже упоминало выше граф сцены – это древовидная структура, в текущей реализации представленная двумя классами: SceneNodeCollection – коллекция элементов дерева и SceneNode – одиночный элемент. Интерфейс IController будет использоваться для анимации элементов графа.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public class SceneNodeCollection : ICollection<SceneNode>
{
    /// Тут простая реализация коллекции
}
 
 
public interface IController
{
    void UpdateSceneNode(SceneNode node, GameTime gameTime);
}
 
 
public class SceneNode
{
 
    // Поля
    SceneNodeCollection children = new SceneNodeCollection();
    Vector3 position = Vector3.Zero;
    Vector3 offset = Vector3.Zero;
    Quaternion rotation = Quaternion.Identity;
    bool visible = true;
    Matrix absoluteTransform = Matrix.Identity;
    IController controller;
 
 
    // Свойства
 
    public SceneNodeCollection Children
    {
        get { return children; }
    }
 
    public Vector3 Position
    {
        get { return position; }
        set { position = value; }
    }
 
    public Vector3 Offset
    {
        get { return offset; }
        set { offset = value; }
    }
 
    public Quaternion Rotation
    {
        get { return rotation; }
        set { rotation = value; }
    }
 
    public bool Visible
    {
        get { return visible; }
        set { visible = value; }
    }
 
    public BoundingSphere BoundingSphere
    {
        get { return GetBoundingSphere(); }
    }
 
    public Matrix AbsoluteTransform
    {
        get { return absoluteTransform; }
        set { absoluteTransform = value; }
    }
 
    public IController Controller
    {
        get { return controller; }
        set { controller = value; }
    }
 
    // Конструктор по умолчанию
    public SceneNode()
    {
    }
 
    //Методы
    protected virtual BoundingSphere GetBoundingSphere()
    {
        return new BoundingSphere(center, 0);
    }
 
    public virtual void Update(SceneGraph sceneGraph)
    {
        if (controller != null)
            controller.UpdateSceneNode(this, sceneGraph.GameTime);
    }
 
    public virtual void Draw(SceneGraph sceneGraph)
    {
    }
}

 

Класс SceneNodeCollection реализует стандартную коллекцию, при желании его можно заменить классом List, но не рекомендуется использовать List как незащищенное публичное поле.

 

Класс SceneNode представляет собой «листья» дерева сцены. Каждый SceneNode содержит в себе коллекцию дочерних «листьев» которые хранятся в SceneNodeCollection, таким образом мы получаем иерархию объектов сцены. Свойства местоположения (Position) и вращения (Rotation) содержат в себе значения по отношению к родительскому элементу, трансформации в мировом пространстве впоследствии будут вычисляться из этих значений проходя по всему графу сцены. Свойство BoundingSphere отвечает за расчет видимости объекта в пирамиде (frustum) камеры, если объект не попадает в камеру, он просто не будет отрисовываться. Метод Update отвечает за пересчет внутренних состояний объекта, Draw отвечает, как нетрудно догадаться за отрисовку объекта.


Создание визуального представления объектов

Теперь, когда написана основа для графа сцены, настало время прикрутить к нему модель.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
public class ModelSceneNode : SceneNode
{
    // Поля
    Model model;
    BoundingSphere modelSphere;
 
    // Свойства
    public Model Model
    {
        get { return model; }
        set
        {
            model = value;
 
            if (model == null)
                modelSphere = new BoundingSphere(Center, 0);
            else
                CalculateBoundingSphere();
        }
    }
 
    // Конструкторы
    public ModelSceneNode()
    {
    }
 
    public ModelSceneNode(Model model)
    {
        this.model = model;
        CalculateBoundingSphere();
    }
 
    // Методы
    private void CalculateBoundingSphere()
    {
        //Расчет BoundingSphere для модели
        modelSphere = new BoundingSphere();
 
        foreach (ModelMesh mesh in model.Meshes)
        {
            modelSphere = Microsoft.Xna.Framework.BoundingSphere.CreateMerged(
                                modelSphere,
                                model.Meshes[0].BoundingSphere);
        }
    }
 
    protected override BoundingSphere GetBoundingSphere()
    {
        return modelSphere;
    }
 
    public override void Draw(SceneGraph sceneGraph)
    {
        if (sceneGraph.Camera != null)
        {
            if (model != null)
            {
                // Копирование иерархии трансформаций модели
                Matrix[] transforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(transforms);
 
                // отрисовка кождого меша из модели
                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (Effect effect in mesh.Effects)
                    {
                        BasicEffect basicEffect = effect as BasicEffect;
 
                        if (basicEffect == null)
                        {
                            throw new NotSupportedException(
                                    "Only the BasicEffect is supported in a model.");
                        }
 
                        //Установка матриц
                        basicEffect.World = transforms[mesh.ParentBone.Index] *
                                                AbsoluteTransform;
 
                        basicEffect.View = sceneGraph.Camera.View;
                        basicEffect.Projection = sceneGraph.Camera.Projection;
 
                        basicEffect.EnableDefaultLighting();
                    }
 
                    mesh.Draw(SaveStateMode.SaveState);
                }
            }
        }
    }
}

 

Класс ModelSceneNode наследует от SceneNode и добавляет свойство Model для работы с моделью объекта, переопределяет метод CalculateBoundingSphere, который в свою очередь возвращает сферу окружения всей модели. Также переопределяется метод Draw который рассчитывает одну общую матрицу трансформации для модели из матриц мешей и матрицы элемента графа сцены (AbsoulteTransform), которая в свою очередь рассчитывается графом. Что же это нам дает? Модель размещенная где-то в пространстве и назначенная как дочерняя для другой модели, будет наследовать изменения своего «родителя».

Как уже упоминалось выше, камера дает возможность отображать сцену под любым углом и приближением без необходимости изменения параметров самих объектов.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public class Camera
{
    // Поля
    Vector3 position = Vector3.Zero;
    Quaternion rotation = Quaternion.Identity;
    float fieldOfView = (float)(System.Math.PI / 4.0);
    float aspectRatio = 4f / 3f;  // Ширина/Высота
    float nearPlane = 1.0f;
    float farPlane = 10500.0f;
    Matrix view;
    Matrix projection;
    BoundingFrustum frustum;
 
    // Свойства
    public Vector3 Position
    {
        get { return position; }
        set { position = value; }
    }
    public Quaternion Rotation
    {
        get { return rotation; }
        set { rotation = value; }
    }
    public float FieldOfView
    {
        get { return fieldOfView; }
        set { fieldOfView = value; }
    }
    public float AspectRatio
    {
        get { return aspectRatio; }
        set { aspectRatio = value; }
    }
    public float NearPlane
    {
        get { return nearPlane; }
        set { nearPlane = value; }
    }
    public float FarPlane
    {
        get { return farPlane; }
        set { farPlane = value; }
    }
    public Matrix View
    {
        get { return view; }
    }
    public Matrix Projection
    {
        get { return projection; }
    }
    public BoundingFrustum Frustum
    {
        get { return frustum; }
    }
 
    // Конструктор по умолчанию
    public Camera()
    {
    }
 
    // Методы
    public void LookAt(Vector3 target, Vector3 up)
    {
        view = Matrix.CreateLookAt(position, target, up);
 
        rotation = Quaternion.CreateFromRotationMatrix(Matrix.Invert(view));
    }
 
    public virtual void Update(SceneGraph sceneGraph)
    {
        projection = Matrix.CreatePerspectiveFieldOfView(fieldOfView,
                                                         aspectRatio,
                                                         nearPlane,
                                                         farPlane);
 
        Matrix matrix = Matrix.CreateFromQuaternion(rotation);
        matrix.Translation = position;
 
        view = Matrix.Invert(matrix);
 
        frustum = new BoundingFrustum(Matrix.Multiply(view, projection));
    }
}

 

Свойства Position и Rotation класса камеры задают местоположение камеры в пространстве и ее ориентацию. Метод LookAt предназначен для «нацеливания» камеры в точку пространства. Метод Update производит необходимые расчеты, рассчитывает матрицы вида (view), проекции (projection) и рассчитывает новую усеченную пирамиду камеры (frustum), которая впоследствии пригодится для исключения отрисовки невидимых объектов.

Собираем все воедино

Когда все основные элементы реализованы, настало время собрать их в граф сцены.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
public class SceneGraph
{
    // Поля
    SceneNode rootNode = new SceneNode();
    GraphicsDevice device;
    Camera camera;
    GameTime gameTime;
    int nodesCulled;
 
    // Свойства
    public SceneNode RootNode
    {
        get { return rootNode; }
        set { rootNode = value; }
    }
 
    public Camera Camera
    {
        get { return camera; }
        set { camera = value; }
    }
 
    public GameTime GameTime
    {
        get { return gameTime; }
    }
 
    public GraphicsDevice GraphicsDevice
    {
        get { return device; }
    }
 
    public int NodesCulled
    {
        get { return nodesCulled; }
    }
 
    // Конструктор
    public SceneGraph(GraphicsDevice device)
    {
        this.device = device;
    }
 
    // Методы
    void CalculateTransformsRecursive(SceneNode node)
    {
        node.AbsoluteTransform = Matrix.CreateTranslation(node.Offset) *
            Matrix.CreateFromQuaternion(node.Rotation) *
            node.AbsoluteTransform *
            Matrix.CreateTranslation(node.Position);
 
        //Рекурсивное обновление "потомков"
        foreach (SceneNode childNode in node.Children)
        {
            childNode.AbsoluteTransform = node.AbsoluteTransform;
            CalculateTransformsRecursive(childNode);
        }
    }
 
    void UpdateRecursive(SceneNode node)
    {
        //Обновление элемента
        node.Update(this);
 
        //Рекурсивное обновление "потомков"
        foreach (SceneNode childNode in node.Children)
        {
            UpdateRecursive(childNode);
        }
    }
 
    void DrawRecursive(SceneNode node)
    {
        //Отрисовка
        if (node.Visible)
        {
            BoundingSphere transformedSphere = new BoundingSphere();
            transformedSphere.Center = Vector3.Transform(node.BoundingSphere.Center,
                                                         node.AbsoluteTransform);
            transformedSphere.Radius = node.BoundingSphere.Radius;
            if (camera.Frustum.Intersects(transformedSphere))
            {
                node.Draw(this);
            }
            else
            {
                nodesCulled++;
            }
        }
 
        foreach (SceneNode childNode in node.Children)
        {
            DrawRecursive(childNode);
        }
    }
 
    void CalculateTransforms()
    {
        CalculateTransformsRecursive(rootNode);
    }
 
    public void Update(GameTime time)
    {
        gameTime = time;
 
        if (camera != null)
            camera.Update(this);
 
        UpdateRecursive(rootNode);
        CalculateTransformsRecursive(rootNode);
    }
 
    public void Draw()
    {
        nodesCulled = 0;
        rootNode.AbsoluteTransform = Matrix.Identity;
        DrawRecursive(rootNode);
    }
}

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

В процессе работы графа для каждого элемента рассчитывается матрица AbsoluteTransform, которая содержит в себе все действия по трансформации объекта в пространстве, родительский элемент передает эту матрицу в дочерние элементы и дочерний элемент «дописывает» в нее свои изменения присущие только этому элементу, таким образом если к примеру сдвинуть родительский элемент, все дочерние элементы сдвинутся вслед за родительским.

1
2
3
4
node.AbsoluteTransform = Matrix.CreateTranslation(node.Offset) *
            Matrix.CreateFromQuaternion(node.Rotation) *
            node.AbsoluteTransform *
            Matrix.CreateTranslation(node.Position);

 

В процессе обхода дерева вычисляется, попадает ли сфера окружения (BoudingSphere) объекта в усеченную пирамиду (frustum) камеры и если попадает, то объект будет рисоваться, если же не попадает то, соответственно объект отрисовываться не будет и как следствие отпадает необходимость производить расчеты и сравнения для потомков этого объекта.

Пример использования
Ниже приведен минимальный объем кода для отрисовки модели в XNA с использование графа сцены.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class SceneGraphSampleGame : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    ContentManager content;
    SceneGraph sceneGraph;
 
    // Конструктор
    public SceneGraphSampleGame()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }
 
    // Методы
    protected override void Initialize()
    {
        base.Initialize();
    }
 
    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        sceneGraph = new SceneGraph(graphics.GraphicsDevice);
 
        // Создание объекта для отображения модели
        ModelSceneNode modelNode = new ModelSceneNode(
                                        content.Load<Model>("Content/Ship"));
 
        // Присоединение объекта к графу сцены
        sceneGraph.RootNode.Children.Add(modelNode);
 
        // Создание камеры
        sceneGraph.Camera = new Camera();
        sceneGraph.Camera.Position = new Vector3(0, 0, 200);
    }
 
    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();
 
        // Обновление графа сцены
        if (sceneGraph != null)
            sceneGraph.Update(gameTime);
 
		// Обновление прочих компонентов
        base.Update(gameTime);
    }
 
    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
        // Отрисовка графа сцены
        if (sceneGraph != null)
            sceneGraph.Draw();
 
        // Отрисовка прочих компонентов
        base.Draw(gameTime);
    }
}

 

Как видно из кода граф сцены встраивается в основной цикл XNA. Сам граф сцены инициализируется в методе загрузки контента LoadGraphicsContent, там же инициализируется объект модели графа (ModelSceneNode) и камеры (Camera). Обновление и отрисовка графа вызывается в стандартных методах Update и Draw.

Управление элементами графа

Теперь реализуем управление элементами графа, так называемые контроллеры, которые будут отвечать за трансформации (передвижение, вращение, масштабирование) элементов в пределах графа. Класс контроллера реализует интерфейс IController и будет вызываться при обновлении элемента графа.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public abstract class ControllerBase : IController
{
    public abstract void UpdateSceneNode(SceneNode node, GameTime gameTime);
}
 
public class XRotationController : ControllerBase
{
    // Поля
    float radiansPerSecond;
 
    // Свойства
    public float RadiansPerSecond
    {
        get { return radiansPerSecond; }
        set { radiansPerSecond = value; }
    }
 
    // Конструктор по умолчанию
    public XRotationController()
    {
    }
 
    // Методы
    public override void UpdateSceneNode(SceneNode node, GameTime gameTime)
    {
        if (radiansPerSecond != 0.0f)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            float rotation = radiansPerSecond * elapsedTime;
            node.Rotation *= Quaternion.CreateFromYawPitchRoll(0, rotation, 0);
        }
    }
}
 
public class YRotationController : ControllerBase
{
    // Поля
    float radiansPerSecond;
 
    // Публичные свойства
    public float RadiansPerSecond
    {
        get { return radiansPerSecond; }
        set { radiansPerSecond = value; }
    }
 
    // Конструктор по умолчанию
    public YRotationController()
    {
    }
 
    // Методы
    public override void UpdateSceneNode(SceneNode node, GameTime gameTime)
    {
        if (radiansPerSecond != 0.0f)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            float rotation = radiansPerSecond * elapsedTime;
            node.Rotation *= Quaternion.CreateFromYawPitchRoll(rotation, 0, 0);
        }
    }
}
 
public class ZRotationController : ControllerBase
{
    // Поля
    float radiansPerSecond;
 
    // Свойства
    public float RadiansPerSecond
    {
        get { return radiansPerSecond; }
        set { radiansPerSecond = value; }
    }
 
    // Конструктор по умолчанию
    public ZRotationController()
    {
    }
 
    // Методы
    public override void UpdateSceneNode(SceneNode node, GameTime gameTime)
    {
        if (radiansPerSecond != 0.0f)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            float rotation = radiansPerSecond * elapsedTime;
            node.Rotation *= Quaternion.CreateFromYawPitchRoll(0, 0, rotation);
        }
    }
}

 

ControllerBase является абстрактным классом которые реализует интерфейс IController, он создан просто для удобства использования.

Классы XRotationController, YRotationController и ZRotationController обеспечивают вращение объекта графа. Коэффициент вращение определяется свойством RadiansPerSecond и пересчитывается в методе Update. Метод Update использует объединение кватернионов (операцией перемножения), для прибавления коэффициента вращения.

Ниже представленный код отображает изменения которые нужно внести в метод LoadGraphicContent основного класса Game для реализации использования контроллеров.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        sceneGraph = new SceneGraph(graphics.GraphicsDevice);
 
        ModelSceneNode modelNode = new ModelSceneNode(content.Load<Model>("Content/Ship"));
        sceneGraph.RootNode.Children.Add(modelNode);
 
        sceneGraph.Camera = new Camera();
        sceneGraph.Camera.Position = new Vector3(0,0,200);
 
        // Код добавленный для использования контроллера
        YRotationController rotationController = new YRotationController();
        rotationController.RadiansPerSecond = (float)Math.PI;
 
        modelNode.Controller = rotationController;
    }

 

После присвоения контроллера экземпляру объекта, он будет изменять данный объект без написания какого-либо дополнительного кода. В текущем примере модель будет вращаться по оси Y? полный оборот за 2 секунды.

Заключение

Итоги

Граф сцены помогает упростить и делает игровой код более логичным. Позволяет централизованно управлять поведением объектов и их отрисовкой. В дополнение ко всему вышесказанному, граф сцен очень легко можно дополнять новым функционалом, с минимальными трудозатратами.

Куда копать

Граф сцены можно (и нужно) дополнять новыми типами объектов и контроллеров, в приложенном к статье проекту вы найдете реализацию дополнительных элементов графа.

Известные ограничения и недоработки

Проверяйте чтобы дерево сцены не замыкалось само на себя, в текущем примере это не контролировалось. Указание потомком элемента, данного элемента может привести к переполнению стека при первом же вызове рекурсивной функции.

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

1065 Прочтений •  [Создание графа сцены для XNA] [08.08.2012] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• Создание графа сцены для XNA Ukraine Vova 08.08.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка