[vlc-devel] [PATCH 2/2] viewpoint: rotate 360 sphere and cube to -pi/2

Alexandre Janniaux ajanni at videolabs.io
Sat Jan 9 14:10:47 UTC 2021


Renderers in OpenGL and D3D11 were adding +pi/2 to yaw when generating
the View matrix. This additional +pi/2 is ought to be understood as a
-pi/2 angle on yaw instead since the matrix is written transposed.

This additional angle stems from the sphere coordinates being mapped
from 0 to 2.pi while the texture itself is conceived to be mapped on
the segment [-pi/2; 3.pi/2] instead.

This patch "hardcode" the -pi/2 rotation in the sphere mesh by matching
the generated coordinates with the ones expected for the texture
mapping, thus removing the pi/2 rotation in the View matrix.

The rotation was initially added in the following commit:
08207425d8d260a6650a332c4c7c7b040ff48b15

No additional rotation is done for D3D11 cube because it was already
accidentally rotated in ec0b151f397bf4470f58aa55daa9f7b2068113a4.
---
 modules/video_output/opengl/renderer.c  | 64 +++++++++++++++----------
 modules/video_output/win32/d3d11_quad.c |  4 +-
 src/misc/viewpoint.c                    |  2 +-
 3 files changed, 41 insertions(+), 29 deletions(-)

diff --git a/modules/video_output/opengl/renderer.c b/modules/video_output/opengl/renderer.c
index 795754f900..a6d1b65508 100644
--- a/modules/video_output/opengl/renderer.c
+++ b/modules/video_output/opengl/renderer.c
@@ -494,18 +494,30 @@ static int BuildSphere(GLfloat **vertexCoord, GLfloat **textureCoord, unsigned *
 
         sincosf(theta, &sinTheta, &cosTheta);
 
-        for (unsigned lon = 0; lon <= nbLonBands; lon++) {
-            float phi = lon * 2 * (float) M_PI / nbLonBands;
+        for (unsigned int lon = 0; lon <= nbLonBands; lon++) {
+            float phi =  2.f * (float)M_PI * (float)lon / nbLonBands;
             float sinPhi, cosPhi;
 
             sincosf(phi, &sinPhi, &cosPhi);
 
-            float x = cosPhi * sinTheta;
+            /* The camera is centered on the Z axis when yaw = 0, while the
+             * front part of the equirectangular texture is located at u=0.5.
+             * To have the camera at the correct location, phi is
+             * shifted +pi/2 to have u=0.5 fall at the correct location.
+             *
+             * Another way to interpret the shift is to interpret the shift
+             * as a shift in texture coordinate. Considering the initial
+             * orientation of the camera to Z which accounts as a pi/2
+             * rotation, adding pi/2 maps the first and last coordinate to the
+             * meridian, pi radians after the camera, so that u=0 amd u=1, ie.
+             * the back face, is mapped to the back of the initial orientation
+             * of the camera. */
+            float x = -sinPhi * sinTheta;
             float y = cosTheta;
-            float z = sinPhi * sinTheta;
+            float z = cosPhi * sinTheta;
 
             unsigned off1 = (lat * (nbLonBands + 1) + lon) * 3;
-            (*vertexCoord)[off1] = SPHERE_RADIUS * x;
+            (*vertexCoord)[off1 + 0] = SPHERE_RADIUS * x;
             (*vertexCoord)[off1 + 1] = SPHERE_RADIUS * y;
             (*vertexCoord)[off1 + 2] = SPHERE_RADIUS * z;
 
@@ -568,15 +580,15 @@ static int BuildCube(float padW, float padH,
     swap(value,  1.f,  1.f), \
     swap(value,  1.f, -1.f)
 
-#define X_FACE(v, a, b) (v), (a), (b)
+#define X_FACE(v, a, b) (v), (b), (a)
 #define Y_FACE(v, a, b) (a), (v), (b)
 #define Z_FACE(v, a, b) (a), (b), (v)
 
     static const GLfloat coord[] = {
-        CUBEFACE(X_FACE, -1.f), // FRONT
-        CUBEFACE(X_FACE, +1.f), // BACK
-        CUBEFACE(Z_FACE, +1.f), // LEFT
-        CUBEFACE(Z_FACE, -1.f), // RIGHT
+        CUBEFACE(Z_FACE, -1.f), // FRONT
+        CUBEFACE(Z_FACE, +1.f), // BACK
+        CUBEFACE(X_FACE, -1.f), // LEFT
+        CUBEFACE(X_FACE, +1.f), // RIGHT
         CUBEFACE(Y_FACE, -1.f), // BOTTOM
         CUBEFACE(Y_FACE, +1.f), // TOP
     };
@@ -592,15 +604,15 @@ static int BuildCube(float padW, float padH,
     float row[] = {0.f, 1.f/2, 1.0};
 
     const GLfloat tex[] = {
-        col[1] + padW, row[0] - padH, // front
-        col[2] + padW, row[0] + padH,
-        col[1] - padW, row[1] - padH,
-        col[2] - padW, row[1] + padH,
-
-        col[3] - padW, row[0] - padH, // back
+        col[1] + padW, row[1] - padH, // front
+        col[1] + padW, row[0] + padH,
+        col[2] - padW, row[1] - padH,
         col[2] - padW, row[0] + padH,
-        col[3] + padW, row[1] - padH,
-        col[2] + padW, row[1] + padH,
+
+        col[3] - padW, row[1] - padH, // back
+        col[3] - padW, row[0] + padH,
+        col[2] + padW, row[1] - padH,
+        col[2] + padW, row[0] + padH,
 
         col[2] - padW, row[2] - padH, // left
         col[2] - padW, row[1] + padH,
@@ -612,15 +624,15 @@ static int BuildCube(float padW, float padH,
         col[1] - padW, row[2] - padH,
         col[1] - padW, row[1] + padH,
 
-        col[0] + padW, row[1] + padH, // bottom
-        col[1] + padW, row[1] - padH,
-        col[0] - padW, row[0] + padH,
-        col[1] - padW, row[0] - padH,
+        col[0] + padW, row[0] + padH, // bottom
+        col[0] + padW, row[1] - padH,
+        col[1] - padW, row[0] + padH,
+        col[1] - padW, row[1] - padH,
 
-        col[2] + padW, row[1] - padH, // top
-        col[3] + padW, row[1] + padH,
-        col[2] - padW, row[2] - padH,
-        col[3] - padW, row[2] + padH,
+        col[2] + padW, row[2] - padH, // top
+        col[2] + padW, row[1] + padH,
+        col[3] - padW, row[2] - padH,
+        col[3] - padW, row[1] + padH,
     };
 
     memcpy(*textureCoord, tex,
diff --git a/modules/video_output/win32/d3d11_quad.c b/modules/video_output/win32/d3d11_quad.c
index 1caf64635f..0928155fea 100644
--- a/modules/video_output/win32/d3d11_quad.c
+++ b/modules/video_output/win32/d3d11_quad.c
@@ -427,9 +427,9 @@ static void SetupQuadSphere(d3d_vertex_t *dst_data, const RECT *output,
 
             sincosf(phi, &sinPhi, &cosPhi);
 
-            float x = cosPhi * sinTheta;
+            float x = -sinPhi * sinTheta;
             float y = cosTheta;
-            float z = sinPhi * sinTheta;
+            float z = cosPhi * sinTheta;
 
             unsigned off1 = lat * (nbLonBands + 1) + lon;
             dst_data[off1].position.x = SPHERE_RADIUS * x;
diff --git a/src/misc/viewpoint.c b/src/misc/viewpoint.c
index c4b6aa4f04..6d5aeaf2bd 100644
--- a/src/misc/viewpoint.c
+++ b/src/misc/viewpoint.c
@@ -28,7 +28,7 @@
 
 void vlc_viewpoint_to_4x4( const vlc_viewpoint_t *vp, float *m )
 {
-    float yaw   = -vp->yaw   * (float)M_PI / 180.f + (float)M_PI_2;
+    float yaw   = -vp->yaw   * (float)M_PI / 180.f;
     float pitch = -vp->pitch * (float)M_PI / 180.f;
     float roll  = -vp->roll  * (float)M_PI / 180.f;
 
-- 
2.30.0



More information about the vlc-devel mailing list