bkaradzic / bgfx

Cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.
https://bkaradzic.github.io/bgfx/overview.html
BSD 2-Clause "Simplified" License
14.93k stars 1.94k forks source link

Cubemap faces all messed up when blitting? #1075

Open volcoma opened 7 years ago

volcoma commented 7 years ago

Ok so I have an issue with cubemap faces of a render target in opengl only. I generate reflection probes for my scene and for every reflection probe I render 6 faces to a cubemap and I am setting the view matrix for each face like so:

math::vec3 X(1, 0, 0);
math::vec3 Y(0, 1, 0);
math::vec3 Z(0, 0, 1);
math::vec3 Zero(0, 0, 0);
math::transform_t t;
switch (face)
{
    case 0:
        t.look_at(Zero, -X, +Y); break;   // NEGATIVE X
        case 1:
        t.look_at(Zero, +X, +Y); break;  // POSITIVE X
        case 2:
        t.look_at(Zero, -Y, +Z); break;   // NEGATIVE Y
    case 3:
        t.look_at(Zero, +Y, -Z); break;   // POSITIVE Y
    case 4:
        t.look_at(Zero, +Z, +Y); break;  // POSITIVE Z
    case 5:
        t.look_at(Zero, -Z, +Y); break;  // NEGATIVE Z
}

After each side is rendered I blit it into a cubemap to the corresponding face of the cubemap. Fist of all whats with the weird order of the faces? Shouldn't it be +X ,-X, +Y, -Y, +Z, -Z ?Then when I sample it I get the following RIGHT result with DX11:

dx11

and this result with opengl

opengl

In the shader I sample with a reflection vector created like this drawing a clip quad vertex_shader:

vec3 v_weye_dir = mul( u_invViewProj, vec4( gl_Position.x, gl_Position.y, 1.0f, 1.0f ) ).xyz;

fragment_shader

vec3 N = data.world_normal;
vec3 V = -normalize(v_weye_dir);
vec3 R = reflect(-V, N);

Event if I flip the .y of the reflection vector I get this: opengl_flipped

This only happens with opengl. If in opengl I create the view matrix like so:

case 1:
    t.look_at(Zero, +X, +Y); break;
case 0:
    t.look_at(Zero, -X, +Y); break;
case 2:
    t.look_at(Zero, +Y, -Z); break;
case 3:
    t.look_at(Zero, -Y, +Z); break;
case 4:
    t.look_at(Zero, +Z, +Y); break;
case 5:
    t.look_at(Zero, -Z, +Y); break;

and flip the y of the reflection vector when sampling from it i get the right result in opengl too... Something is really fishy here and i cant figure it out. Maybe the blit function is blitting to the wrong face or something or maybe I am doing something wrong?

bkaradzic commented 7 years ago

Fist of all whats with the weird order of the faces? Shouldn't it be +X ,-X, +Y, -Y, +Z, -Z ?

It already is: https://github.com/bkaradzic/bgfx/blob/master/include/bgfx/defines.h#L437

#define BGFX_CUBE_MAP_POSITIVE_X UINT8_C(0x00) //!< Cubemap +x.
#define BGFX_CUBE_MAP_NEGATIVE_X UINT8_C(0x01) //!< Cubemap -x.
#define BGFX_CUBE_MAP_POSITIVE_Y UINT8_C(0x02) //!< Cubemap +y.
#define BGFX_CUBE_MAP_NEGATIVE_Y UINT8_C(0x03) //!< Cubemap -y.
#define BGFX_CUBE_MAP_POSITIVE_Z UINT8_C(0x04) //!< Cubemap +z.
#define BGFX_CUBE_MAP_NEGATIVE_Z UINT8_C(0x05) //!< Cubemap -z.

See: https://bkaradzic.github.io/bgfx/bgfx.html#_CPPv2N4bgfx17updateTextureCubeE13TextureHandle8uint16_t7uint8_t7uint8_t8uint16_t8uint16_t8uint16_t8uint16_tPK6Memory8uint16_t

volcoma commented 7 years ago

Ok reading the docs now I setup my view matrix like so:

switch (face)
        {
        case 0:
            t.set_rotation(-Z, +Y, +X); break;
        case 1:
            t.set_rotation(+Z, +Y, -X); break;
        case 2:
            t.set_rotation(+X, -Z, +Y); break;
        case 3:
            t.set_rotation(+X, +Z, -Y); break;
        case 4:
            t.set_rotation(+X, +Y, +Z); break;
        case 5:
            t.set_rotation(-X, +Y, -Z); break;
        }

which gives me the same result which only works properly on directx, but on opengl the faces are messed up exactly the same as I mentioned above. Considering I use Left handed coordinate system for both.

volcoma commented 7 years ago

Is it possible that the blit function creates the issue maybe copying to the wrong region or something? I render each face to a standard render target then blit the render target to the cubemap face like so:

bgfx::blit(pass.id, bgfx::getTexture(cubemap_fbo->handle), 0, 0, 0, face, bgfx::getTexture(output->handle));
hugoam commented 5 years ago

I fought for a few hours with this issue, but the solution is simply to render everything flipped on the Y axis of the output when originBottomLeft is true. (So basically all your shaders need to have a switch to flip the rendering).

IIUC, this is due to bgfx abstracting the sampling origin differences when uploading textures, but not when rendering to a buffer, so your cubemap sides end up vertically flipped in respect to how sampling behaves.