diff --git a/shaders/lighting.frag b/shaders/lighting.frag index 77736a2..f76f698 100644 --- a/shaders/lighting.frag +++ b/shaders/lighting.frag @@ -15,6 +15,7 @@ struct LightData vec3 color; vec3 attenuation; vec4 direction_angle; + mat4 vp[6]; }; layout(std140, binding = 2) uniform Light @@ -37,6 +38,7 @@ uniform sampler2D gNormal; uniform sampler2D gDiffuseP; uniform sampler2D gAmbientSpecular; uniform sampler2DArray sunShadowDepth; +uniform samplerCubeArray pointShadowDepth; out vec4 color; @@ -63,8 +65,10 @@ void main() vec3 fragPosLightSpace; // Фрагмент в пространстве источника float shadowValue; // Значение затененности vec2 texelSize = 1.0 / textureSize(sunShadowDepth, 0).xy; // Размер текселя текстуры теней - int x, y; // Счетчик для PCF + int x, y, z; // Счетчик для PCF float pcfDepth; // Глубина PCF + float cubemap_offset = 0.05f; // Отступ в текстурных координатах для PCF + float cubemap_depth; // Дистанция между фрагментом и источником в диапазоне [0;1] vec4 fragPosCamSpace = camera.view * vec4(fragPos, 1); // Фрагмент в пространстве камеры int cascade_index; // Индекс текущего каскада для вычисления теней @@ -119,43 +123,68 @@ void main() int i; for (i = 0; i < light_f.count; i++) { - // Данные об источнике относительно фрагмента - L_vertex = light_f.data[i].position - fragPos; - - // Расстояние от поверхности до источника - L_distance = length(L_vertex); - - // Проверка на дистанцию - if (L_distance < light_f.data[i].attenuation.r) + // Обнулим значение тени + shadowValue = 0; + // Позиция фрагмента относительно источника + fragPosLightSpace = fragPos - light_f.data[i].position; + // Дистанция между фрагментом и источником в диапазоне [0;1] + cubemap_depth = length(fragPosLightSpace) / light_f.data[i].attenuation.r; + // Сдвиг для решения проблемы акне + cubemap_depth -= max(0.05 * (1.0 - dot(N, light_f.data[i].direction_angle.xyz)), 0.005); + for(x = -1; x <= 1; ++x) { - // Нормирование вектора - L_vertex = normalize(L_vertex); - // арккосинус между вектором от поверхности к источнику и обратным направлением источника - acosA = degrees(acos(dot(-L_vertex, normalize(light_f.data[i].direction_angle.xyz)))); - // Если угол меньше угла источника или угол источника минимален, то считаем освещенность - if(acosA <= light_f.data[i].direction_angle.a) + for(y = -1; y <= 1; ++y) { - // Диффузная составляющая - diffuse = max(dot(L_vertex, N), 0.0); // скалярное произведение с отсеканием значений < 0 - - // Вектор половины пути - H = normalize(L_vertex + Cam_vertex); - // Зеркальная составляющая - specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p - - // Угасание с учетом расстояния - attenuation = 1 / (1 + light_f.data[i].attenuation[1] * L_distance + light_f.data[i].attenuation[2] * L_distance * L_distance); - - // Если источник - прожектор, то добавим смягчение - if (light_f.data[i].direction_angle.a < 180) + for(z = -1; z <= 1; ++z) { - intensity = clamp((light_f.data[i].direction_angle.a - acosA) / 5, 0.0, 1.0); - diffuse *= intensity; - specular *= intensity; + // Значение из кубической текстуры с учетом источника (i) + pcfDepth = texture(pointShadowDepth, vec4(fragPosLightSpace + vec3(x, y, z)*cubemap_offset, i)).r; + if(cubemap_depth > pcfDepth) + shadowValue += 1.0; } + } + } + shadowValue /= (27); + if (shadowValue < 1.0) + { + // Данные об источнике относительно фрагмента + L_vertex = light_f.data[i].position - fragPos; - color += vec4(light_f.data[i].color*kd*diffuse * attenuation, 1) - + vec4(light_f.data[i].color*ks*specular * attenuation, 1); + // Расстояние от поверхности до источника + L_distance = length(L_vertex); + + // Проверка на дистанцию + if (L_distance < light_f.data[i].attenuation.r) + { + // Нормирование вектора + L_vertex = normalize(L_vertex); + // арккосинус между вектором от поверхности к источнику и обратным направлением источника + acosA = degrees(acos(dot(-L_vertex, normalize(light_f.data[i].direction_angle.xyz)))); + // Если угол меньше угла источника или угол источника минимален, то считаем освещенность + if(acosA <= light_f.data[i].direction_angle.a) + { + // Диффузная составляющая + diffuse = max(dot(L_vertex, N), 0.0); // скалярное произведение с отсеканием значений < 0 + + // Вектор половины пути + H = normalize(L_vertex + Cam_vertex); + // Зеркальная составляющая + specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p + + // Угасание с учетом расстояния + attenuation = 1 / (1 + light_f.data[i].attenuation[1] * L_distance + light_f.data[i].attenuation[2] * L_distance * L_distance); + + // Если источник - прожектор, то добавим смягчение + if (light_f.data[i].direction_angle.a < 180) + { + intensity = clamp((light_f.data[i].direction_angle.a - acosA) / 5, 0.0, 1.0); + diffuse *= intensity; + specular *= intensity; + } + + color += ( vec4(light_f.data[i].color*kd*diffuse * attenuation, 1) + + vec4(light_f.data[i].color*ks*specular * attenuation, 1) ) * (1.0 - shadowValue); + } } } }