0
\$\begingroup\$

I created a cubemap for skybox, but there were problems with displaying UV for it. when I appear in the world, everything looks fine as it should, BUT when I approach one of the sides of the cube, its UV begins to shrink down.

// Matrix for skybox( SkyMatrix in hlsl )
DirectX::XMMATRIX m;
m = DirectX::XMMatrixTranslation( -g_playerOrigin.x, -g_playerOrigin.y, -g_playerOrigin.z );

Vertex shader hlsl:

SkyPixel_t main(SkyVertex_t vs)
{
    SkyPixel_t ps;
    ps.position = mul(MVP, vs.position);
    ps.TexCoord = mul(SkyMatrix, vs.position).xyz;
    return ps;
}

Pixel shader hlsl

float4 main(SkyPixel_t ps) : SV_TARGET
{
    float4 finalColor = SkyTexture.Sample(SkySampler, ps.TexCoord);
    return finalColor;
}

Strange UV behavior when I'm up close to the skybox plane

You can see in the screenshot that the right side of the cliff is going down. And if I start walking backwards, everything goes back to normal.

Who knows what my mistake is?

EDIT*

// Initialize

void InitSkyBox( )
{
    // Make cubemap texture from 6 textures
    m_pTexture = MakeSkyBox( "skyBox" );

    // Sampler state
    skyState = CreateSamplerState( D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, 0, 0, 1 );
}

// Render

void RenderSky( )
{
    if( sky_surfaces )
    {
        // Set sky shader
        auto shaders = g_pShaderSystem->GetShader( "BaseSkyShader" );
        if( !shaders )
            return;

        g_pRender->GetDeviceContext( )->VSSetShader( shaders->pVertexShader, 0, 0 );
        g_pRender->GetDeviceContext( )->PSSetShader( shaders->pPixelShader, 0, 0 );
        g_pRender->GetDeviceContext( )->IASetInputLayout( shaders->pInputLayout );
        g_pRender->GetDeviceContext( )->PSSetShaderResources( 0, 1, &m_pTexture );
        g_pRender->GetDeviceContext( )->PSSetSamplers( 0, 1, &skyState );

        // update constant buffer
        DirectX::XMMATRIX m;
        
        // Set translation for SkyMatrix ( this translation apply on UV )
        m = DirectX::XMMatrixTranslation( -g_playerOrigin[ 0 ], -g_playerOrigin[ 1 ], -g_playerOrigin[ 2 ] );
     
        SkyConstantBuffer cb;
        cb.sky = m;
        g_pRender->GetDeviceContext( )->UpdateSubresource( m_pContantBuffer, 0, nullptr, &cb, 0, 0 );

        // Insert in slot 1 because in slot 0 MVP matrix
        g_pRender->GetDeviceContext( )->VSSetConstantBuffers( 1, 1, &m_pContantBuffer );

        RenderSky( sky_surfaces );
    }
\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

You should never be able to approach the edge of a skybox, because you always render the skybox as though it's centered at the camera / infinitely far away.

The easiest way to do that, if your skybox model is a full cube centered at the origin, is to zero-out the vertex position's w component when multiplying by the view matrix (and model matrix, if necessary). This blocks any translation due to object positioning or camera movement from taking effect, so the object always gets rendered as though it's centered on the camera (but rotation can still take effect).

SkyPixel_t main(SkyVertex_t vs)
{
    SkyPixel_t ps;    
    float4 viewspace = mul(MV, float4(vs.position.xyz, 0) );
    viewspace.w = 1;
    ps.position = mul(Projection, viewspace);
    ps.TexCoord = vs.position.xyz;
    return ps;
}

It's been a while since I tinkered with DirectX projection matrices directly, but I think they might need the w=1, which is why I've done the transformation in two steps above - stripping out the w for the model and view matrices and putting it back for the final operation. I'm not 100% sure that's required though - test and confirm!

Note that once you've done this, you don't need your math modifying the UV coordinates based on view position. You can let your UV coordinates just take the object space positions unchanged and save yourself a uniform and a matrix multiply.

You can also adjust the z position here to ensure it's always drawn flat along your far plane, and never clips out of view or occludes nearer geometry. If I recall correctly, the way to do that is to set ps.position.z = ps.position.w, so that after the perspective divide, this comes out as 1 = "at far plane", unless you're using a reversed depth buffer.

\$\endgroup\$
3
  • \$\begingroup\$ Hmm. The UV coordinates still keep stretching with each step. My idea is to change the UV coordinates (but they change strangely) with each character step, without moving the cube itself, since it is a static geometry. The code suggested above works, but the cube itself rotates when rotated and moves with the character \$\endgroup\$
    – Roolld
    Aug 12, 2023 at 13:56
  • \$\begingroup\$ You normally should not need to modify the UV coordinates. To help you debug this, we'll need to see what modifications you're making.Try editing your question to walk us through the steps to build a Minimal Complete Verifiable Example. \$\endgroup\$
    – DMGregory
    Aug 12, 2023 at 14:01
  • \$\begingroup\$ I have added all the code related to the skybox \$\endgroup\$
    – Roolld
    Aug 12, 2023 at 14:28
0
\$\begingroup\$

I have found a solution to my question. My camera has 'viewheight' variable which is 32 in the normal state. So, if you add this 'viewheight' to the Z component when creating the matrix, has such artifacts will disappear. By the way, when the player sit down the 'viewheight' becomes 16, and this also works.

Most likely this is hack and I'm still studying this issue in more detail

g_playerOrigin.z += g_movement.viewHeight;
m = DirectX::XMMatrixTranslation( -g_playerOrigin[ 0 ], -g_playerOrigin[ 1 ], -g_playerOrigin[ 2 ] );
...
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .