0
\$\begingroup\$

I want to render a sky: My camera is at the origin, and I want there to be a white background for all world coordinates with z < 0 (would normally be considered y > 0, but I have a different coordinate system via glLookAt()).

I thought I may be able to do this in the fragment shader by multiplying the inverse MVP matrix with the corresponding clip space (?) coordinate (I compute that matrix on the CPU each frame by calling Matrix.invertM()). To get my vertices into the fragment shader, I use a varying variable (I wasn't sure if I could access gl_Position in the fragment shader) and passed the position right through; not sure if my syntax is right (see below):

Vertex Shader:

attribute vec4 position;
varying vec4 vp;
void main() {
  gl_Position = position;
  vp = position;
}

Fragment Shader:

precision mediump float;
uniform mat4 inverseMatrix;
varying vec4 vp;
void main() {
  vec4 inversePosition = inverseMatrix * vp;
  if (inversePosition.z > 0.0) {
    gl_FragColor = vec4(0,0,0,1);
  } else {
    gl_FragColor = vec4(1,1,1,1);
  }
}

Question:

Does this approach seem sane? Should I use some other approach that doesn't involve multiplying each fragment coordinate with the inverse MVP matrix?

\$\endgroup\$
  • 1
    \$\begingroup\$ You could multiply your varying with the matrix in the vertex shader, the results will be the same as they'll be interpolated, that way you at least do the calculation per vertex instead of per fragment. Also you can use gl_FragCoord in the fragment shader to get the fragments position, it's a vec4 holding the interpolated data from gl_Position. \$\endgroup\$ – cozmic Jan 1 '16 at 9:09
  • 1
    \$\begingroup\$ Did you considered using a cubemap for the background and a plane for the soil ? \$\endgroup\$ – elenfoiro78 Jan 1 '16 at 9:46
  • \$\begingroup\$ I was considering a cubemap, but I have never used one before and wasn't sure if that would actually be simpler? It seems like drawing the top (as in above the horizon) half of the screen in one solid color should be simple to do without texturing? cozmic - hm, would that actually be correct? Perspective is not a linear operation in 3D, which is why I wanted to interpolate the clipspace points. But perhaps it works as long as I do perspective divide for the interpolated 4d values. \$\endgroup\$ – Tobias Jan 1 '16 at 10:12
  • \$\begingroup\$ PS. I implemented both of these suggestions. The vertex shader doing the inverse matrix multiplication works great. The cubemap doesn't work because the colors that are above and below the horizon on four sides of the cubemap get blended by OpenGL, even though I have set glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); Perhaps it's a bug in OpenGL? \$\endgroup\$ – Tobias Jan 1 '16 at 17:35
1
\$\begingroup\$

If you want things to be simple, another approach would be to set the clear color to the sky color at the beginning of your render pipeline. Then render a square with the soil color. It will be more efficient than the technique you are exploring.

Otherwise, I would recommend you to use a cubemap for the sky. Performance will still be good and you'll have the possibility to rotate the sky view along with the camera.

Hope it helps.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your suggestion. I can rotate the camera either way, because the rotation is part of the view projection matrix that I'm inverting. When I tried the cubemap, for some reason the colors above/below the horizon bled into one another, so it didn't work. See my comment above. \$\endgroup\$ – Tobias Jan 1 '16 at 17:38
  • 1
    \$\begingroup\$ If you don't need background terrain in the cube map, you can avoid these glitches by having it pure sky on all faces. \$\endgroup\$ – elenfoiro78 Jan 1 '16 at 18:47
  • \$\begingroup\$ elenforio, thanks for your suggestion. I want the top halves of each side to be sky (white) and the bottom half to be ground (black). I programmatically created a 2x2 bitmap with two white and two black pixels for those sides of the cubemap, but it's showing as a smooth-ish transition from black to white for some reason, rather than an abrupt transition like I wanted with my GL_NEAREST scaling. However I've now discovered that the smoothing only happens when I render via the Google Cardboard SDK; perhaps the Cardboard SDK is issuing GL commands to change the texture scaling mode that I set? \$\endgroup\$ – Tobias Jan 2 '16 at 11:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.