skyforge rendering tech (kri 2014)
TRANSCRIPT
SKYFORGE: Технологии рендерингаСергей Макеев, технический директор
План! Что такое Skyforge?! Графические технологии, использованные при разработке графического движка Skyforge
! Physically Based Shading! Deferred Shading! Reversed Depth buffer
! Выводы! Q&A
Skyforge для программиста
! Fantasy + Sci-fi ! Свой движок! Nextgen графика в MMO! Стилизованная реальность! Огромные открытые локации! Материалы и освещение максимально естественны! 4 графических программиста
Physically Based Shading
Зачем ?! Зачем нужен шейдинг, основанный на физике?
! Более реалистичная и сведенная картинка – меньше настраивать
! Материалы и свет разделены – меньше настраивать! Меньше параметров в материале – меньше настраивать! Соблюдается закон сохранения энергии – меньше настраивать
! Физически корректно не значит фотореалистично(см. работы Disney, Pixar и т.д.)
Физика процесса! В реальной жизни поверхность не гладкая! Поверхность объектов состоит из множества маленьких неровностей. Эти неровности настолько маленькие, что не видны невооруженным глазом! Размер микронеровностей больше длины волны и они влияют на отражение света от поверхности
Бумага под электронным микроскопом
Бумага под электронным микроскопом
Микрогеометрия поверхности! Часть света отражается от поверхности! Часть проникает внутрь поверхности и переизлучается или поглощается
Микрогеометрия поверхности! Мы оперируем на уровне пикселей! Нужно учитывать отраженный и переизлученный свет
! BRDF ! Bidirectional! Reflection! Distribution! Function
! Цель: рассчитать количество энергии, излучаемой в сторону наблюдателя, при заданном входящем излучении! В теории, многомерная функция - 3D, 4D, 6D! На практике, мы будем рассматривать функцию от двух параметров
BRDF
Рассеянный свет (diffuse)! Можно пренебречь точкой входа и выхода луча! Считаем, что весь рассеянный свет распределяется равномерно
Рассеянный свет (diffuse)! Функция для расчета рассеянного света
! l – направление света! v – направление взгляда (не используется в данной модели)! albedo – векторный параметр, который определяет сколько энергии рассеивается, а сколько поглощается материалом ! n – нормаль поверхности! Деление на PI закон сохранения энергии
! Всем известный dot ( N, L )! dot ( N, L ) это cos между векторами N, L
Рассеянный свет (diffuse)! Площадь проекции зависит от угла падения! И равна cos(N, L)
Рассеянный свет (diffuse)! На поверхность попадает меньше энергии в зависимости от угла падения
Отраженный свет (specular)! Отражение света
! Направление отражения меняетсяиз-за микрограней
Отраженный свет (specular)! Отражение света
! Менее гладкая поверхность
Микрогеометрия поверхности! Microfacet theory
! Моделирует поверхность как множество микрограней
! Каждая микрогрань - идеально отражающее зеркало
! Нам нужна сумма вклада каждой микрограни в освещение (интеграл)
! Слишком много вычислений, чтобы решить численно
Microfacet BRDF! Функция для расчета отраженного света (microfacet theory)
! D – функция распределения нормали. Определяет, как микрограни распределены вдоль направления h (от этой функции меняется форма блика)! F – формула Френеля! G – функция затенения микрогранями друг друга
! l – направление света! v – направление взгляда! n – нормаль поверхности! h – вектор между векторами l and v (half vector)
Half vector! Half vector, вектор между L и V! Физический смысл half vector
! Фильтрация микрограней, которые вносят вклад в BRDF! h = m значит микрогрань отражает свет, видимый наблюдателю
Microfacet BRDF! Функция для расчета отраженного света (microfacet theory)
! D – функция распределения нормали. Определяет, как микрограни распределены вдоль направления h (от этой функции меняется форма блика)! F – формула Френеля! G – функция затенения микрогранями друг друга
! l – направление света! v – направление взгляда! n – нормаль поверхности! h – вектор между векторами l and v (half vector)
Распределение микрограней! Степень косинуса в качестве функции распределения микрограней (Blinn-Phong)! Степень 0.25 .. 65536
Microfacet BRDF! Функция для расчета отраженного света (microfacet theory)
! D – функция распределения нормали. Определяет, как микрограни распределены вдоль направления h (от этой функции меняется форма блика)! F – формула Френеля! G – функция затенения микрогранями друг друга
! l – направление света! v – направление взгляда! n – нормаль поверхности! h – вектор между векторами l and v (half vector)
Френель!ло
Френель
Френель! Аппроксимация Шлика
! f0 – можно получить из IOR (Index of refraction)
Френель! Френель: задает, сколько света будет поглощено, а сколько отражено под разными углами
! Физический смысл f0: процент света, отраженный от материала под прямым углом
! Обычное значение f0 для диэлектриков 2% - 5%
! Металлы рассеивают мало света, в основном отражают
Microfacet BRDF! Функция для расчета отраженного света (microfacet theory)
! D – функция распределения нормали. Определяет, как микрограни распределены вдоль направления h (от этой функции меняется форма блика)! F – формула Френеля! G – функция затенения микрогранями друг друга
! l – направление света! v – направление взгляда! n – нормаль поверхности! h – вектор между векторами l and v (half vector)
Microfacet BRDF! Пример того, какая часть света скрывается микрогранями
Видимость микрограней
! Используем простейшую функцию видимости
! Функция отраженного света! Соответствует normalized Blinn-Phong model
Отраженный свет (specular)
Изменение параметров! Изменение F0 ( IOR )
! Изменение шероховатости
Сохранение энергии! Закон сохранения энергии
! Количество отраженного света <= 1! Т.е. рассеянный + отраженный свет <= 1
! Из этого следует: яркость и площадь блика от источника света связаны
Шероховатость 100%
Шероховатость 80%
Шероховатость 50%
Шероховатость 30%
Шероховатость 10%
Интенсивность света! Интенсивность света обратно пропорциональна квадрату расстояния до источника света
! Хорошо подходит для точечных источников, не имеющих объема! Мы хотим источник света, у которого есть размер (area light)! Стремится к нулю, но никогда его не достигает
Интенсивность света! Нужно учесть два радиуса
! Rinner – размер источника! Router – дистанция, на которой вкладом в освещение можно пренебречь
Интенсивность света! Наша функция затухания! Константа внутри Rinner
! На дистанции Router равна 0
float GetAttenuation(float distance, float lightInnerR, float invLightOuterR){ float d = max(distance, lightInnerR); return saturate(1.0 - pow(d * invLightOuterR, 4.0)) / (d * d + 1.0);}
Интенсивность света! График затухания света
Модель материала! Модель материала
! Base color! Albedo для диэлектрика! Векторная часть F0 для проводника
! Normal (нормаль поверхности, макро)! Roughness (шероховатость поверхности, микро)! Fresnel F0 (практически всегда константа для диэлектрика, скалярная часть F0 для металла)
! Metal (маска: металл или диэлектрик)
Base color ( Albedo )
Base color ( Albedo )
Normal map
Gloss (Roughness)
Specular ( F0 / IOR )
Metal
Пример материала
Пример материала
Пример материала
Пример материала
Пример материала
Пример материала
Deferred Shading
Deferred shading! Плюсы
! Геометрия отделена от освещения! Много источников света! Нет комбинаторного взрыва в шейдерах
! Минусы! Bandwidth! Источники света с тенями по-прежнему дорогие! Сложность с разными BRDF! Поддержка прозрачности
Deferred shading! Skyforge Gbuffer layout (2xRGBA8, 1xRGB10A2, 1xD24S8)
! 96 bits + 24 bits + 8 bits = 128 bits per pixel
Финальный результат
Base color
Нормали (world space)
Шероховатость
Fresnel reflectance (F0)
Metallic
HDR: Global Illumination + Emissive
Ambient occlusion
Без локального освещения и волюметриков
Финальный результат
Tips & Tricks
Реконструкция позиции! Алгоритмам освещения нужна позиция
! world space! shadow space! view space! и т.д.
! В Gbuffer хранится только глубина! используем INTZ (DX9)! гиперболическое распределение "
! Нужна реконструкция позиции из глубины
Реконструкция позиции! Преобразуем depth буфер в линейный! INTZ в R32F! Сразу после заполнения Gbuffer
// Функция для преобразования глубины с гиперболическим распределением в линейнуюfloat ConvertHyperbolicDepthToLinear(float hyperbolicDepth){ return ((zNear / (zNear-zFar)) * zFar) / (hyperbolicDepth - (zFar / (zFar-zNear)));}
Подобие треугольников! Треугольник P1, P2, P3 подобен треугольнику P1, P4, P5
Подобие треугольников! Треугольник P1, P2, P3
Подобие треугольников! Треугольник P1, P4, P5
Реконструкция позиции! Вершинный шейдер
! Считаем треугольник P1, P2, P3 в вершинном шейдере! Передаем отрезок P1, P3 в пиксельный шейдер
! Пиксельный шейдер! Получаем интерполированный вектор P1,P3 (rayDir) через интерполятор! Считываем линейную глубину! position = cameraPosition + rayDir * linearDepth
! Очень быстро: mad + интерполятор! Можно реконструировать позицию в любом удобном пространстве. world, view, shadow и т.д.! HLSL код в бонус слайдах
Reversed Depth Buffer
Большая дальность видимости
Большая дальность видимости
Большая дальность видимости
Большая дальность видимости
Reversed Depth Buffer! Reversed depth buffer
near = 1far = 0
! Работает с fixed point depth, формат D24S8! Нужно инвертировать D3DRS_ZFUNC
D3DCMP_GREATEREQUAL! Всегда инвертируйте матрицу проекции
Некорректно инвертировать на стадии viewport’а или в шейдере
Матрица проекции
! Как получается глубина?! float4 p = mul( float4( pos, 1 ), mtxProjection );! float depth = p.z / p.w;
Матрица проекции
Сравнение методов! Z near = 0.5! Z far = 50000.0
Сравнение методов! Стандартный метод
! Reversed depth buffer
Сравнение методов! Стандартный метод
! Reversed depth buffer
Numeric error – стандартный метод
Numeric error – reversed depth buffer
Numeric error – reversed depth buffer
Reversed depth buffer : выводы
! D24 легко покрывает дальность в 50 км! Reverse depth подходит для любого движка! Лучше закладывать с самого начала проекта
! Извлечение плоскостей фрустума из матрицы! Bias у теней! и т.д.
! При возможности используйте float depth буфер
Заключение! Nextgen графика в MMO уже реальность
! Все меньше отличий от ААА консольных тайтлов
! Физичный шейдинг упрощает производство контента
! Нам нужны графические программисты !
СПАСИБО ЗА ВНИМАНИЕ!ВОПРОСЫ[email protected]
Bonus
Реконструкция позиции: Vertex shader
// Часть матрицы проекцииfloat tanHalfVerticalFov; // invProjection.11;float tanHalfHorizontalFov; // invProjection.00;
// Базис камеры в пространстве реконструкцииfloat3 camBasisUp;float3 camBasisSide;float3 camBasisFront;
// postProjectiveSpacePosition в homogeneous projection spacefloat3 CreateRay(float4 postProjectiveSpacePosition){ float3 leftRight = camBasisSide * -postProjectiveSpacePosition.x * tanHalfHorizontalFov; float3 upDown = camBasisUp * postProjectiveSpacePosition.y * tanHalfVerticalFov; float3 forward = camBasisFront; return (forward + leftRight + upDown);}
void VertexShader(float4 inPos, out float4 outPos : POSITION, out float3 rayDir : TEXCOORD0){ outPos = inPos; rayDir = CreateRay(inPos);}
Реконструкция позиции: Pixel shader
// Позиция камеры в пространстве реконструкцииfloat3 camPosition;
float4 PixelShader(float3 rayDir : TEXCOORD0) : COLOR0{ ... float linearDepth = tex2D(linearDepthSampler, uv).r; float3 position = camPosition + rayDir * linearDepth; ...}
// Функция для преобразования глубины с гиперболическим распределением в линейнуюfloat ConvertHyperbolicDepthToLinear(float hyperbolicDepth){ return ((zNear / (zNear-zFar)) * zFar) / (hyperbolicDepth - (zFar / (zFar-zNear)));}