600 likes | 927 Views
Огонь, Вода и Медные Трубы: Новые, Интересные Графические Эффекты. Наталья Татарчук ATI Research, Inc 3D Application Research Group. КРИ, Москва 2004. Обзор Материала. Создание эффекта металлической автомобильной краски Эффект дымки и разгоряченного воздуха (heat and haze simulation)
E N D
Огонь, Вода и Медные Трубы: Новые, Интересные Графические Эффекты Наталья Татарчук ATI Research, Inc 3D Application Research Group КРИ, Москва 2004
Обзор Материала • Создание эффекта металлической автомобильной краски • Эффект дымки и разгоряченного воздуха (heat and haze simulation) • Изображение объёмного освещения в реальном времени (light shafts)
Создание Металлической Краски для Автомобиля • Создание многотональной прослойки краски • Симуляция металлических частиц в эмали • Блестящее покрытие • Создание динамически размытых отражений
Слои Металлической Краски Multi-Tone Base Color Microflake Layer Clear gloss coat Final Color Composite
Многотональная Основа Краски • Смешивание двух цветовкраски в зависимости от направления обозревателя • Нормаль N из карты нормалей • Используем третий тон для балансирования результатов смешения
Вершинный Шейдер VS_OUTPUTmain( float4Pos :POSITION, float3Normal :NORMAL, float2Tex :TEXCOORD0, float3Tangent :TANGENT, float3Binormal:BINORMAL) { VS_OUTPUT Out = (VS_OUTPUT) 0; // Propagate transformed position out: Out.Pos =mul( view_proj_matrix, Pos ); // Compute view vector: Out.View =normalize( mul(inv_view_matrix, float4( 0, 0, 0, 1)) - Pos ); // Propagate texture coordinates: Out.Tex = Tex; // Propagate tangent, binormal, and normal vectors to pixel shader: Out.Normal = Normal; Out.Tangent = Tangent; Out.Binormal = Binormal; returnOut; }
Compute the result color by lerping three input tones using computed fresnel term. Fetch normal from a normal map and scale and bias it to move into [-1; 1] Normalize the view vector to ensure higher quality results Compute Nw • V using world-space normal vector Пиксельный Шейдер float4main(float4Diff:COLOR0, float2Tex:TEXCOORD0, float3Tangent:TEXCOORD1, float3Binormal:TEXCOORD2, float3Normal:TEXCOORD3, float3View:TEXCOORD4) :COLOR { float3vNormal =tex2D( normalMap, Tex ); vNormal = 2 * vNormal - 1.0; float3vView =normalize( View ); float3x3mTangentToWorld =transpose( float3x3( Tangent, Binormal, Normal )); float3vNormalWorld =normalize( mul(mTangentToWorld,vNormal)); floatfNdotV =saturate( dot( vNormalWorld, vView ) ); floatfNdotVSq = fNdotV * fNdotV; float4paintColor = fNdotV * paintColor0 + fNdotVSq * paintColorMid + fNdotVSq * fNdotVSq * paintColor2; returnfloat4( paintColor.rgb, 1.0 ); }
Прослойка Микрочастиц • Моделирование взаимодействия фотонов, отраженных металлическими микрочастицами в слое эмали • Алгоритм использует высокочастотную карту нормалей (Nn), содержащую шумы, повторяющуюся по поверхности машины
Расчет Нормалей Микрочастиц • Сначала подсчитываем нормаль, N, из карты нормалей для машины • Используя высокочастотнуюкарту шумов, рассчитываем пертурбированную нормаль Np • Моделируем два слоя микрочастиц подсчитывая пертурбированные нормали Np1и Np2на основе нормали шумов Np где c = b где a << b
Подчитываем скалярные продукты нормализированного вектора обозревателя с нормалями Для обоих слоев микрочастиц Пертурбированная нормаль из карты шумов Компонуем многотональный цвет прослойки микрочастиц Подсчитываем нормали для обоих слоев микрочастиц Пиксельный Шейдер float4main(float4 Diff: COLOR0, float2 Tex : TEXCOORD0,float3 Tangent: TEXCOORD1, float3 Binormal: TEXCOORD2, float3 Normal: TEXCOORD3, float3 View: TEXCOORD4,float3 SparkleTex : TEXCOORD5 ) : COLOR { … fetch and signed scale the normal fetched from the normal map float3 vFlakesNormal = 2 * tex2D( microflakeNMap, SparkleTex ) - 1; float3 vNp1 = microflakePerturbationA * vFlakesNormal + normalPerturbation * vNormal ; float3 vNp2 = microflakePerturbation * ( vFlakesNormal + vNormal ) ; float3 vView = normalize( View ); float3x3 mTangentToWorld = transpose( float3x3( Tangent, Binormal, Normal )); float3 vNp1World = normalize( mul( mTangentToWorld, vNp1) ); float fFresnel1 = saturate( dot( vNp1World, vView )); float3 vNp2World = normalize( mul( mTangentToWorld, vNp2 )); float fFresnel2 = saturate( dot( vNp2World, vView )); float fFresnel1Sq = fFresnel1 * fFresnel1; float4 paintColor = fFresnel1 * flakeColor + fFresnel1Sq * flakeColor + fFresnel1Sq * fFresnel1Sq * flakeColor +pow( fFresnel2, 16 ) * flakeColor; returnfloat4( paintColor, 1.0 ); }
Динамически Размытые Отраженные Объекты Размытые отражения объектов
Подсчет Динамически Размытых Отражений • Можно использовать карту глянца (gloss map) для обозначения регионов, где отражения должны быть более размытыми • Изпользуйте bias читая текстуру environment map, чтобы размывать отражения • ИспользуйтеtexCUBEbiasдля текстурного чтения • Для более размытого спекулярного отражения, значение bias – высокое, что собственно и создает эффект размытости
Зараннее помножим на альфу из environment map, чтобы подсветить отражения и правильно просчитать спекулярные блики Отраженные блики Просчитайте вектор отражения для доступа к environment map Этот параметр используется для динамического размывания отражений при bias’е чтения environment map Пиксельный Шейдер float4 ps_main( ... /* same inputs as in the previous shader */ ) { // ... use normal in world space (see Multi-tone pixel shader) // Compute reflection vector: float fFresnel = saturate(dot( vNormalWorld, vView)); float3 vReflection = 2 * vNormalWorld * fFresnel - vView; float fEnvBias = glossLevel; // Sample environment map using this reflection vector and bias: float4 envMap = texCUBEbias( showroomMap, float4( vReflection, fEnvBias ) ); // Premultiply by alpha: envMap.rgb = envMap.rgb * envMap.a; // Brighten the environment map sampling result: envMap.rgb *= brightnessFactor; // Combine result of environment map reflection with the paint // color: float fEnvContribution = 1.0 - 0.5 * fFresnel; return float4( envMap.rgb * fEnvContribution, 1.0 ); }
Компонование Многотонального Слоя Краски и Прослойки Микрочастиц Базовый цвет материала и микрочастичный эффект подсчитывается по вот этой формуле: color0(Np1·V) + color1(Np1·V)2 + color2(Np1·V)4 + color3(Np2·V)16 Базовый материал Микрочастицы
Компонование Финального Эффекта { ... // Compute final paint color: combines all layers of paint as well// as two layers of microflakes: float fFresnel1Sq = fFresnel1 * fFresnel1; float4 paintColor = fFresnel1 * paintColor0 + fFresnel1Sq * paintColorMid + fFresnel1Sq * fFresnel1Sq * paintColor2 +pow( fFresnel2, 16 ) * flakeLayerColor; // Combine result of environment map reflection with the paint // color: float fEnvContribution = 1.0 - 0.5 * fNdotV; // Assemble the final look: float4 finalColor; finalColor.a = 1.0;finalColor.rgb = envMap * fEnvContribution + paintColor; return finalColor; }
Эффект дымки и разгоряченного воздуха (Heat and haze simulation)
Об Эффекте • Естественное явление атмосфере, хорошо знакомый всем • Лучи света преломляются, проходя через воздух и другие среды разных плотностей • Не обязательно использовать формулу из учебника по физике для создания правильно выглядещего эффекта для игр
Дрожание и Рассеивание Лучей Света • Горячий воздух имеет меньшую плотность, чем холодный воздух • Индекс преломления лучей света зависит от плотности материала • По мере поднятия, горячий воздух перемешивается с холодным, таким образом преломляя лучи света
Алгоритм • Нарисуйте сцену в RGBA текстуру (offscreen-buffer) (renderable texture) • Цвет материала в каналы RGB • Специальный параметр искажения в канал Alpha • Нарисуйте полноэкранный прямоугольник в буфер кадра • Используйте параметр искажения чтобы изменить текстурные координаты для прочитки текстуры сцены, чтобы создать эффект преломления света в горячем воздухе Расчет параметра искажения: • Самой простой: просто используйте глубину сцены • Рассеивание используя геометрический объект • Динамическое рассеивание и дрожание света используя температурные текстуры
Дрожание и Рассеивание Света на Основе Специальных Объектов • Отличный подход для изображения однородных газов • Для изображения воздуха над отдушиной горячих газов либо позади струи реактивного самолета • Рисуйте сцену используя специальные «температурные» объекты: единственное предназначение этих объектов в том, чтобы создавать параметр искажения в канал альфа • Они не прорисовываются в главном рендеринге сцены в каналы RGB • Просчитайте параметр искажения для этих объектов
Параметры Искажения • Глубина сцены – неплохой фактор искажения, но ваши художники наверняка захотят что-то более легко контролируемое • Решение: • Изменяйте маштаб параметра искажения (scale)расстоянием от источника тепла, чтобы создать эффект рассеивания и дрожания воздуха из-за дисперсии температуры
Избегайте Слишком Резкого Изображения • Старайтесь не рисовать слишком ровные края температурных объектов в канал альфа • Не забывайте, что газы расширяются, чтобы заполнять всю окружающюю среду • Для избежания этих проблем, модулируйте параметр искажения при помощи N • V (Fresnel)
Температурные Текстуры • Расширение предыдущего подхода • Отлично изображают газы с хаотическим распределением плотности
Совместное Использование Температурных Текстур и Объектов • Скроллайте температурные текстуры по поверхности температурных объектов • Направление движения текстур важно: облегчает восприятие рассеивания газов при изменяющейся температуры • Скролл вверх (world-space) для изображения эффекта горячего воздуха, поднимающегося над разогретым шоссе • Для изображения струи горячего воздуха из двигателя реактивного самолета, текстуры должны скроллаться по направлению движения воздуха из мотора • Направления скроллинга так же может зависить от температурных объектов • Начальный параметр искажения должен быть модулирован значением глубины сцены температурного объекта
Эффект Рассеиваемых Газов Renderable Texture • Рисуйте полноэкранный прямоугольник, используя раннее созданный off-screen buffer (renderable texture) и пертурбационные температурные карты Full-Screen Quad Drawn to Back Buffer Perturbation Map
Пертурбационные Температурные Карты • 2х-компонентный вектор сохраняется в каналах RB • Скроллайте эту карту в двух различных направлениях по полноэкранному прямоугольнику и считывайте дважды • Расчитайте среднее значение обоих самплов, за тем переведите в диапазон [-1.0, 1.0] • Модулируйте вектор параметром искажения • Таким образом получаем вектор пертурбации Average
Как Использовать Вектор Пертурбации Для Эффекта Рассеивания • Простое измение значения пикселей выглядит сносно • Но! Таким образом мы не создаем эффект размытости воздуха из-за преломления света с точки зрения обозревателя • Размывайте (blur) измененный пиксель, используя параметр искажения: • Для этого можно использовать расширяемый диск Пуассона для размытия • Так же можно использовать отделимые фильтры Гаусса
Вектор Пертурбации (Perturbation Vector) • Этот вектор используется, чтобы изменить начальную текстурную координаты • Длиной этого вектора является значение параметра искажения • Эта новая измененная текстурная координата используется для зависимой (dependant) прочитки буфера off-screen с прорисовкой главной сцены Original <u,v> + Perturbation vector <x,y>
Шейдер для Подсчета Искажения float4 main (PsInput i) : COLOR { // fetch from perturbation map with scrolling texture coords float3 vPerturb0 = tex2D (tPerturbationMap, i.texCoord1); float3 vPerturb1 = tex2D (tPerturbationMap, i.texCoord2); // scale and bias: (color - 0.5f)*2.0f vPerturb0 = SiConvertColorToVector(vPerturb0); vPerturb1 = SiConvertColorToVector(vPerturb1); // average perturbation vectors float2 offset = (vPerturb0.xy + vPerturb1.xy) * 0.5f; // get distortion weight from renderable texture (stored in alpha) float4 cDistWeight = tex2D (tRBFullRes, i.texCoord0); // square distortion weight cDistWeight.a *= cDistWeight.a; // compute distorted texture coords offset.xy = ((offset.xy * cDistWeight.a) * fPerturbScale) + i.texCoord0; // fetch the distorted color float4 o; o.rgb = SiPoissonDisc13RGB(tRBFullRes, offset, 1.0f/screenRes.xy, cDistWeight.a); o.a = 1.0f; return o; }
Радиус диска и количество сэмплов контролирует качество размывки. Для поддержки большего размера ядра фильтра с лучшим качеством, этот шейдер должен изменять количество сэмплов в зависимости от размера диска. Шейдер Расширяемого ДискаПуассона float3 SiGrowablePoissonDisc13FilterRGB (sampler tSource, float2 texCoord, float2 pixelSize, float discRadius) { float3 cOut; float2 poisson[12] = {float2(-0.326212f, -0.40581f), float2(-0.840144f, -0.07358f), float2(-0.695914f, 0.457137f), float2(-0.203345f, 0.620716f), float2(0.96234f, -0.194983f), float2(0.473434f, -0.480026f), float2(0.519456f, 0.767022f), float2(0.185461f, -0.893124f), float2(0.507431f, 0.064425f), float2(0.89642f, 0.412458f), float2(-0.32194f, -0.932615f), float2(-0.791559f, -0.59771f)}; // Center tap cOut = tex2D (tSource, texCoord); for (int tap = 0; tap < 12; tap++) { float2 coord = texCoord.xy + (pixelSize * poisson[tap] * discRadius); // Sample pixel cOut += tex2D (tSource, coord); } return (cOut / 13.0f); }
Создание Объёмного Освещения в Реальном Времени • Мы видим только освещение, достигающее наших глаз, так каким же образом мы замечаем объёмное освещение? • Лучи света рассеиваются от подвешенных в воздухе частиц (либо любой другой среды, через которую проходят лучи света) • В этом случае тени, особенно динамические, выглядять очень драматичный эффект
Рассеянные Лучи Сквозь Пыльную Комнату From CSI
Примеры из Игр • Практически каждая игра так или иначе создает объёмное освещение • Zelda: Windwaker • Splinter Cell • Tomb Raider • I.C.O
Что же Именно Они Делают вЗельде? • Скорее всего используют самый простой алгоритм • Аддитивный блендинг полигонов, вытянутых по направлению от источника света • Они рисуются последними и просто с z-буферингом по всей сцене • Понижают яркость с растоянием
Затемнение По Растоянию • В-общем-то отличная идея для любых объектов • Мы можем использовать это для источников освещения даже когда мы не будем просчитывать рассеивание света из-за частиц в среде • Это может улучшить производительность distance
Проблема: Z-Buffering Против Сцены • Сцена рисуется до рисования объемного освещения • В этом случае, плоскости объемного освещения оставляют заметные линии в местах пересечений с геометрическими объектами в сцене
Отличный Визуальный Эффект • Из последнего Tomb Raider:
Как Были Нарисованы Эти Эффекты? • Большинство игр вытягивают контур окна либо формы источника света • В зависимости от угла обзора, это может быть очень сильно заметно • Так же достаточно сложно нарисовать по-настоящему объемное освещение либо изменять цвет • Использование системы частиц так же может неплохо выглядеть • Но сложно сделать хорошие тени
Возьмем Пример из Объемной Визуализации • Того же рода, как и просто объемная визуализацилия для медицинских программных приложений From [Dobashi00a]
Прорисовка Объемного Освещения • РазработаноДобашии Нишита • Занимает алгоритм из визуализации медицинских данных • Окрасьте плоскости в пространстве источника света • Скомпонуйте в буфер кадра, чтобы просчитать интеграл по векторам обзора (приблизительно) Light Space Sampling Planes Screen Viewpoint
Результати Проекта Добаши и Нишита