Полностью корректный кольцевой буффер
This commit is contained in:
@@ -20,18 +20,27 @@ out vec4 FragColor;
|
||||
// Настройки
|
||||
//------------------------------------------------------------
|
||||
|
||||
const float STEP_SIZE = 0.5;
|
||||
const float MAX_DISTANCE = 256.0;
|
||||
const int MAX_STEPS = int(MAX_DISTANCE / STEP_SIZE);
|
||||
|
||||
// Размер туманного объёма
|
||||
const float FOG_SIZE_X = 256.0;
|
||||
const float FOG_SIZE_Z = 256.0;
|
||||
const float FOG_SIZE_Z = FOG_SIZE_X;
|
||||
|
||||
const int MAX_STEPS = 256; // Уменьшили количество шагов благодаря адаптивности
|
||||
|
||||
// Высота мира
|
||||
const float WORLD_BOTTOM = -64.0;
|
||||
const float WORLD_HEIGHT = 384.0;
|
||||
|
||||
const float MAX_DISTANCE = (FOG_SIZE_X / 2.0) - 18.0;
|
||||
|
||||
// Коэффициент нелинейности распределения шагов:
|
||||
// 1.0 = равномерные шаги (как было)
|
||||
// 1.5 = мягкое увеличение (рекомендуется для начала)
|
||||
// 2.0 = линейный рост размера шага с расстоянием (хороший баланс)
|
||||
// 2.5 = более агрессивное увеличение (лучшая производительность)
|
||||
const float GAMMA = 2.0;
|
||||
|
||||
// Включение jittering для устранения banding артефактов
|
||||
const bool USE_JITTERING = true;
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
vec3 reconstructViewPosition(vec2 uv)
|
||||
@@ -68,23 +77,19 @@ float density(vec3 worldPos)
|
||||
float localZ = worldPos.z - float(FogOrigin.y);
|
||||
|
||||
if (
|
||||
localX < 0.0 || localX >= FOG_SIZE_X ||
|
||||
localZ < 0.0 || localZ >= FOG_SIZE_Z ||
|
||||
worldPos.y < WORLD_BOTTOM ||
|
||||
worldPos.y >= WORLD_BOTTOM + WORLD_HEIGHT
|
||||
localX < 0.0 || localX >= FOG_SIZE_X ||
|
||||
localZ < 0.0 || localZ >= FOG_SIZE_Z ||
|
||||
worldPos.y < WORLD_BOTTOM ||
|
||||
worldPos.y >= WORLD_BOTTOM + WORLD_HEIGHT
|
||||
){
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float physicalX = mod(
|
||||
localX + float(RingBlockOffset.x),
|
||||
FOG_SIZE_X
|
||||
);
|
||||
float physicalX =
|
||||
localX + float(RingBlockOffset.x);
|
||||
|
||||
float physicalZ = mod(
|
||||
localZ + float(RingBlockOffset.y),
|
||||
FOG_SIZE_Z
|
||||
);
|
||||
float physicalZ =
|
||||
localZ + float(RingBlockOffset.y);
|
||||
|
||||
uv.x = physicalX / FOG_SIZE_X;
|
||||
uv.z = physicalZ / FOG_SIZE_Z;
|
||||
@@ -95,6 +100,21 @@ float density(vec3 worldPos)
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
// Псевдослучайное значение для jittering (детерминированное по UV)
|
||||
float random(vec2 st)
|
||||
{
|
||||
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
||||
}
|
||||
|
||||
// Функция нелинейного маппинга параметра t [0,1] в расстояние
|
||||
// Использует степенную функцию для распределения шагов
|
||||
float mapParameterToDistance(float t)
|
||||
{
|
||||
return MAX_DISTANCE * pow(t, GAMMA);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 sceneColor = texture(DiffuseSampler, texCoord);
|
||||
@@ -109,17 +129,52 @@ void main()
|
||||
vec3 samplePos = CameraPosition;
|
||||
|
||||
float fog = 0.0;
|
||||
float currentDistance = 0.0;
|
||||
|
||||
for (int i = 0; i < MAX_STEPS; i++)
|
||||
{
|
||||
float traveled = float(i) * STEP_SIZE;
|
||||
// Jittering начальной позиции для устранения banding (ступенчатых артефактов)
|
||||
// Это стандартная техника в volumetric rendering
|
||||
float jitter = 0.0;
|
||||
if (USE_JITTERING) {
|
||||
// Вычисляем размер первого шага для корректного jittering
|
||||
float firstStep = mapParameterToDistance(1.0 / float(MAX_STEPS));
|
||||
jitter = random(texCoord) * firstStep;
|
||||
currentDistance = jitter;
|
||||
samplePos += rayDir * currentDistance;
|
||||
}
|
||||
|
||||
if (traveled >= rayLength)
|
||||
break;
|
||||
for (int i = 0; i < MAX_STEPS; i++) {
|
||||
// Параметр t меняется от 0 до 1
|
||||
float t = float(i + 1) / float(MAX_STEPS);
|
||||
|
||||
samplePos += rayDir * STEP_SIZE;
|
||||
// Вычисляем следующее расстояние через нелинейное маппинг
|
||||
float nextDistance = mapParameterToDistance(t);
|
||||
|
||||
fog += density(samplePos) * STEP_SIZE;
|
||||
// Ограничиваем максимальной длиной луча
|
||||
if (nextDistance > rayLength) {
|
||||
nextDistance = rayLength;
|
||||
}
|
||||
|
||||
// Размер текущего шага
|
||||
float stepSize = nextDistance - currentDistance;
|
||||
|
||||
// Проверяем, не вышли ли за пределы луча
|
||||
if (stepSize <= 0.0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Продвигаемся по лучу
|
||||
samplePos += rayDir * stepSize;
|
||||
|
||||
// Интегрируем плотность (Beer-Lambert law approximation)
|
||||
// Важно умножать на stepSize для корректной физической модели
|
||||
fog += density(samplePos) * stepSize;
|
||||
|
||||
currentDistance = nextDistance;
|
||||
|
||||
// Прерываем, если достигли конца луча
|
||||
if (currentDistance >= rayLength) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fog = clamp(fog, 0.0, 1.0);
|
||||
|
||||
Reference in New Issue
Block a user