c++ - 如何将世界坐标转换为屏幕坐标

标签 c++ directx-11 coordinate-transformation

我正在创建一个将在 3d 世界中包含 2d 图片的游戏。

我最初并不关心我的图像被拉伸(stretch)成一个正方形,同时我了解了更多关于游戏机制的工作原理......但现在是时候让我的纹理以正确的比例和......大小显示。

只是一个旁注,我玩过正交左手投影,但我注意到你不能在那里做 3d ......(我想这是有道理的......但我可能是错的,我试过了,当我旋转了我的图像,它变得有弹性和怪异)。

我的游戏性质如下:

enter image description here

在图片中,它表示 -1.0 到 1.0...如果坐标是:我不会大惊小怪:

  • 左上角 = 0,0,0
  • 右下 = 1920, 1200, 0

但如果那是解决方案,那么无论如何......(p.s 游戏当前未设置,因此 -1.0 和 1.0 位于屏幕的左侧和右侧。事实上,我不确定我将如何进行使屏幕边缘边界(但这是另一天的问题)


问题:

我遇到的问题是我的播放器 (2d) 图像是 128 x 64 像素。在世界矩阵乘法(我认为就是这样)之后,我放入的顶点极大地缩放了我的纹理......这是有道理的,但它看起来很丑陋,我不想只是将一个巨大的缩放矩阵打到混合中,因为它将很难弄清楚如何使纹理与我的屏幕像素成 1:1(虽然也许你会告诉我这实际上是你如何做的,但你需要做一个聪明的公式来计算缩放比例应该是多少)。

但基本上,我希望顶点保持图像的 1:1 像素大小,未拉伸(stretch)...

所以我假设我需要在输出我的纹理和顶点之前将我的世界坐标转换为屏幕坐标???我不确定它是如何工作的...

无论如何,这是我的顶点..你可能会注意到我做了什么:

struct VERTEX
{
    float X, Y, Z;
    //float R, G, B, A;
    float NX, NY, NZ;
    float U, V;          // texture coordinates
};

const unsigned short SquareVertices::indices[ 6 ] = {
    0, 1, 2,    // side 1
    2, 1, 3
};

const VERTEX SquareVertices::vertices[ 4 ] = {
        //{ -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f,  0.0f, 0.0f },    // side 1
        //{ 1.0f, -1.0f, 0.0f,  0.0f, 0.0f, -1.0f,  1.0f, 0.0f },
        //{ -1.0f, 1.0f, 0.0f,  0.0f, 0.0f, -1.0f,  0.0f, 1.0f },
        //{ 1.0f, 1.0f, 0.0f,       0.0f, 0.0f, -1.0f,  1.0f, 1.0f }

    { -64.0f, -32.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f },    // side 1
    { 64.0f, -32.0f, 0.0f,  0.0f, 0.0f, -1.0f, 1.0f, 0.0f },
    { -64.0f, 32.0f, 0.0f,  0.0f, 0.0f, -1.0f, 0.0f, 1.0f },
    { 64.0f, 64.0f, 0.0f,   0.0f, 0.0f, -1.0f, 1.0f, 1.0f }
};

(128 像素/2 = 64 ),( 64/2 = 32 )因为中心是 0.0...但是我需要对投影、世界转换以及什么不能让世界显示在屏幕上做什么?

我目前的设置是这样的:

// called 1st
void Game::SetUpViewTransformations( )
{
    XMVECTOR vecCamPosition = XMVectorSet( 0.0f, 0.0f, -20.0f, 0 );
    XMVECTOR vecCamLookAt = XMVectorSet( 0, 0, 0, 0 );
    XMVECTOR vecCamUp = XMVectorSet( 0, 1, 0, 0 );
    matView = XMMatrixLookAtLH( vecCamPosition, vecCamLookAt, vecCamUp );
}

// called 2nd
void Game::SetUpMatProjection( )
{
    matProjection = XMMatrixPerspectiveFovLH(
        XMConvertToRadians( 45 ),                                      // the field of view
        windowWidth / windowHeight,  // aspect ratio
        1,                                                           // the near view-plane
        100 );                                                        // the far view-plan
}

下面是我的更新和渲染方法的偷偷摸摸:

// called 3rd
void Game::Update( )
{
    world->Update();
    worldRotation = XMMatrixRotationY( world->rotation );

    player->Update( );
    XMMATRIX matTranslate = XMMatrixTranslation( player->x, player->y, 0.0f );
    //XMMATRIX matTranslate = XMMatrixTranslation( 0.0f, 0.0f, 1.0f );
    matWorld[ 0 ] = matTranslate;
}

// called 4th
void Game::Render( )
{
    // set our new render target object as the active render target
    d3dDeviceContext->OMSetRenderTargets( 1, rendertarget.GetAddressOf( ), zbuffer.Get( ) );

    // clear the back buffer to a deep blue
    float color[ 4 ] = { 0.0f, 0.2f, 0.4f, 1.0f };
    d3dDeviceContext->ClearRenderTargetView( rendertarget.Get( ), color );
    d3dDeviceContext->ClearDepthStencilView( zbuffer.Get( ), D3D11_CLEAR_DEPTH, 1.0f, 0 ); // clear the depth buffer

        CBUFFER cBuffer;
        cBuffer.DiffuseVector = XMVectorSet( 0.0f, 0.0f, 1.0f, 0.0f );
        cBuffer.DiffuseColor = XMVectorSet( 0.5f, 0.5f, 0.5f, 1.0f );
        cBuffer.AmbientColor = XMVectorSet( 0.2f, 0.2f, 0.2f, 1.0f );
        //cBuffer.Final = worldRotation * matWorld[ 0 ] * matView * matProjection;
        cBuffer.Final = worldRotation * matWorld[ 0 ] * matView * matProjection;
        cBuffer.Rotation = XMMatrixRotationY( world->rotation );

        // calculate the view transformation
        SetUpViewTransformations();
        SetUpMatProjection( );

            //matFinal[ 0 ] = matWorld[0] * matView * matProjection;

            UINT stride = sizeof( VERTEX );
            UINT offset = 0;

                d3dDeviceContext->PSSetShaderResources( 0, 1, player->texture.GetAddressOf( ) ); // Set up texture
                d3dDeviceContext->IASetVertexBuffers( 0, 1, player->vertexbuffer.GetAddressOf( ), &stride, &offset ); // Set up vertex buffer
                d3dDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // How the vertices be drawn
                d3dDeviceContext->IASetIndexBuffer( player->indexbuffer.Get( ), DXGI_FORMAT_R16_UINT, 0 ); // Set up index buffer
                d3dDeviceContext->UpdateSubresource( constantbuffer.Get( ), 0, 0, &cBuffer, 0, 0 ); // set the new values for the constant buffer

                d3dDeviceContext->OMSetBlendState( blendstate.Get( ), 0, 0xffffffff ); // DONT FORGET IF YOU DISABLE THIS AND YOU WANT COLOUR, * BY Color.a!!!
                d3dDeviceContext->DrawIndexed( ARRAYSIZE( player->indices ), 0, 0 ); // draw

    swapchain->Present( 1, 0 );
}

澄清一下,如果我让我的顶点分别使用 2 和 1 来表示我的图像是 128 x 64..我得到一个正常大小的图像..但在 0,0 ,0 它不是 1:1 大小... wadduuuppp buddyyyy

    { -2.0f, -1.0f, 0.0f,   0.0f, 0.0f, -1.0f,  0.0f, 0.0f },    // side 1
    { 2.0f, -1.0f, 0.0f,    0.0f, 0.0f, -1.0f,  1.0f, 0.0f },
    { -2.0f, 1.0f, 0.0f,    0.0f, 0.0f, -1.0f,  0.0f, 1.0f },
    { 2.0f, 2.0f, 0.0f,     0.0f, 0.0f, -1.0f,  1.0f, 1.0f }

期望的结果 2 最大:

enter image description here

很酷的图片是不是 :D?

评论帮助:

enter image description here

最佳答案

我不熟悉 direct-x,但据我所知,你的图像的屏幕坐标是 x 和 y 上的 [-1...+1]。因此,两个轴上的总长度等于 2,您的图像被缩放了 2 倍。尝试在相机矩阵中考虑这个比例。

关于c++ - 如何将世界坐标转换为屏幕坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20985369/

相关文章:

VS2010 中使用 lambda 参数捕获的 C++ 嵌套 lambda 错误?

objective-c - 设备方向更改后无法翻译触摸坐标

maps - 将纬度/经度转换为地理引用 map 上的相对 X/Y 坐标

opengl - OpenGL 中 2D 鼠标单击导致 3D 坐标不正确?

c++ - 与慢消费者异步发送

c++ - 'list::list' 命名构造函数,而不是类型

c++ - 调试断言失败!表达式 : __acrt_first_block == header

c++ - DirectX11 更新动态实例缓冲区

c++ - DirectX 11 渲染到纹理

c++ - Microsoft 的 DirectX 11 教程在释放变量时崩溃