diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 28 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 8 |
2 files changed, 32 insertions, 4 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d70d62ede..6ed67efeb 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -158,12 +158,34 @@ void RasterizerOpenGL::Reset() { | |||
| 158 | res_cache.InvalidateAll(); | 158 | res_cache.InvalidateAll(); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | /** | ||
| 162 | * This is a helper function to resolve an issue with opposite quaternions being interpolated by | ||
| 163 | * OpenGL. See below for a detailed description of this issue (yuriks): | ||
| 164 | * | ||
| 165 | * For any rotation, there are two quaternions Q, and -Q, that represent the same rotation. If you | ||
| 166 | * interpolate two quaternions that are opposite, instead of going from one rotation to another | ||
| 167 | * using the shortest path, you'll go around the longest path. You can test if two quaternions are | ||
| 168 | * opposite by checking if Dot(Q1, W2) < 0. In that case, you can flip either of them, therefore | ||
| 169 | * making Dot(-Q1, W2) positive. | ||
| 170 | * | ||
| 171 | * NOTE: This solution corrects this issue per-vertex before passing the quaternions to OpenGL. This | ||
| 172 | * should be correct for nearly all cases, however a more correct implementation (but less trivial | ||
| 173 | * and perhaps unnecessary) would be to handle this per-fragment, by interpolating the quaternions | ||
| 174 | * manually using two Lerps, and doing this correction before each Lerp. | ||
| 175 | */ | ||
| 176 | static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) { | ||
| 177 | Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() }; | ||
| 178 | Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() }; | ||
| 179 | |||
| 180 | return (Math::Dot(a, b) < 0.f); | ||
| 181 | } | ||
| 182 | |||
| 161 | void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, | 183 | void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, |
| 162 | const Pica::Shader::OutputVertex& v1, | 184 | const Pica::Shader::OutputVertex& v1, |
| 163 | const Pica::Shader::OutputVertex& v2) { | 185 | const Pica::Shader::OutputVertex& v2) { |
| 164 | vertex_batch.emplace_back(v0); | 186 | vertex_batch.emplace_back(v0, false); |
| 165 | vertex_batch.emplace_back(v1); | 187 | vertex_batch.emplace_back(v1, AreQuaternionsOpposite(v0.quat, v1.quat)); |
| 166 | vertex_batch.emplace_back(v2); | 188 | vertex_batch.emplace_back(v2, AreQuaternionsOpposite(v0.quat, v2.quat)); |
| 167 | } | 189 | } |
| 168 | 190 | ||
| 169 | void RasterizerOpenGL::DrawTriangles() { | 191 | void RasterizerOpenGL::DrawTriangles() { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b9c1d61bd..99266854c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -248,7 +248,7 @@ private: | |||
| 248 | 248 | ||
| 249 | /// Structure that the hardware rendered vertices are composed of | 249 | /// Structure that the hardware rendered vertices are composed of |
| 250 | struct HardwareVertex { | 250 | struct HardwareVertex { |
| 251 | HardwareVertex(const Pica::Shader::OutputVertex& v) { | 251 | HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion) { |
| 252 | position[0] = v.pos.x.ToFloat32(); | 252 | position[0] = v.pos.x.ToFloat32(); |
| 253 | position[1] = v.pos.y.ToFloat32(); | 253 | position[1] = v.pos.y.ToFloat32(); |
| 254 | position[2] = v.pos.z.ToFloat32(); | 254 | position[2] = v.pos.z.ToFloat32(); |
| @@ -270,6 +270,12 @@ private: | |||
| 270 | view[0] = v.view.x.ToFloat32(); | 270 | view[0] = v.view.x.ToFloat32(); |
| 271 | view[1] = v.view.y.ToFloat32(); | 271 | view[1] = v.view.y.ToFloat32(); |
| 272 | view[2] = v.view.z.ToFloat32(); | 272 | view[2] = v.view.z.ToFloat32(); |
| 273 | |||
| 274 | if (flip_quaternion) { | ||
| 275 | for (float& x : normquat) { | ||
| 276 | x = -x; | ||
| 277 | } | ||
| 278 | } | ||
| 273 | } | 279 | } |
| 274 | 280 | ||
| 275 | GLfloat position[4]; | 281 | GLfloat position[4]; |