Показаны сообщения с ярлыком video. Показать все сообщения
Показаны сообщения с ярлыком video. Показать все сообщения

суббота, 15 октября 2011 г.

"GB&W Lite" [wp7][game][release]

Выпустил лайт версию игры GB&W.



Вот видео с мастер классом по прохождению 19го уровня:



игру можно найти тут: 


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

Оказалось, при первой публикации лайт версии, GB&W занимает в памяти более 90 МБ (на сколько не скажу). Очень много анимированной растровой рафики. Лайт версию пришлось немного порезать. Получается для GB&W мне в свое время сделали скидку :).

понедельник, 13 июня 2011 г.

GB&W - Update v1.4

Это уже 4-е обновление.

Сейчас доступно:
- 40 уровней.
- 14 типов кирпичей
- 14 бонусов

Одна из последних добавленный пакостей это кирпич с кодовым названием "Биомасса". Он не прерывно плодиться с постоянной скоростью, кроме того он подвержен влиянию 2х бонусов:
- катализатор, единовременно ускоряющий рост общего объема биомассы
- заморозка, соответственно временно останавливающий рост биомассы.

Вот новое видео:

среда, 18 мая 2011 г.

GB&W и Конкурс мобильных приложений

С начала главный вопрос на повестке дня).

Сегодня зарегистрировал свой проект в конкурсе мобильных приложений под Windows Phone 7 на сайте конференции DevCon•11. В конкурсе участвует следующее видео:


Ребят у меня к вам просьба - кому симпатичен данный проект, пожалуйста не пожалейте 5 секунд своего времени, проголосуйте за него, для меня важен каждый Ваш голос. Ниже кнопочка для голосования:

Заранее благодарен.

Наконец то завершена работа над первым релизом игры. Почему первым? Потому что в планах добавлять уровни в следующих обновлениях. Сейчас приложение находится на этапе публикации в Marketplace.

суббота, 23 апреля 2011 г.

GB&W - Windows Phone 7 game preview 3

Не пугайтесь обилию выпадающих бонусов. Это один из первых десяти обучающих уровней. Десятка разбита по применению тематических бонусов их комбинаций.
В этом уровне первый раз появляется усиление на пулемет, который в свою очередь превращается в нечто иное :).

Рекомендую смотреть в качестве 720p (сейчас 480p)



Мне часто задают вопрос - как происходит управление в игре и как целиться? Все просто. Кораблик управляется одним касанием и постоянно находится под пальцем. Пулеметы наводятся на ближайшую цель в радиусе поражения. Вторым касанием на кнопки в верхней панели активируется тяжелое вооружение:
ракета I - открыть/закрыть подвеску, для экономии боезапаса. Само наводится и поражает ближайшего бота. При потере цели в процессе подлета (цель уничтожена др. ракетой и т.д.) находит и атакует следующую ближайшую.
ракета II - пуск. Само наводится и поражает/запечатывает ближайшую шахту из которой появляются боты.
ракета III - активация ракеты. Второе нажатие в области экрана помечает область поражения и происходит старт. Так же взрывается от столкновения с кирпичами.

Я потратил какое то время на изменение своего Touch класса. Теперь он понимает второе касание типа Tap при активном первом касании. Т.е. можно не прерываясь контролить кораблик и активировать ракетные бонусы.

среда, 23 марта 2011 г.

"Guns, Balls & Walls" - Windows Phone 7 game preview 2

Делюсь очередным видео. Музыкальное сопровождение отключено по политическим соображениям. Еще нет четкой договоренности с композитором.

понедельник, 7 марта 2011 г.

"Guns, Balls & Walls" - Windows Phone 7 game preview

Игра предназначается для Windows Phone 7 marketplace.
Cуть игры - смешанный коктейль трех направлений:
1) арканоид - основная идея и условия прохождения уровня.
2) аэрохоккей - расширенные правила взаимодействия биты(battleship) и мяча
3) хардкорный 2d шутер - пулеметы, ракеты, враги, кровь, взрывы ... боже дай мне сил остановиться :))).

Отладочный уровень:


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

В целом данный проект является экспериментом, в том числе и в 2d.
Очень много времени уходит на рисование, особенно что касается на первый взгляд не заметных деталей таких как кровь на решетках вентиляторов и т.д. . Примерное соотношение времени = (день рисую) / (час программирую). С самим вопросом рисования проблем нет, но не набита рука, плюс, например, если в карандаше я нарисую все что угодно, то ощущение цвета нужно еще нарабатывать. Радует то, что по мере работы прокачка движется. Мега респект создателям графического редактора Paint.net

Windows Phone 7 радует своими возможностями. По предварительным подсчетам, в данном приложении, запас на частицы порядка 4000 штук. Возможно при желании у меня получится и больше. Время покажет.

четверг, 14 октября 2010 г.

GPF - "WPF" for XNA

GPF - на таком рабочем названии библиотеки я остановился.

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

Пока не стал возиться с наложением форм на не плоские поверхности по
причине того, что это нарушит совместимость с Windows Phone 7 экземпляром библиотеки.

Вот такое видео:



Показал Expander, DataGrid, Table.
Со стилями элементов опять не поиграл. Оставил на потом)

суббота, 9 октября 2010 г.

XNA. gEngine. Forms (GUI)

Вот и созрел я до первого показа своего интерфейса для приложений реализованных на базе XNA. Как говорится лучше один раз увидеть …, так не буду Вас задерживать:

Рекомендую смотреть в HD режиме.


Данное видео не показывает всех элементов и возможностей. Опубликовал по многочисленным заявкам. За продолжением следите в следующих сериях.

Идея архитектуры, данного интерфейса, базируется на архитектуре предложенной в WPF. Но ядро и элементы написаны с нуля и оптимизированы под 3d. Так же данная библиотека работает и на Windows Phone 7.
Список уже реализованных элементов выглядит следующим образом:
- Button
- Canvas
- CheckBox
- CheckElement
- ConsoleOutput
- DataGrid
- Expander
- Image
- ListSelector
- Menu
- ProgressBar
- ScrollBar
- ScrollDiagram2d
- ScrollView
- Slider
- StackPanel
- Switch
- TabControl
- Table
- TextBlock
- TextBox
В этот список попали не характерные для WPF элементы, что было продиктовано первоочередной необходимостью реализации отображения функционала 3d движка.
В представленном видео все элементы и формы выводятся с простым базовым стилем. Под базовым стилем подразумевается (если есть) прямоугольная рамка и (если есть) прямоугольник фона. Стиль любого элемента достаточно просто меняется наследованием от него нового нового класса. Я пока не стал перегружать рабочую версию интерфейса надуманным стилем и растровой графикой, бесполезная трата времени на то что в последствии не пригодится.

среда, 19 мая 2010 г.

Windows Phone 7 + XNA 4.0 + Test Game

Поигрался с Windows Phone 7, начал с проверки возможностей 2D, вот что получилось:

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

воскресенье, 21 февраля 2010 г.

#1 XnaDevRuEngine - 3d Max Export Plugin

Заработал мой плагин экспорта из 3d Max. Были сложности с взаимодействием костей, но упорство, блокнот и карандаш все решили.

четверг, 4 февраля 2010 г.

#0 XnaDevRuEngine

Мои коллеги, с которыми меня объединяет деятельность в рамках ресурса xnadev.ru, и я, начали работу над 3D движком XnaDevRuEngine. Если не брать в расчет наработки по модулю интерфейса (forms), которые ранее существовали как самостоятельный проект, то следующее видео можно считать первым, демонстрирующим XnaDevRuEngine:

Сейчас частично готовы модули SceneTree и прототип ResorceManager.

суббота, 29 августа 2009 г.

XNA: Water video

Рекомендую смотреть в режиме HD 1024x768



В данном исполнении нет каустики. Но сейчас я заинтересовался этой темой, нагреб кучу инфы, изучаю ... пробую.
Пока мои изыскания выглядят так:



Т.е. простое вычисление в один (сильно тяжелые вычисления для real time) проход на CPU.

Пока делал первое видео, в глаза бросилась вот какая штука. Изначально видео с водичкой весило 2,092 ГБ, конвертировал при помощи Camtasia Studio и как то сильно быстро изменялся прогресс конвертирования. Посмотрел загрузку процессоров ... и о чудо.



Camtasia Studio умеет распределять вычисления на все доступные процессоры.
Конвертация прошла в real time режиме :). Очень порадовало!

воскресенье, 21 июня 2009 г.

Terrain Geomorphing in the Vertex Shader

Читал несколько статей на эту тему. Искал с рабочими примерами (желательно на XNA + HLSL), конкретно с пред расчетом и готовым шейдером. Но нашел только много теории и не для XNA и DirectX, а в общем. Написано умно, ничего не понял. Конкретно озадачив себя, просидел как всегда допоздна. На утро, проснулся с готовым представлением о содержимом шейдера. Мне повезло.



Демонстрация:



И так по порядку.
Рассмотрим вот такую картинку:



Здесь изображен процесс перехода между уровнями детализации ландшафта.
черным цветом - контур геометрии предыдущего слоя детализации;
синим цветом – его вершины;
красным цветом – вершины нового уровня детализации.
зеленым цветом – выделен контур новой геометрии с учетом достроенных вершин, в следствии разбиения;
фиолетовым цветом – вершины середин отрезков между вершинами предыдущего слоя детализации;
красные вектора в низ – delta вектора разности между серединами отрезков вершин предыдущего слоя и соответствующими им новыми вершинами. Дальше по тексту разъясню подробнее.

Что из себя представляет «Terrain Geomorphing in the Vertex Shader»?
Если посмотреть более пристально на видео пример к моей предыдущей статье "Procedural Landscape on XNA Game Studio 3.0", где нет геоморфинга,то можно увидеть как «выпрыгивает» (новый научный термин) новая геометрия, при наезде друг на друга слоев с различной детализацией.

Это не есть good!

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

Нам понадобится следующее описание формата вершин для хранения выше описанных данных:



namespace gEngine.gProgressiveLandscape
{
public struct gplVertexPositionNormalTexture
{

public Vector3 Position;
public Vector3 PositionGeomorphing;
public Vector3 Normal;
public Vector3 NormalGeomorphing;
public Vector2 TextureCoordinate;
public float IndexDetailedLayer;


public static readonly VertexElement[] VertexElements;

static gplVertexPositionNormalTexture()
{
VertexElements = new VertexElement[6];
short offset = 0;
// Position
VertexElements[0] = new VertexElement(0, offset,
VertexElementFormat.Vector3,
VertexElementMethod.Default,
VertexElementUsage.Position, 0);
offset += (short)Marshal.SizeOf(new Vector3());
// PositionGeomorphing
VertexElements[1] = new VertexElement(0, offset,
VertexElementFormat.Vector3,
VertexElementMethod.Default,
VertexElementUsage.Position, 1); // !
offset += (short)Marshal.SizeOf(new Vector3());
// Normal
VertexElements[2] = new VertexElement(0, offset,
VertexElementFormat.Vector3,
VertexElementMethod.Default,
VertexElementUsage.Normal, 0);
offset += (short)Marshal.SizeOf(new Vector3());
// NormalGeomorphing
VertexElements[3] = new VertexElement(0, offset,
VertexElementFormat.Vector3,
VertexElementMethod.Default,
VertexElementUsage.Normal, 1); // !
offset += (short)Marshal.SizeOf(new Vector3());
// TextureCoordinate
VertexElements[4] = new VertexElement(0, offset,
VertexElementFormat.Vector2,
VertexElementMethod.Default,
VertexElementUsage.TextureCoordinate, 0);
offset += (short)Marshal.SizeOf(new Vector2());
// NamberDetailedLayer
VertexElements[5] = new VertexElement(0, offset,
VertexElementFormat.Single,
VertexElementMethod.Default,
VertexElementUsage.TextureCoordinate, 1); // !
}

public gplVertexPositionNormalTexture( Vector3 position,
Vector3 positionGeomorphing,
Vector3 normal,
Vector3 normalGeomorphing,
Vector2 textureCoordinate,
float indexDetailedLayer)
{
this.Position = position;
this.PositionGeomorphing = positionGeomorphing;
this.Normal = normal;
this.NormalGeomorphing = normalGeomorphing;
this.TextureCoordinate = textureCoordinate;
this.IndexDetailedLayer = indexDetailedLayer;
}

public static int SizeInBytes
{
get
{
return (int)( Marshal.SizeOf(new Vector3()) +
Marshal.SizeOf(new Vector3()) +
Marshal.SizeOf(new Vector3()) +
Marshal.SizeOf(new Vector3()) +
Marshal.SizeOf(new Vector2()) +
sizeof(float));
}
}
}
}


Здесь PositionGeomorphing и есть то поле для хранения вектора смещения.

Нечто похожее делаем и с нормалями.

Все волшебство произойдет в шейдере!

Куда мы передадим дополительную информацию о:
float3 vEyePosition; - положении камеры
float layerRadius[7]; - реальные размеры уровней детализации

Для каждой вершины будем считать удаление от камеры, по ее индексу выбирать данные, из массива размеров уровней детализации, для расчета коэффициента затухания вектора PositionGeomorphing.

Сам шейдер выглядит следующим образом:



float4x4 matWorld : WORLD;
float4x4 matWVP : WORLDVIEWPROJECTION;

float3 vLightPosition;
float3 vEyePosition;

float layerRadius[7];

float fogBegin = 200.0f;
float fogEnd = 400.0f;

struct VS_INPUT
{
float3 Position : POSITION0;
float3 PositionGeomorphing : POSITION1;
float3 Normal : NORMAL0;
float3 NormalGeomorphing : NORMAL1;
float2 Texcoord : TEXCOORD0;
float IndexDetailedLayer : TEXCOORD1;
};

struct VS_OUTPUT
{
float4 Position : POSITION0;
float2 Texcoord : TEXCOORD0;
float3 Light : TEXCOORD1;
float3 Normal : TEXCOORD2;
float Fog : TEXCOORD3;
};

VS_OUTPUT VS(VS_INPUT In)
{
VS_OUTPUT Out = ( VS_OUTPUT ) 0;
float Distance = length ( In.Position - vEyePosition );
float K = clamp ((( Distance / layerRadius[In.IndexDetailedLayer] - 0.5f ) * 2.0f ), 0.0f, 1.0f );
Out.Position = mul ( float4(In.Position + In.PositionGeomorphing * K, 1.0f ), matWVP );
Out.Fog = clamp ((( 1.0f - (Distance - fogBegin) / fogEnd) - 0.5f) * 2.0f, 0.0f, 1.0f);
//Out.Fog = 1.0f;
Out.Texcoord = In.Texcoord;
Out.Light = normalize ( mul(vLightPosition, matWorld) );
Out.Normal = normalize ( mul( In.Normal + In.NormalGeomorphing * K, matWorld ) );
return Out;
}

texture tex;
sampler2D sTexture = sampler_state
{
Texture = (tex);
};

float spec = 0.5f;

float4 PS(VS_OUTPUT In) : COLOR0
{
float4 specColor = tex2D( sTexture, In.Texcoord ) * spec;
float4 diffColor = clamp( tex2D( sTexture, In.Texcoord ) * dot( In.Normal, In.Light ), 0.0f, 1.0f );
float4 color = float4(1.0f, 1.0f, 1.0f, 1.0f) * (1.0f - In.Fog) + (diffColor + specColor) * In.Fog;
return color;
}

technique TerrainGeomorphing
{
pass Pass1
{
VertexShader = compile vs_3_0 VS();
PixelShader = compile ps_3_0 PS();
}
}


Да, в шейдере добавлен расчет тумана, его можно выбросить. Он влияет только на текстурирование.

Оригинальный блог

Procedural Landscape on XNA Game Studio 3.0

Динамический ландшафт



Демонстрация:



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

Закончил эту часть работы давно. Даже успели обсудить на xnadev.ru . Сейчас данный проект уже несколько раз преобразился. Возможно, в скором времени, дойдут руки сделать новое видео. Как раз будет повод рассказать о том, что из себя представляет «Terrain Geomorphing in the Vertex Shader» и с чем его едят. Пока расскажу об этом этапе.

Как это делалось?

Описал представление слоев детализации и данных о вершинах.
Карта логики представления слоев детализации выглядит так:



Карта логики связывания вершин слоев детализации в треугольники, с учетом связей между соседними слоями выглядит так:



На обеих картинках цвета слоев не совпадают. Лень переделывать. Просто остались наработанные картинки, которые изначально не предназначались для статьи.

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

private void backgroundWorker_DoWork
(object sender, DoWorkEventArgs e)
{
PartitionLevels();
geometry.InitIndex();
geometry.GenNormal();
}

- разбиение слоев детализации, добавление новых вершин (и корректировка их высот) в единый массив вершин;
- инициализация единого массива индексов, связывающих все треугольники (вершины), всех слоев детализации.
- генерация нормалей.

На пальцах все это выглядит просто, для оценки реализации приведу пример рекурсивного метода, рассчитывающего интервал значений индексного массива, соответствующего ветке дерева визуализации нулевого слоя детализации.
Честное слово, мне проще код писать, чем слова в предложения собирать. Не ругайте сильно, но по другому мне сложно коротко сформулировать ту кучу "каракуль", которыми я исписал свой блокнот, занимаясь данной темой.
Нулевым в данном случае является слой наименьшей детализации. Что бы окончательно Вас запутать. Скажу что понятия уровней детализации и дерева детализации тесно сплетены между собой. Дерево это восходящие, из слоя нулевой детализации, ветви связей перпендикулярно пересекающие по иерархии старшинства следующие уровни (плоскости) детализации, разделяясь в точке пересечения на четыре наследника. Потому Quad tree. Зачем все так сложно? Зачем представление в виде дерева и плоскостей? Все просто. Каждое представление для выполнения различных задач. Каждые задачи наиболее быстро выполняются только в одном из представлений. Плоскости для линейных задач, дерево для рекурсивных и отслеживания наследственных связей. Выше упомянутый обещанный рекурсивный метод возвращает все индексы всех треугольников ограниченных габаритами одной ветки нулевого слоя детализации.

Блок схема обещанного метода:



Блок схема автоматически сгенерирована примочкой к Visual Studio под названием «Microsoft Visual Studio Learning Pack 2.0»

Код метода:



Код метода:
///
/// Рекурсивная сборка индексов отдельной ветки дерава уровней детализации ландшафта
///
private void InitNodeIndex (gplNode inNode, ref int inIndex)
{
// --- уровень детализации ---------------------------------------
int l = inNode.Level;
// --- индекс активной ветки --------------------------------------
int i = inNode.Index;
// --- размеры активного уровня детализации -----------------------
int w = levelInfo[l].W;
int h = levelInfo[l].H;
// --- признаки соединение со слоем более низкой детализации ------
bool bLeft = false;
bool bRight = false;
bool bUp = false;
bool bDown = false;
// --- индексные направления слоя для псевдодвухмерной карты ------
gxplTrends trends = new gxplTrends();
trends.NewTrends(i, w);
// --- если ветка не разбита ----------------------------------------------------------------------------------------
if (inNode.NodeChildren == null)
{
// --------------------------------------------------------------------------------------------------------------
#region --- собираем два треугольника ---------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
// - 1й треугольник -----------------------
indices[inIndex + 0] = trends.Center;
indices[inIndex + 1] = trends.Right;
indices[inIndex + 2] = trends.Down;
// - 2й треугольник -----------------------
indices[inIndex + 3] = trends.Down;
indices[inIndex + 4] = trends.Right;
indices[inIndex + 5] = trends.DownRight;
inIndex += 6;
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
}
// --- если разбита -------------------------------------------------------------------------------------------------
else
{
// --------------------------------------------------------------------------------------------------------------
#region --- определение режима соединения с соседними ветками ---------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
// --- check left join --------------------------------------------
//if (!bNoLeft)
bLeft = (inNode.Coord.X > levelInfo[l].SX0) ?
map[trends.Left].NodeChildren == null : true;
// --- check right join -------------------------------------------
//if (!bNoRight)
bRight = (inNode.Coord.X < levelInfo[l].SX0 + levelInfo[l].W - 1) ?
map[trends.Right].NodeChildren == null : true;
// --- check up join ----------------------------------------------
//if (!bNoUp)
bUp = (inNode.Coord.Y > levelInfo[l].SY0) ?
map[trends.Up].NodeChildren == null : true;
// --- check down join --------------------------------------------
//if (!bNoDown)
bDown = (inNode.Coord.Y < levelInfo[l].SY0 + levelInfo[l].H - 1) ?
map[trends.Down].NodeChildren == null : true;
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
#region --- сборка всех треугольников с учетом связей различных слоев детализации -------------------------------
// --------------------------------------------------------------------------------------------------------------
// --- индексные направления слоя +1 для псевдодвухмерной карты -------------------------
gxplTrends trends4x3 = new gxplTrends(inNode.NodeChildren[3].Index, levelInfo[l + 1].W);
// --------------------------------------------------------------------------------------------------------------
#region --- если с лева соединение с более высокой детализацией --------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
if (bLeft)
{
indices[inIndex + 0] = trends.Center;
indices[inIndex + 1] = trends4x3.Center;
indices[inIndex + 2] = trends.Down;
inIndex += 3;
// --- если с верху нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bUp)
{
indices[inIndex + 0] = trends.Center;
indices[inIndex + 1] = trends4x3.Up;
indices[inIndex + 2] = trends4x3.Center;
inIndex += 3;
}
// --- если с низу нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bDown)
{
indices[inIndex + 0] = trends.Down;
indices[inIndex + 1] = trends4x3.Center;
indices[inIndex + 2] = trends4x3.Down;
inIndex += 3;
}
}
else // если нет соединение с более высокой детализацией, то переходим к следующему уровню детализации
{
if (!bUp) // Х0
InitNodeIndex(inNode.NodeChildren[0], ref inIndex); // 00

if (!bDown) // 00
InitNodeIndex(inNode.NodeChildren[2], ref inIndex); // Х0
}
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
#region --- если с права соединение с более высокой детализацией ------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
if (bRight)
{
indices[inIndex + 0] = trends.Right;
indices[inIndex + 1] = trends.DownRight;
indices[inIndex + 2] = trends4x3.Center;
inIndex += 3;
// --- если с верху нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bUp)
{
indices[inIndex + 0] = trends4x3.Center;
indices[inIndex + 1] = trends4x3.Up;
indices[inIndex + 2] = trends.Right;
inIndex += 3;
}
// --- если с низу нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bDown)
{
indices[inIndex + 0] = trends4x3.Center;
indices[inIndex + 1] = trends.DownRight;
indices[inIndex + 2] = trends4x3.Down;
inIndex += 3;
}
}
else // если нет соединение с более высокой детализацией, то переходим к следующему уровню детализации
{
if (!bUp) // 0Х
InitNodeIndex(inNode.NodeChildren[1], ref inIndex); // 00

if (!bDown) // 00
InitNodeIndex(inNode.NodeChildren[3], ref inIndex); // 0Х
}
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
#region --- если с верху соединение с более высокой детализацией ------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
if (bUp)
{
indices[inIndex + 0] = trends.Center;
indices[inIndex + 1] = trends.Right;
indices[inIndex + 2] = trends4x3.Center;
inIndex += 3;
// --- если с лева нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bLeft)
{
indices[inIndex + 0] = trends.Center;
indices[inIndex + 1] = trends4x3.Center;
indices[inIndex + 2] = trends4x3.Left;
inIndex += 3;
}
// --- если с права нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bRight)
{
indices[inIndex + 0] = trends4x3.Center;
indices[inIndex + 1] = trends.Right;
indices[inIndex + 2] = trends4x3.Right;
inIndex += 3;
}
}
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
#region --- если с низу соединение с более высокой детализацией -------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
if (bDown)
{
indices[inIndex + 0] = trends.Down;
indices[inIndex + 1] = trends4x3.Center;
indices[inIndex + 2] = trends.DownRight;
inIndex += 3;
// --- если с лева нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bLeft)
{
indices[inIndex + 0] = trends4x3.Center;
indices[inIndex + 1] = trends.Down;
indices[inIndex + 2] = trends4x3.Left;
inIndex += 3;
}
// --- если с права нет! соединения с более высокой детализацией (добавочный треугольник)
if (!bRight)
{
indices[inIndex + 0] = trends4x3.Center;
indices[inIndex + 1] = trends4x3.Right;
indices[inIndex + 2] = trends.DownRight;
inIndex += 3;
}
}
//else
//{
//
//}
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
#endregion ------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
}
}


Свои задачи данная разработка уже выполнила. Для себя дальнейшие пути развития данной идеи я вижу два:
1) Растачивать дальше в этом направлении. Реализовать динамическую подгруздку данных о высотах с диска. Есть расчетные таблицы. Разработан алгоритм быстрого обновления кэшей высот к уровням детализации, без смещения (move) данных. Это позволит работать с ландшафтами огромного размера. Приведу пример расчета размеров LOD’ов для карты 1310.72^2 км с максимальной детализацией до 10^2 м:



2) Для игр. Придется переделать исходную коллекцию массивов высот в один. И реализовать новую выборку.

Вот как то так.

Оригинальный блог