From ca96174b6b83ec8da2d79680cc470d1859e61323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Br=C3=BCckner?= Date: Sat, 14 Aug 2021 23:45:33 +0200 Subject: [PATCH] Fix nishita sky artifacts on some GPUs It could happen that values returned by dot() were slightly larger than 1 or less than -1 due to precision errors, but acos() is undefined outside of [-1, 1]. This would lead to NaN values on some GPUs, causing visible artifacts. --- Shaders/std/math.glsl | 5 +++++ Shaders/std/sky.glsl | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Shaders/std/math.glsl b/Shaders/std/math.glsl index 93293401..279b9898 100755 --- a/Shaders/std/math.glsl +++ b/Shaders/std/math.glsl @@ -40,4 +40,9 @@ float attenuate(const float dist) { // 1.0 / (quadratic * dist * dist); } +float safe_acos(const float x) { + // acos is undefined if |x| > 1 + return acos(clamp(x, -1.0, 1.0)); +} + #endif diff --git a/Shaders/std/sky.glsl b/Shaders/std/sky.glsl index e192bb11..112aaff1 100644 --- a/Shaders/std/sky.glsl +++ b/Shaders/std/sky.glsl @@ -20,6 +20,8 @@ #ifndef _SKY_GLSL_ #define _SKY_GLSL_ +#include "std/math.glsl" + uniform sampler2D nishitaLUT; uniform vec2 nishitaDensity; @@ -119,7 +121,7 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa // Idea behind this: "Rotate" everything by iPos (-> iPos is the new zenith) and then all calculations for the // inner integral only depend on the sample height (iHeight) and sunTheta (angle between sun and new zenith). - float sunTheta = acos(dot(normalize(iPos), normalize(pSun))); + float sunTheta = safe_acos(dot(normalize(iPos), normalize(pSun))); vec3 jAttn = nishita_lookupLUT(iHeight, sunTheta); // Calculate attenuation