title: Procedural generation of stars with skybox
body: <p>I am attempting to procedurally generate a star-filled background in OpenGL.</p>
  
  <p>The approach I am taking is to create a skybox with a cubemap texture. Each side of the cubemap texture essentially consists of a 2048x2048 black image with randomly selected texels set to White. Here is the result:</p>
  
  <p><a href="https://i.stack.imgur.com/TuStI.png" rel="noreferrer"><img src="https://i.stack.imgur.com/TuStI.png" alt="Procedurally generated stars."></a> I'm not sure how obvious it is from the image, but when moving around a very distinct box shape can be made out as stars close to the edge of the box appear smaller and closer together. How can I prevent this? Do I need to abandon the skybox approach and use something like a skysphere instead?</p>
  
  <p>EDIT: here is how I am mapping the cubemap onto the sky.</p>
  
  <pre><code>// Create and bind texture.
  glGenTextures(1, &amp;texture_);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_CUBE_MAP, texture_);
  
  for (unsigned int i = 0; i &lt; 6; ++i) {
      std::vector&lt;std::uint8_t&gt; image = generateTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
      glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT,
                   0, GL_RGB, GL_UNSIGNED_BYTE, image.data());
  }
  
  // Set texture parameters.
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  </code></pre>
  
  <p>Here is the definition of the <code>generateTexture</code> function:</p>
  
  <pre><code>std::vector&lt;std::uint8_t&gt; Stars::generateTexture(GLsizei width, GLsizei height) {
      std::vector&lt;std::uint8_t&gt; image(static_cast&lt;std::size_t&gt;(3 * width * height));
  
      add_stars(image, NUM_STARS);
  
      return image;
  }
  
  void Stars::add_stars(std::vector&lt;std::uint8_t&gt;&amp; image, unsigned int nStars) {
      std::default_random_engine eng;
      std::uniform_int_distribution&lt;std::size_t&gt; dist(0, image.size() / 3 - 1);
  
      while (nStars--) {
          std::size_t index = 3 * dist(eng);
  
          image[index++] = 255;
          image[index++] = 255;
          image[index++] = 255;
      }
  }
  </code></pre>
  
  <p>EDIT2: here is the draw function used to render the sky.</p>
  
  <pre><code>void Stars::draw(const Camera&amp; camera) const {
      // Skybox will be rendered last. In order to ensure that the stars are rendered at the back of
      // the scene, the depth buffer is filled with values of 1.0 for the skybox -- this is done in
      // the vertex shader. We need to make sure that the skybox passes the depth te3t with values
      // less that or equal to the depth buffer.
      glDepthFunc(GL_LEQUAL);
  
      program_.enable();
  
      // Calculate view-projection matrix and set the corresponding uniform. The view matrix must be
      // stripped of translation components so that the skybox follows the camera.
      glm::mat4 view       = glm::mat4(glm::mat3(camera.viewMatrix()));
      glm::mat4 projection = camera.projectionMatrix();
  
      glm::mat4 VP = projection * view;
      glUniformMatrix4fv(program_.uniformLocation("VP"), 1, GL_FALSE, glm::value_ptr(VP));
  
      // Bind buffer objects and texture to current context and draw.
      glBindVertexArray(vao_);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
      glBindTexture(GL_TEXTURE_CUBE_MAP, texture_);
  
      glDrawElements(GL_TRIANGLES, static_cast&lt;GLsizei&gt;(INDICES.size()), GL_UNSIGNED_INT,
                     reinterpret_cast&lt;GLvoid *&gt;(0));
  
      glBindVertexArray(0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
      glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
      program_.disable();
  
      glDepthFunc(GL_LESS);
  }
  </code></pre>