Skybox/cubemap mistextured

I’ve written this little program to create a cubemap:

from direct.showbase.ShowBase import ShowBase
import sys

class MyApp(ShowBase):
    def __init__(self):
        # The basics
        ShowBase.__init__(self)
        base.disableMouse()
        scene = self.loader.loadModel("models/environment")
        scene.reparent_to(self.render)
        scene.set_scale(0.25, 0.25, 0.25)
        scene.set_pos(-8, 42, 0)
        self.camera.set_pos(0,0,3)
        base.saveCubeMap('grassy_#.jpg', size = 512)
        sys.exit()
        
app = MyApp()
app.run()

…and this one to display it (the salient part being the one after the comment “The skybox part”):

from direct.showbase.ShowBase import ShowBase
from panda3d.core import TextureStage, TexGenAttrib
from direct.task import Task
from math import sin, cos, pi
import sys

class MyApp(ShowBase):
    def __init__(self):
        # The basics
        ShowBase.__init__(self)
        base.disableMouse()
        # A model in the center
        m = self.loader.loadModel("models/smiley")
        m.reparentTo(self.render)
        m.setPos(0,0,0)
        # The skybox part
        skybox = self.loader.loadModel("skybox")
        skybox.setScale(5)
        skybox.reparentTo(self.camera)
        skybox.set_two_sided(True)
        skybox.set_bin("background", 0)
        skybox.set_depth_write(False)
        skybox.set_compass()
        tex = loader.loadCubeMap('grassy_#.jpg')
        skybox.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap)
        skybox.setTexture(tex)
        # Bookkeeping for the rotation around the model
        self.angle = 0.0
        self.pitch = 0.0
        self.adjust_angle = 0
        self.adjust_pitch = 0
        self.last_time = 0.0
        # Initial camera setup
        self.camera.set_pos(sin(self.angle)*20,-cos(self.angle)*20,0)
        self.camera.look_at(0,0,0)
        # Key events and camera movement task
        self.accept("arrow_left", self.adjust_turning, [-1.0, 0.0])
        self.accept("arrow_left-up", self.adjust_turning, [1.0, 0.0])
        self.accept("arrow_right", self.adjust_turning, [1.0, 0.0])
        self.accept("arrow_right-up", self.adjust_turning, [-1.0, 0.0])
        self.accept("arrow_up", self.adjust_turning, [0.0, 1.0])
        self.accept("arrow_up-up", self.adjust_turning, [0.0, -1.0])
        self.accept("arrow_down", self.adjust_turning, [0.0, -1.0])
        self.accept("arrow_down-up", self.adjust_turning, [0.0, 1.0])
        self.accept("escape", sys.exit)
        self.taskMgr.add(self.update_camera, 'adjust camera', sort = 10)
    def adjust_turning(self, heading, pitch):
        self.adjust_angle += heading
        self.adjust_pitch += pitch
    def update_camera(self, task):
        if task.time != 0.0:
            dt = task.time - self.last_time
            self.last_time = task.time
            self.angle += pi * dt * self.adjust_angle
            self.pitch += pi * dt * self.adjust_pitch
            # Why /2.001 and not an even 2.0? Because then we'd have to set_Hpr
            # explicitly, as look_at can't deduce the heading when the camera is
            # exactly above/below the spheres center.
            if self.pitch > pi/2.001:
                self.pitch = pi/2.001
            if self.pitch < -pi/2.001:
                self.pitch = -pi/2.001
            self.camera.set_pos(sin(self.angle)*cos(abs(self.pitch))*20,
                                -cos(self.angle)*cos(abs(self.pitch))*20,
                                sin(self.pitch)*20)
            self.camera.look_at(0,0,0)
        return Task.cont

app = MyApp()
app.run()

As I was lacking knowledge of a good default model to use as a skybox, I created this skybox.egg in blender:

<CoordinateSystem> { Z-up } 
<Material> Material {
  <Scalar> diffr { 0.640000 }
  <Scalar> diffg { 0.640000 }
  <Scalar> diffb { 0.640000 }
  <Scalar> specr { 0.500000 }
  <Scalar> specg { 0.500000 }
  <Scalar> specb { 0.500000 }
  <Scalar> shininess { 12.5 }
  <Scalar> emitr { 0.000000 }
  <Scalar> emitg { 0.000000 }
  <Scalar> emitb { 0.000000 }
}

  <Group> Cube {
    <Transform> {
      <Matrix4> {
        1.000000 0.000000 0.000000 0.000000 
        0.000000 1.000000 0.000000 0.000000 
        0.000000 0.000000 1.000000 0.000000 
        0.000000 0.000000 0.000000 1.000000 
      }
    }
    
    <VertexPool> Cube {
    
      <Vertex> 0 {
        1.0 0.9999999403953552 -1.0
      }
      <Vertex> 1 {
        1.0 -1.0 -1.0
      }
      <Vertex> 2 {
        -1.0000001192092896 -0.9999998211860657 -1.0
      }
      <Vertex> 3 {
        -0.9999996423721313 1.0000003576278687 -1.0
      }
      <Vertex> 4 {
        1.0000004768371582 0.999999463558197 1.0
      }
      <Vertex> 5 {
        -0.9999999403953552 1.0 1.0
      }
      <Vertex> 6 {
        -1.0000003576278687 -0.9999996423721313 1.0
      }
      <Vertex> 7 {
        0.9999993443489075 -1.0000005960464478 1.0
      }
      <Vertex> 8 {
        1.0 0.9999999403953552 -1.0
      }
      <Vertex> 9 {
        1.0000004768371582 0.999999463558197 1.0
      }
      <Vertex> 10 {
        0.9999993443489075 -1.0000005960464478 1.0
      }
      <Vertex> 11 {
        1.0 -1.0 -1.0
      }
      <Vertex> 12 {
        1.0 -1.0 -1.0
      }
      <Vertex> 13 {
        0.9999993443489075 -1.0000005960464478 1.0
      }
      <Vertex> 14 {
        -1.0000003576278687 -0.9999996423721313 1.0
      }
      <Vertex> 15 {
        -1.0000001192092896 -0.9999998211860657 -1.0
      }
      <Vertex> 16 {
        -1.0000001192092896 -0.9999998211860657 -1.0
      }
      <Vertex> 17 {
        -1.0000003576278687 -0.9999996423721313 1.0
      }
      <Vertex> 18 {
        -0.9999999403953552 1.0 1.0
      }
      <Vertex> 19 {
        -0.9999996423721313 1.0000003576278687 -1.0
      }
      <Vertex> 20 {
        1.0000004768371582 0.999999463558197 1.0
      }
      <Vertex> 21 {
        1.0 0.9999999403953552 -1.0
      }
      <Vertex> 22 {
        -0.9999996423721313 1.0000003576278687 -1.0
      }
      <Vertex> 23 {
        -0.9999999403953552 1.0 1.0
      }}
    
    
    <Polygon> {
      <MRef> { Material }
      <Normal> {0.000000 0.000000 -1.000000}
      <VertexRef> { 0 1 2 3 <Ref> { Cube }}
    }
    <Polygon> {
      <MRef> { Material }
      <Normal> {0.000000 0.000000 1.000000}
      <VertexRef> { 4 5 6 7 <Ref> { Cube }}
    }
    <Polygon> {
      <MRef> { Material }
      <Normal> {1.000000 -0.000000 0.000000}
      <VertexRef> { 8 9 10 11 <Ref> { Cube }}
    }
    <Polygon> {
      <MRef> { Material }
      <Normal> {-0.000000 -1.000000 -0.000000}
      <VertexRef> { 12 13 14 15 <Ref> { Cube }}
    }
    <Polygon> {
      <MRef> { Material }
      <Normal> {-1.000000 0.000000 -0.000000}
      <VertexRef> { 16 17 18 19 <Ref> { Cube }}
    }
    <Polygon> {
      <MRef> { Material }
      <Normal> {0.000000 1.000000 0.000000}
      <VertexRef> { 20 21 22 23 <Ref> { Cube }}
    }
  }

The output of the first program looks consistent with the diagrams on panda3d.org/manual/index.php/Cube_Maps
Also, the error can be reproduced with the images of panda3d.org/manual/index.php/Sample_Cube_Map
The error is that the images seem horribly switched around. The top one is at the bottom and vice versa, and the images on the sides have obvious seams between them. If I swap the images 0 and 1, and 2 and 3, the seams disappear, except that now of course everything looks upside down (which is probably to be expected).