Is it possible to make a cube map texture (GL_TEXTURE_CUBE_MAP_POSITIVE_X...) repeat on a given face with OpenGL?
I have a simple unit cube with 24 vertexes centered around the origin (xyz between (-0.5, -0.5, -0.5) and (0.5, 0.5, 0.5)). Among its attributes, initially I set the uvw coords to the xyz position in the fragment shader as was done in the cubemap learnopengl.com tutorial. I obviously tried also to have separate uvw coordinates set to values equal to the scale, but the texture wasnt't repeating on any cube face as can be seen from the one displayed below (I painted the uvw coordinates in the fragment shader) :
height (y-coord of top pixels) = 3.5 in the image above, so by setting v = 3.5 for the vertex at the top, I'd expect the gradient to repeat vertically (which is not the case).
If it's not possible, the only way left for me to fix it is to assign a 2D Texture with custom uv coordinates on each vertex, right?
No, it's not possible to have wrapping with GL_REPEAT
for cubemaps. You should probably look to the alternatives people have suggested in the comments.
The reason for this, is that the coordinates that you pass to the cubemap sampler are interpreted as a direction. The length of this direction is ignored. You can think of it as if the vec3 used for sampling gets normalized — therefore, wrapping won't ever happen.
If, for any reason, you need to use a cubemap, you could make a modification to the sample direction in the shader.
vec3 tweakSampleDirForReapeat(vec3 dir, float repeatScale)
{
for(int i = 0; i < 3; i++) {
float d = abs(dir[i]);
if(abs(d) >= 0.5) // skip dominant direction (assuming a coordinate in a unit cube centered at the origin)
continue;
d += 0.5; // transform from [-0.5, +0.5] range to [0, 1]
d *= repeatScale; // transform from [0, 1] range to [0, repeatScale]
d = fract(d); // wrap [0, repeatScale] to multiple [0, 1] ranges
d -= 0.5; // transform from [0, 1] range to [-0.5, +0.5]
dir[i] = d;
}
return dir;
}
Disclaimer: this code should work but I haven't actually tried it.
This code could be adapted to support different repearScales per face.
EDIT: I will try to explain what this code does.
Imagine that we have a point that lays in the +X face of the cube.
We are trying to modify the location of this blue dot. We don't know yet where to place this point exactly. But this point will be in the same face.
In this case, the X value is equal to +0.5. The other coordinates (Y and Z) will have values smaller than 0.5 in absolute value.
That's what we are checking in this if:
if(abs(d) >= 0.5) // skip dominant direction
continue;
So basically, if X is -0.5 or +0.5, we don't want to change X, in order to keep it on the same face.
We will only modify Y and Z.
Now lets see the cube from a different perspective. Now we see the +X face facing towards us.
With this perspective we can clearly see that Y and Z are both < 0.5 (in absolute value), as the point is inside the box.
Now let's bring in a texture.
By default we would get whole the texture splatted onto the face.
But we would like something like this.
That's what this transformation is trying to do:
d += 0.5; // transform from [-0.5, +0.5] range to [0, 1]
d *= repeatScale; // transform from [0, 1] range to [0, repeatScale]
d = fract(d); // wrap [0, repeatScale] to multiple [0, 1] ranges
d -= 0.5; // transform from [0, 1] range to [-0.5, +0.5]
I recommend you go through the algorithm with a few examples, using paper and pencil. I'm sure you will end up understanding it, it's just a matter of putting in some time. Good luck!
Quiz question: what would be "repeatScale" for the previous image?