Навигация
· XNA FAQ
· С чего начать
· Конкурсы
· Обратная связь
· XNA Блоги
Сейчас на сайте
· Гостей: 1

· Пользователей: 0

· Всего пользователей: 3,684
· Новый пользователь: headron
Последние фото
Эх, чуть не проспал закрытие.
Эх, чуть не проспал ...
Альбом: XNA Engine

GB
GB
Альбом: XNA Engine

South Park Coon & Friends
South Park Coon & Fr...
Альбом: XNA Games

Блоги
yavshoke
» XboxOne - интерес...
dampirik
» Push уведомления ...
dampirik
» Реклама,статистик...
Chort
» XNA и StartCoroutine
Chort
» Curve Class
dampirik
» Реклама, статисти...
dampirik
» Увеличение скорос...
dampirik
» Реклама, статисти...
general
» Распаковка DxtCom...
general
» Как работать с XN...
Поддержка
microsoft.com
1gb.ru - Дом для вашего сайта
Статистика посещений:

Использование Vertex Textures в XNA

Урок, рассматривающий основы работы с Vertex Textures Fetch в XNA. Фактически это не один урок, а целых четыре, материала очень много, но интересно. Одним из плюсов является то, что автор (Catalin Zima) постарался расписать каждую строку кода, почему сделано именно так и что для чего надо, таким образом набрать исходный код можно и не прибегая к прилагающимся к уроку исходникам. Кто все же решит досконально пройти весь урок и набрать весь исходный код сам, небольшой совет – сохраняйте состояния проектов (делайте копии, используйте SVN и т.п.) перед каждой из частей и конце их, ибо замечены несколько прецедентов «отката» состояния проекта на предыдущее состояние. В тексте переведены все комментарии к исходным кодам как C#, так и HLSL, прилагаемые исходники взяты с англоязычного ресурса и там все комментарии на английском.


Вступление

Данная статья описывает четыре метода использования Вершинных Текстур (Vertex Textures) в XNA играх. Начнем мы с краткого описания вершинных текстур, что это такое и как ими пользоваться, затем реализуем четыре эффекта с их использованием, от простейшего до довольно сложных реализаций. В статье будет детально расписан каждый шаг написания программ и объяснено, почему выбрана именно эта реализация и какие техники могут быть применены для решения подобных задач. Некоторые части будут содержать дополнения с разъяснениями как использовать те или иные подходы реализации в других подобных задачах, даже если они не связаны с Vertex Texture Fetching (далее по тексту просто VTF).


Вершинные Текстуры


С момента появления программируемых графических процессоров в их архитектуру было изначально заложено, что вершинный и пиксельный шейдеры имеют различные характеристики. В шейдерной модели 3.0 были сделаны первые шаги для объединения их функциональности. DirectX 10 сделал последний шаг и объединил набор инструкций между всеми типами шейдеров: пиксельными (Pixel), вершинными (Vertex) и новыми геометрическими (Geometry) шейдерами. Основной темой данной статьи будет Vertex Texture Fetch (VTF), одна из фичей третьей шейдерной модели (Shader Model 3.0), которая в свою очередь послужила началом этой унификации.
VTF позволяет нам читать информацию из текстуры в вершинный шейдер, почти так же, как это делает пиксельный шейдер. Чтобы использовать функциональность VTF Вам потребуется XBOX 360 (у которого унифицированная шейдерная архитектура) или графическая карта NVIDIA серии GeForce 6 или выше. Для владельцев видеоадаптеров от ATI, для достижения подобного результата применима технология R2VB – отрисовка в вершинный буфер (Render To Vertex Buffer), но я не знаю, как использовать данную технологию в XNA. (Вот тут можно прочитать как сэмулировать VTF программно, для пользователей адаптеров ATI).
Ассемблерная функция графического процессора для чтения текстуры в вершинный шейдер – «texldl», в HLSL, который и будет использоваться, ее аналогом является – «tex2Dlod». Параметры вызова - tex2Dlod( s, t ), где «s» - 2D текстурный самплер и «t» - четырехмерный вектор (float4). При чтении текстуры mipmap уровень указывается вручную, путем задания четвертого компонента вектора (t.w). В большинстве случаев используется 0 уровень (текстура будет считана, как есть), так что вызов будет выглядеть примерно следующим образом - tex2Dlod(textureSampler, float4(uv.xy,0,0)).
Поведение вершинной текстуры аналогично текстурам в пиксельных шейдерах, за исключением:

  • Билинейная (Bilinear) и трилинейная (Trilinear) фильтрация не поддерживается на аппаратном уровне. Далее будет рассмотрено, как реализовать билинейную фильтрацию в вершинном шейдере.
  • Анизотропная (Anisotropic) фильтрация не поддерживается на аппаратном уровне.
  • Автоматический расчет mipmap уровня не производится и если необходимо, расчет нужно реализовывать самим.

 

Необходимые ресурсы и код

Прежде чем мы начнем, скачайте архив Resources.zip, который содержит:

  • Две карты высот, .dds в формате R32F (каждый пиксель записан в 32 битный float и содержит информацию о высоте).
  • Примечание: видеокарты NVIDIA поколения 6 и 7 для VTF поддерживают только R32F и A32R32G32B32F форматы. Возможно GeForce 8 и XBOX 360 могут для VTF использовать и другие форматы, но у меня нет возможности проверить это.
  • Несколько текстур взятых с turbosquid.com и прочих уроков и примеров.
  • Camera.cs является компонентом (GameComponent), который реализует игровую камеру, взят из примера Skinned Model Sample.
  • Используйте триггеры на контроллере или клавиши Z и X клавиатуры для зума камеры.
  • Правый стик или клавиши WASD для перемещения камеры.
  • Grid.cs класс для отрисовки сетки в плоскостях XZ.
  • DudeModel.zip будет использован в четвертой части.

 

Эти ресурсы будут использованы в данном уроке, и исходный код будет содержать ссылки на эти файлы.
Grid.cs


Данный класс реализует геометрию сетки и будет использован в Heightmap Rendering, Terrain Morphing и Steps in Snow. Свойство CellSize отвечает, на сколько большими будут ячейки сетки, а свойство Dimension контролирует размерность сетки (сколько строк, столбцов). Каждая вершина содержит информацию о позиции, нормали и соответствующей текстурной координате. Таким образом, каждая вершина ссылается (мапится) на пиксель в текстуре и это будет использовано в вершинном шейдере для манипуляции вершинами. Механизм ассоциации между вершиной и пикселем текстуры, является ключевым при использовании VTF. Изначально высота для всех вершин установлена в 0, так что мы имеем идеально гладкую поверхность, в этом можно убедиться, посмотрев в функцию GenerateStructures (строка 46, кода Grid.cs).

 

vert.Position = new Vector3((i - dimension / 2.0f) * cellSize, 
 0, (j - dimension / 2.0f) * cellSize);
 

 


 

I. Отрисовка ландшафта, используя карту высот

Начнем мы с простого примера - отрисовки ландшафта, используя карту высот. Карта высот (heightmap) это изображение (оттенки серого), содержащее информацию о высотах. Чем темнее оттенок пикселя, тем ниже данный участок поверхности, соответственно, чем светлее, тем выше. Так как мы используем текстуру, которая содержит данные с плавающей точкой, то 0,0 – минимальная высота, а 1,0 – означает максимальную высоту. На самом деле построить ландшафт по карте высот можно и без использования вершинных текстур, просто прочитав карту высот на этапе загрузки и на основе ее данных построить буфер вершин. А так как эта операция производится только один раз (в момент загрузки), а не каждый кадр (в вершинном шейдере) использование вершинных текстур для решения подобных задач, в плане производительности приложения, несколько нелогично. Как бы то ни было, это является простейшей и относительно легкой в реализации демонстрацией использования VTF.
Начнем с создания нового проекта (Windows или Xbox360) и добавим в проект файлы Camera.cs и Grid.cs. Затем идем в основной класс созданного проекта (Game1.cs) и добавляем пространство имен VTFTutorial в объявления using.

 

using VTFTutorial;

 

Теперь добавляем две новые переменные в класс Game1: одну для камеры и одну для сетки. Инициализируем их и указываем параметры в конструкторе класса. Камера должна быть добавлена в список компонентов, т.к. является игровым компонентом и за изменения состояний камеры и ее обновление теперь будет отвечать компонентная модель XNA. Так же мы должна задать параметры сетки CellSize и Dimension, 4 и 256 соответственно. Вы можете проиграться с параметром CellSize и повыставлять ему различные параметры, просто ради спортивного интереса «А что будет?». О том, что произойдет если выставить другие параметры свойству Dimension, мы поговорим четь позже. Теперь в методе LoadGraphicsContent добавьте вызов grid.LoadGraphicsContent().

 

Camera camera;
Grid grid;
 
public Game1()
{
	graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
 
        camera = new Camera(this);
        this.Components.Add(camera);
 
        grid = new Grid(this);
        grid.Dimension = 256;
        grid.CellSize = 4;
}
 
protected override void LoadGraphicsContent(bool loadAllContent)
{
	if (loadAllContent)
        {
	}
 
        grid.LoadGraphicsContent();
}

Итак, у нас есть геометрия, теперь нам необходимо создать файл эффекта (шейдера) который нам создаст и отресует ландшафт. Добавьте в проект новую папку с именем «Shaders», затем в эту папку добавьте новый текстовой файл (Add -> New Item...) с именем «VTFDisplacement.fx». Откройте его и приступим к написанию кода шейдера на языке HLSL (High Level Shading Language).

Нам необходимы 3 параметра матрицы, для матриц мира (world), вида (view) и проекции (projection). Затем мы должны будем добавить карту высот с именем displacementMap (карта смещения, так как именно в ней содержится информация о смещении вершин относительно плоскости XZ) и самплер дня нее. Самплер будет использоваться для чтения данных высоты из карты высот в вершинном шейдере. Для всех фильтров с самплере используется значение Point, т.к. линейный (Linear) и анизотропный (Anisotropic) не поддерживается для вершинных текстур. Даже если прописать другое значение для фильтров, никаких сообщений об ошибках выедено не будет, но использоваться все равно будет значение Point.

float4x4 world; // матрица мира
float4x4 view; // матрица вида
float4x4 proj; // матрица проекции
 
// максимальная высота для ландшафта
float maxHeight = 128;
 
//текстура карты высот
texture displacementMap;
 
// самплер для чтения карты высот
sampler displacementSampler = sampler_state     
    {
            Texture   = <displacementMap>;
            MipFilter = Point;
            MinFilter = Point;
            MagFilter = Point;
 
            AddressU  = Clamp;
            AddressV  = Clamp;
    };

Далее создадим две структуры, одна будет описывать данные, поступающие на вход вершинному шейдеру, вторая данные на выходе из него. На вход мы будем подавать местоположение вершины (position) и ее текстурные координаты (uv), на выходе мы будем получать трансформированные вершины в пространстве, а так же будем передавать в пиксельный шейдер еще один «комплект» координат вершины в переменной worldPos для «раскрашивания» основываясь на данных высоты вершин. Текстурные координаты будем просто «туннелировать» через вершинный шейдер в пиксельный, оставляя без изменений.

 

    struct VS_INPUT 
    {
        float4 position : POSITION;
        float4 uv       : TEXCOORD0;
    };
 
    struct VS_OUTPUT
    {
        float4 position  : POSITION;
        float4 uv        : TEXCOORD0;
        float4 worldPos  : TEXCOORD1;
    };

 

 

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

 

    VS_OUTPUT Transform(VS_INPUT In)
    {
        // инициализация выходной структуры
        VS_OUTPUT Out = (VS_OUTPUT)0;
 
        //расчет матрицы произведения View * Projection
        float4x4 viewProj = mul(view, proj);
 
        //финальный расчет матриц для вывода на экран World * View * Projection
        float4x4 worldViewProj= mul(world, viewProj);
 
        // Данная инструкция читает карту высот
        // в соответствии с текстурными координатами вершины
 
        // Примечание: мы передаем как параметр 0 уровень mipmap в tex2Dlod,
        // т.к. хотим чтобы изображение использовалось 1 к 1
        float height = tex2Dlod ( displacementSampler,
                                  float4(In.uv.xy , 0 , 0 ) );
        // После считывания данных высоты с текстуры
        // мы присваиваем это значение в y координаты вершины
        // и т.к. значение height лежит в диапазоне от 0 до 1,
        // то перемножаем с переменной maxHeight, которая в
        // свою очередь отвечает за максимальный подъем ландшафта
        In.position.y = height * maxHeight;
 
        //Передаем в пиксельный шейдер координаты вершины в мировом пространстве
        Out.worldPos = mul(In.position, world);
 
        //Расчитываем финальное местоположение вершины уже для вывода на экран
        Out.position = mul( In.position, worldViewProj);
 
        //Текстурные координаты передаем без изменений
        Out.uv = In.uv;
 
        return Out;
    }

Функция tex2Dlod читает данные высот из текстуры, использую текстурные координаты которые создаются в классе Grid.cs. Перед тем как координаты вершины будут перемножены со всеми матрицами для вывода на экран, мы подменим данные координаты Y, на этом этапе вершины будут выстроены по высоте в соответствии с данными карты высот и только потом произойдет преобразование вершин в экранные координаты. Все эти действия выполняет графический процессор.

Настало время позаботиться о пиксельном шейдере. Мы просто отрисовываем ландшафт раскрашивая в оттенки серого, более светлые тона наверху, темные внизу. Техника (technique) шейдера имеет всего один проход (pass), содержащий два наших шейдера. В параметрах компиляции указываем vs_3_0 и ps_3_0, т.к. VTF является функциональностью Shader Model 3.0.

 

    float4 PixelShader(in float4 worldPos : TEXCOORD1) : COLOR
    {
        return worldPos.y / maxHeight;
    }
 
    technique GridDraw
    {
        pass P0
        {
            vertexShader = compile vs_3_0 Transform();
            pixelShader  = compile ps_3_0 PixelShader();
        }
    }

После того как мы закончили с шейдером, давайте вернемся в класс Game. Создайте в проекте еще одну папку с именем Textures и добавьте в нее файл height1.dds из архива resources, установите для фала контент процессор Texture(mipmapped). Далее нам необходимо добавить в класс поля для шейдера (эффекта) и текстуры.

    Effect gridEffect;
    Texture2D displacementTexture;

В методе LoadGraphicsContent загружаем эффект и текстуру.

gridEffect = content.Load<Effect>("Shaders\VTFDisplacement");
displacementTexture = content.Load<Texture2D>("Textures\height1");

В метод Draw добавляем код, устанавливающий параметры эффекта и код отрисовки сетки. Мы помещаем наш ландшафт в центр виртуального мира, поэтому матрицу мира (world) оставляем единичной (Identity), матрицы вида (view) и проекции (projection) получаем из компонента камеры.

protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
            gridEffect.Parameters["world"].SetValue(Matrix.Identity);
            gridEffect.Parameters["view"].SetValue(camera.View);
            gridEffect.Parameters["proj"].SetValue(camera.Projection);
            gridEffect.Parameters["maxHeight"].SetValue(128);
            gridEffect.Parameters["displacementMap"].SetValue(displacementTexture);
 
            gridEffect.Begin();
            foreach (EffectPass pass in gridEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                grid.Draw();
                pass.End();
            }
            gridEffect.End();
 
            base.Draw(gameTime);
        }

 

На данном этапе наше приложение удачно скомпилируется и запустится, и вы увидите, что-то наподобие этого:

Пока что все выглядит замечательно, но давайте посмотрим что произойдет, если мы увеличим размер ландшафта, установите значения свойств grid.CellSize = 8, grid.Dimension = 512 и значение переменной maxHeight передаваемое в шейдер = 512. Получаем что-то подобное этому:

Смотрим и ужасаемся, откуда у нас такая «замечательная» лестница? Карта высот у нас имеет размер 256 на 256 пикселей, так что пока размерность сетки была 256, то каждый пиксель текстуры проецировался на одну вершину в сетке, и было все замечательно. Но после того как мы увеличили размер сетки, один пиксель стал проецироваться на 2 вершины, которые на самом деле должны иметь разную высоту, но получилось так, что они находятся на одной высоте. Если бы у нас была билинейная фильтрация, то графический процессор автоматически бы рассчитал среднее значение на основе данных 4 соседних пикселей, и поверхность была бы более сглаженной. Но так как вершинные текстуры не поддерживают фильтрации, то нам придется самим реализовывать билинейную фильтрацию в шейдере. Итак, давайте откроем файл VTFDisplacement.fx и добавим следующий код.

 

    //Следующие два параметра по большому счету
    //должны задаваться из приложения
 
    //Размер текстуры
    float textureSize = 256.0f;
 
    //Размер одного текселя
    float texelSize =  1.0f / 256.0f;
 
    //Функция билинейной интерполяции
    float4 tex2Dlod_bilinear( sampler texSam, float4 uv )
    {
        float4 height00 = tex2Dlod(texSam, uv);
 
        float4 height10 = tex2Dlod(texSam, uv + float4(texelSize, 0, 0, 0));
 
        float4 height01 = tex2Dlod(texSam, uv + float4(0, texelSize, 0, 0));
 
        float4 height11 = tex2Dlod(texSam, uv + float4(texelSize, texelSize, 0, 0));
        float2 f = frac( uv.xy * textureSize );
        float4 tA = lerp( height00, height10, f.x );
        float4 tB = lerp( height01, height11, f.x );
        return lerp( tA, tB, f.y );
    }

 

 

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

Для иcпользования билинейной фильтрации в вершинном шейдере замените

float height = tex2Dlod ( displacementSampler, float4(In.uv.xy, 0, 0 ));

на:

float height = tex2Dlod_bilinear(displacementSampler, float4(In.uv.xy, 0, 0));

Теперь поверхность ландшафта стала более гладкой:

Бонуc: Текстурирование

Давайте наложим на наш ландшафт пару текстур. Наилучшим способом затекстурить поверхность, является смешать несколько текстур (например: песок, траву, скалы и снег) в пиксельном шейдере основываясь на весах вершин, которые рассчитываются из данных высот вершин. У Riemer`s есть отличный урок, как реализовать это, но в его реализации веса для смешивания текстур рассчитываются на CPU, на этапе загрузки карты высот, мы же будем это делать на GPU. Представленный далее код написан по материалам уроков Riemer`s.

Для начала в папку проекта Textures добавьте файлы sand.dds, grass.dds, rock.dds и snow.dds (примечание: для уменьшения размера скачиваемого архива эти файлы представлены в низком разрешении, наличие этих файлов в высоком разрешении заметно улучшит картинку в визуальном плане). Затем откройте файл шейдера и добавьте четыре параметра для текстур и самплеры.

    texture sandMap;
    sampler sandSampler = sampler_state
    {
        Texture   = <sandMap>;
 
        MipFilter = Linear;
        MinFilter = Linear;
        MagFilter = Linear;
 
        AddressU  = Wrap;
        AddressV  = Wrap;
    };
 
    texture grassMap;
    sampler grassSampler = sampler_state
    {
        Texture   = <grassMap>;
 
        MipFilter = Linear;
        MinFilter = Linear;
        MagFilter = Linear;
 
        AddressU  = Wrap;
        AddressV  = Wrap;
    };
 
    texture rockMap;
    sampler rockSampler = sampler_state
    {
        Texture   = <rockMap>;
 
        MipFilter = Linear;
        MinFilter = Linear;
        MagFilter = Linear;
 
        AddressU  = Wrap;
        AddressV  = Wrap;
    };
 
    texture snowMap;
    sampler snowSampler = sampler_state
    {
        Texture   = <snowMap>;
 
        MipFilter = Linear;
        MinFilter = Linear;
        MagFilter = Linear;
 
        AddressU  = Wrap;
        AddressV  = Wrap;
    };

Теперь надо добавить параметр в выходную структуру вершинного шейдера. Для каждой вершины на выходе мы будем задавать 4 значения веса для каждой из текстур (песок, трава, скала, снег). Итак, для вершин с малым значением высоты мы будем накладывать только текстуру песка, так что вес для песка будет равен 1, пока все остальные веса будет равны 0. По мере увеличения высоты мы должны будем сделать переход от песка к траве, так что вес песка будет уменьшаться, а все травы увеличиваться. Так как каждое значение веса лежит в промежутке от 0,0 до 1,0, мы можем запаковать все значения в 4 переменные типа float, а его в один float4 параметр. Новая выходная структура для вершинного шейдера будет выглядеть примерно следующим образом:

    struct VS_OUTPUT
    {
        float4 position       : POSITION;
        float4 uv             : TEXCOORD0;
        float4 worldPos       : TEXCOORD1;
 
        // вес, использующийся для мультитекстурирования
        float4 textureWeights : TEXCOORD2;
    };

В конец вершинного шейдера (до возвращения параметра return Out;) добавьте следующий код:

    float4 TexWeights = 0;
    TexWeights.x = saturate( 1.0f - abs(height - 0.0) / 0.20f);
    TexWeights.y = saturate( 1.0f - abs(height - 0.3) / 0.25f);
    TexWeights.z = saturate( 1.0f - abs(height - 0.6) / 0.25f);
    TexWeights.w = saturate( 1.0f - abs(height - 0.9) / 0.25f);
 
    float totalWeight = TexWeights.x +
                        TexWeights.y +
                        TexWeights.z +
                        TexWeights.w;
 
    TexWeights /= totalWeight;
    Out.textureWeights = TexWeights;

Каждый компонент вектора textureWeights содержит в себе вес для каждой из текстур, X – песок, Y – трава, Z – скала и W – снег. Для каждой из текстур задано значение на которой она начинает проявлять себя, затем достигает максимальной «видимости» и затухает, переходя в следующую текстуру. Последние инструкции нормализуют значения, чтобы сумма всех весов имела значение 1, иначе мы получим темные или светлые участки в местах перехода текстур.

Когда мы производим выборку в пиксельном шейдере, то текстурные координаты мы будем перемножать на специально подобранное значение (в нашем случае 8), это делается для повтора текстуры на все участки ландшафта. Если выбрать данное значение слишком маленьким, то уровень «натяжки» текстуры на ландшафт будет слишком большим и при близком рассмотрении будет заметна пикселизация. Если задать слишком большое значение, то повторение текстуры будет бросаться в глаза при просмотре с дальнего расстояния. Но вы свободны в выборе данного значения, можете посмотреть, к чему приведет его изменение. Техника называемая «detail texturing» может помочь в решении данной проблемы, она заключается в комбинировании с более детализированными текстурами при приближении к поверхности, но в данном уроке она рассматриваться не будет.
И в завершении в пиксельном шейдере, мы считываем цвет со всех 4 текстур и на основе весов смешиваем их.

    float4 PixelShader(in float4 uv      : TEXCOORD0,
                       in float4 weights : TEXCOORD2) : COLOR
    {
         float4 sand  = tex2D(sandSampler,  uv * 8 );
         float4 grass = tex2D(grassSampler, uv * 8 );
         float4 rock  = tex2D(rockSampler,  uv * 8 );
         float4 snow  = tex2D(snowSampler,  uv * 8 );
 
         return sand  * weights.x +
                grass * weights.y +
                rock  * weights.z +
                snow  * weights.w; 
    }

В коде приложения объявляем поля для текстур:

        Texture2D sandTexture;
        Texture2D grassTexture;
        Texture2D rockTexture;
        Texture2D snowTexture;

В методе LoadGraphicsContent загружаем их:

            sandTexture = content.Load<Texture2D>("Textures\sand");
            grassTexture = content.Load<Texture2D>("Textures\grass");
            rockTexture = content.Load<Texture2D>("Textures\rock");
            snowTexture = content.Load<Texture2D>("Textures\snow");

А в методе Draw передаем в шейдер в виде параметров:

            gridEffect.Parameters["sandMap"].SetValue(sandTexture);
            gridEffect.Parameters["grassMap"].SetValue(grassTexture);
            gridEffect.Parameters["rockMap"].SetValue(rockTexture);
            gridEffect.Parameters["snowMap"].SetValue(snowTexture);

В итоге поверхность должна выглядеть примерно следующим образом:

Итак, в первом уроке мы рассмотрели, как использовать вершинные текстуры для построения ландшафта, используя карту высот и наложить на него текстуры при помощи мультитекстурирования, причем вся обработка велась на графическом процессоре. Также мы рассмотрели, как реализовать билинейную фильтрацию в вершинном шейдере. Прошу не обращать внимания на то, что мы все это сделали на GPU и пересчитывали каждый кадр, вместо того чтобы сделать все расчета один раз на CPU в момент загрузки, в следующей части мы рассмотрим, как реализовать морфинг (morph) ландшафта и как добавлять на него деформации. По большому счету всю эту функциональность можно реализовать и на CPU, но мы все сделали на GPU, оставив ресурсы центрального процессора для других задач, например: реализация логики геймплея, физики, AI и т.п.

Полный код этой главы можно скачать тут: Chapter1.rar

Комментарии
#1 | general 10.05.2009 01:36:13
Перевел все примеры(1-4) к статье.
Чуть поморочился только с 4м примером, анимацией, обновил библиотеки.
добавил в хранилище файлов скачать
#2 | master_alexander 18.12.2009 17:48:43
Error 1 'Microsoft.Xna.Framework.Graphics.GraphicsDevice' does not contain a definition for 'ResolveRenderTarget' and no extension method 'ResolveRenderTarget' accepting a first argument of type 'Microsoft.Xna.Framework.Graphics.GraphicsDevice' could be found (are you missing a using directive or an assembly reference?)

Помогите, в чем проблема?Frown
#3 | Dimon4ik 18.01.2011 16:12:36
Для XNA 3

vb = new VertexBuffer(device, (dimension + 1) * (dimension + 1) * VertexPositionNormalTexture.SizeInBytes, BufferUsage.WriteOnly);
ib = new IndexBuffer(device, 6 * dimension * dimension * sizeof(int), BufferUsage.WriteOnly, IndexElementSize.ThirtyTwoBits);
#4 | TreinDSM 23.01.2012 17:55:25
Для XNA 4

vb = new VertexBuffer(device, typeof(VertexPositionNormalTexture), vertices.Length, BufferUsage.WriteOnly);

ib = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, 6 * dimension * dimension * sizeof(int),BufferUsage.WriteOnly);
#5 | TreinDSM 23.01.2012 20:19:50
А метод Draw в классе Game1 будет выглядеть так:
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.RasterizerState = RasterizerState.CullNone;

gridEffect.Parameters["world"].SetValue(Matrix.Identity);
gridEffect.Parameters["view"].SetValue(camera.View);
gridEffect.Parameters["proj"].SetValue(camera.Projection);
gridEffect.Parameters["maxHeight"].SetValue(128);
gridEffect.Parameters["displacementMap"].SetValue(displacementTexture);

gridEffect.Parameters["sandMap"].SetValue(sandTexture);
gridEffect.Parameters["grassMap"].SetValue(grassTexture);
gridEffect.Parameters["rockMap"].SetValue(rockTexture);
gridEffect.Parameters["snowMap"].SetValue(snowTexture);
;
foreach (EffectPass pass in gridEffect.CurrentTechnique.Passes)
{
pass.Apply();
grid.Draw();
}

base.Draw(gameTime);
}
#6 | TreinDSM 23.01.2012 20:24:19
Единственное, на вызове pass.Apply() кидает ошибку. Ругается на не поддерживаемый формат Color. В чем может быть беда?
Добавить комментарий
Пожалуйста, залогиньтесь для добавления комментария.
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Авторизация
Логин

Пароль



Вы не зарегистрированы?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Мини-чат
Вы должны авторизироваться, чтобы добавить сообщение.

27.08.2014
Я умею немного на asp.net + html и css

22.08.2014
на ASP mvc 3 есть пару проектов. Могу помочь, если нужно. Обидно, если закроется Frown

21.08.2014
я тоже ноль

21.08.2014
Я в вебе только с php занимался да и то на уровне чтоб работало.

21.08.2014
Я в вебе полный ноль…

21.08.2014
Переводить его надо, хоть на ту же азуру. И двиг менять на что-то современное. Если есть веб-разрабы - можем скооперироваться. Один делать не буду.

21.08.2014
не знаю всех нюансов по оплате и все хорошее когда нибудь заканчивается

21.08.2014
А что случилось?

21.08.2014
похоже сайт будет работать до 28го числа

09.08.2014
Апи пока не видел. Но есть приложение в магазине Live Lock Screen BETA, так что думаю скоро будет

08.08.2014
Я про API для Update1. На нем работает это

08.08.2014
А что именно нужно? Чтото и сейчас открыто http://msdn.micro.
...105).aspx

06.08.2014
Кто-нибудь слышал об открытии доступа к Lock Screen Api?

31.07.2014
VPDExpress на базе MVS 2012, ни в какую не ловит исключения. Даже если их сам создаешь. И всех так?

25.07.2014
С днем системного администратора причастных к этой профессии! По случаю - тортик от жены

RSS каналы сайта
XNA - Новости
XNA - Статьи
XNA - Форум
XNA - Галерея
XNA - Файлы
Время загрузки: 0,07 секунд 8,709,483 уникальных посетителей