Продвинутое освещение и текстурирование в XNA

Продвинутое освещение и текстурирование в XNA

Автор — Mahdi Khodadadi Fard, 4.4.2008

Свет

Если Вы посмотрите вокруг себя, то Вы будете видеть, что свет существует где-нибудь. Даже в самых темных местах есть немного света. Не имеет значения, что сейчас — день или ночь, внутри или снаружи, свет есть везде.

 

Введение в свет

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

• Отражение. Отражение — отбрасывание или отскакивание назад света после того, как он достигает поверхности.

• Преломление. Преломление — изгиб или отклонение света из-за его перехода из одной передающей среды в другую; например, при переходе из воздуха к стеклу или воде, свет преломляется.

• Передача. Передача света — проводимость или транспортировка света через передающую среду.

• Дифракция. Дифракция — очевидный изгиб света вокруг края, который приводит к изменению его интенсивности и направления. Дифракция приводит к скоплениям света.

• Интерференция. Интерференция — волновое взаимодействие света, которое приводит к усилению, сокращению или составному образованию результирующей световой волны.

• Рассеивание. Рассеивание — сосредоточивание или рассеивание света из-за взаимодействия с материей или средой. Это — множественное отражение света в различных направлениях.

• Диффузия. Диффузия — это тоже рассеивание света отражением от поверхности. Диффузия также относится к передаче света через полупрозрачный материал.

• Поглощение. Поглощение — непроводимость или задержание света материей или средой, которые не приводит ни к отражению, ни к передаче.

• Поляризация. Поляризация — выборочная передача света, основанная на его ориентации. Когда свет отражен или преломлен, его ориентация и выравнивание меняются.

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

Рисунок 1. Отражение

Рисунок 2. Преломление

Рисунок 3. Передача

Рисунок 4. Дифракция

Рисунок 5. Интерференция

Рисунок 6. Рассеивание

Рисунок 7. Диффузия

Рисунок 8. Поглощение

Рисунок 9. Поляризация.

Рисунок 10. Дисперсия

Примечание:

Рисунки 1-10 взяты из книги 3D Lighting: History, Concepts, and Techniques. Jenifer L. Niles.

Закон Отражения

Закон отражения гласит, что угол отражения равняется углу падения относительно нормали поверхности. Это означает, что угол отраженного света будет таким же, как угол входящего света. Поверхностная нормаль — перпендикуляр на отражающую поверхность в точке падения. Рисунок 11 иллюстрирует закон отражения:


Рисунок 11. Закон Отражения

Источники освещения

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

•Окружающий свет

•Направленный Свет

•Световая точка

•Световое пятно

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

Окружающий свет

Окружающий свет — это свет, который существует повсюду. Этот свет является результатом отражения света в соседнем окружении. Кажется, будто окружающий свет исходит из многих направлений, интенсивности света равны. Так, использование окружающего света обеспечивает аппроксимацию общей яркости. Например, предположим, что ночью, когда свет выключен, вы просыпаетесь и идете в кухню, чтобы выпить стакан воды. Количества света в комнате достаточно, чтобы найти дорогу к кухне, но вы не можете видеть детали комнаты. Скажем, что этот тип света называют Окружающим. Мы добавляем окружающий свет к нашему конечному цвету поверхности; код, приведенный ниже, показывает этот факт:

return FinalColor + AmbientColor;

Если рассеянный свет имеет низкую интенсивность, мы часто устанавливаем маленькие значения для этого света в наших уравнениях (Как float4 (0.15, 0.15, 0.15, 1)).

Направленный Свет

Направленный (бесконечный) свет — тип света, который исходят издалека. Лучи света в этой модели света параллельны друг другу. Направленный свет полезен тогда, когда мы хотим поместить солнце в нашу игру. Интенсивность этого света не уменьшается по расстоянию. Рисунок 12 — иллюстрация направленного света:


Рисунок 11. Направленный Свет

Световая точка

Световая точка излучает свет одинаково по любому направлению. Их главное использование — для игр в помещениях, чтобы поместить лампочки в комнате. Интенсивность световой точки уменьшается с увеличением расстояния. Рисунок 13 показывает световую точку, излучающую свет во всех направлениях из единственной точки:


Рисунок 13. Световая точка

Код, приведенный ниже, определяет, сколько света наша поверхность получит от источника освещения для световой точки:

float3 PositionInWorld = mul(float4(Position, 1.0f), World).xyz;

float3 LightDirection = mul((LightPosition — PositionInWorld) / LightRange);

float Attenuation = saturate(1.0f — dot(LightDirection, LightDirection));

Световое пятно

Световое пятно подобно световой точке, но в случае светового пятна у нас есть предпочтительное направление света. Интенсивность светового пятна уменьшается с увеличением расстояния и также под влиянием другого фактора, называемого эффектом светового пятна. Каждое световое пятно имеет углы: внутренний конический угол и внешний конический угол. Рисунок 14 иллюстрирует эти углы:


Рисунок 14. Световое пятно

Этот HLSL код показывает, как вычислить эффект светового пятна:

float GetSpotLightEffect(float3 lightDirection, float3 spotDirection)

{

float2 CosineVector = cos(float2(LightSpotOuterCone, LightSpotInnerCone) * 0.5f);

float LightDotSpot = dot(-lightDirection, normalize(spotDirection));

return smoothstep(CosineVector.x, CosineVector.y, LightDotSpot);

}

В вышеупомянутом коде я поместил внутренний и внешний конические углы в float2, чтобы ускорить вычисление. Цель состоит в том, чтобы получить косинус внутренних и внешних углов. Имея эффект светового пятна, мы умножаем коэффициент ослабления эффектом светового пятна:

float Attenuation = saturate(1.0f — dot(LightDirection, LightDirection));

Attenuation *= GetSpotLightEffect(NormalizedLightDirection, LightDirection);

Материалы

Материалы — просто определение того, как объект, которому назначен определенный материал, отразит падающий свет. Как вы могли бы ожидать, это подразумевает зависимость от характеристик падающего света.

Здесь мы определяем некоторые переменные, необходимые для наших следующих шагов:

#define LIGHT_DIRECTIONAL 0

#define LIGHT_POINT 1

#define LIGHT_SPOT 2

int LightType = 0;

float3 LightDirection = float3(0, -1, -1);

float3 LightPosition = float3(0, 15, 0);

float LightSpotInnerCone = 0.3490;

float LightSpotOuterCone = 0.6981;

float LightRange = 30;

float4 MaterialAmbient = float4(0.2, 0.2, 0.2, 1.0);

float4 MaterialDiffuse = float4(0.8f, 0.8f, 0.8f, 1.0f);

float4 MaterialSpecular = 0;

float MaterialShininess = 0;

float4x4 World;

float4x4 WorldIT;

float4x4 WorldViewProjection;

float3 CameraPosition;

texture2D DiffuseTexture;

texture2D NormalTexture;

sampler2D DiffuseSampler = sampler_state

{

Texture = <DiffuseTexture>;

MagFilter = Linear;

MinFilter = Anisotropic;

MipFilter = Linear;

MaxAnisotropy = 16;

};

sampler2D NormalMap = sampler_state

{

Texture = <NormalTexture>;

MagFilter = Linear;

MinFilter = Anisotropic;

MipFilter = Linear;

MaxAnisotropy = 16;

};

struct VS_OUTPUT

{

float4 Position : POSITION;

float2 TextureCoordinate : TEXCOORD0;

float3 ViewDirection : TEXCOORD1;

float3 LightDirection : TEXCOORD2;

float3 SpotDirection : TEXCOORD3;

float4 Diffuse : COLOR0;

float4 Specular : COLOR1;

};

Уравнение Освещения: Рассеянный, Зеркальный

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

float3 HalfVector = normalize(LightDirection + ViewDirection);

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

Рисунок 15 иллюстрирует эти векторы:


Рисунок 15.

Рассеянный — главный цвет нашей поверхности. Когда мы говорим, что автомобиль является синим, мы говорим о рассеянном цвете того автомобиля. Мы можем установить постоянное значение для рассеянного цвета или получить цвет от отображенной текстуры (или использовать оба способа; в этом случае мы умножаем постоянное значение на цвет, полученный от текстуры). Потом мы должны вычислить скалярное произведение между направлением света и направлением визирования. Это значение будет умножено нашим рассеянным цветом, и мы получим конечный цвет поверхности. Маленькие углы между вектором света и поверхностной нормалью приводят к более яркой поверхности:

float NormalDotLight = saturate(dot(Normal, LightDirection));

float3 Diffuse = DiffuseColor * NormalDotLight;

Зеркальный цвет — маленький блеск на поверхности, когда свет отражается в направлении, то же самом или близком направлению визирования. Фактически это результат отражения света от поверхности объекта прямо в ваши глаза. Рисунок 16 показывает рассеянные и зеркальные цвета:


Рисунок 16. Рассеянный и отраженный цвета

Цвет этой подсветки регулируемый, потому что в реальном мире цвет зеркальной подсветки не только функция цвета падающего света и рассеянного и окружающего цветов объекта. Отраженный свет мог бы принять различные цвета, потому что не все компоненты отражены одинаково. Изменение цвета подсветки может позволить больше гибкости в достижении реалистичных результатов за низкую цену. Отражение от поверхности (MaterialSpecular) позволяет нам задавать цвет зеркальной подсветки. Наконец, «мощностью» зеркальной подсветки можно управлять; короткая версия этого параметра — благодаря ему Вы можете управлять размером «яркого пятна» на поверхности объекта, чтобы изменить воспринятый блеск объекта: более высокая мощность обеспечивает меньшую подсветку.

Здесь приведен код, необходимый для вычисления зеркальной подсветки:

float NormalDotHalf = saturate(dot(Normal, HalfVector));

float FinalSpecular = MaterialSpecular * NormalDotHalf;

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

float NormalDotLight = saturate(dot(Normal, LightDirection));

float SpecularPower = (NormalDotLight == 0.0f) ?

0.0f :

pow(NormalDotHalf, MaterialShininess);

Вот код HLSL для получения конечного цвет путем вычисления рассеянного и зеркального цветов:

// LightDirection and ViewDirection must be normalized.

float4 GetFinalColor(float3 Normal,

float3 LightDirection,

float3 ViewDirection)

{

float3 HalfVector = normalize(LightDirection + ViewDirection);

float NormalDotLight = saturate(dot(Normal, LightDirection));

float NormalDotHalf = saturate(dot(Normal, HalfVector));

float SpecularPower = (NormalDotLight == 0.0f) ?

0.0f :

pow(NormalDotHalf, MaterialShininess);

return MaterialAmbient +

(MaterialDiffuse * NormalDotLight) +

(MaterialSpecular * SpecularPower);

}


Реклама
Запись опубликована в рубрике Uncategorized. Добавьте в закладки постоянную ссылку.

Один комментарий на «Продвинутое освещение и текстурирование в XNA»

  1. Евгений Ли:

    Это не для слабых мозгов

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s