简体   繁体   English

D3D11 中的 Lockedrect

[英]Lockedrect in D3D11

I am trying to implement a pixel perfect collision detection algorithm from an online tutorial, but it is written using d3d9.我正在尝试从在线教程中实现像素完美碰撞检测算法,但它是使用 d3d9 编写的。 I am writing my game in d3d11, so I would like to know the best way to convert it.我正在用 d3d11 编写我的游戏,所以我想知道转换它的最佳方法。 The original code, uses locked rects, whic,h after researching, I found were not in D3D11.原始代码,使用锁定的矩形,研究后,我发现不在 D3D11 中。 By the way, I am using DirectX TK, so I have to convert form the ShaderResourceView to the texture.顺便说一下,我使用的是 DirectX TK,所以我必须将 ShaderResourceView 转换为纹理。 Here is the original code:这是原始代码:

int Bird::PixelPerfectCollision(Vector2* birdPoints, Vector2* pipePoints, Renderer& renderer)
{
    // Creation of the bounding rectangles from the SPRITE values 
    // Remember that coordinates start in the upper left corner of the screen 
    //bird
    RECT rect1; 
    rect1.left = (long)birdPoints[4].x;
    rect1.top = (long)birdPoints[0].y;
    rect1.right = (long)birdPoints[2].x;
    rect1.bottom = (long)birdPoints[3].y;
    //pipe
    RECT rect2; 
    rect2.left = (long)pipePoints[0].x;
    rect2.top = (long)pipePoints[0].y;
    rect2.right = (long)pipePoints[1].x;
    rect2.bottom = (long)pipePoints[2].y;
    // Intersection of the bounding rectangles 
    // Up to here the code is just bounding box collision detection 
    RECT dest;

    if (IntersectRect(&dest, &rect1, &rect2))
    {
        ComPtr<ID3D11ShaderResourceView> birdTexSRV = renderer.GetBirdTexture();
        ComPtr<ID3D11ShaderResourceView> pipeTexSRV = renderer.GetPipeTexture();

        // Loking of the textures 
        // In this case the SPRITE object holds the texture to draw 
        // We will access it and invoke the LockRect method of LPDIRECT3DTEXTURE9 
        // The pixels will be saved in each D3DLOCKED_RECT object 
        Microsoft::WRL::ComPtr<ID3D11Resource> resource;
        birdTexSRV->GetResource(resource.GetAddressOf());

        ComPtr<IDirect3DTexture9> birdTex;
        DX::ThrowIfFailed(resource.As(&birdTex));

        D3DLOCKED_RECT rectS1;
        HRESULT hResult = birdTex->LockRect(0, &rectS1, NULL, NULL);

        if (FAILED(hResult))
        {
            MessageBox(0, L"Failed", L"Info", 0);
            return 0;
        }
        Microsoft::WRL::ComPtr<ID3D11Resource> resource;
        pipeTexSRV->GetResource(resource.GetAddressOf());

        ComPtr<IDirect3DTexture9> pipeTex;
        DX::ThrowIfFailed(resource.As(&pipeTex));

        D3DLOCKED_RECT rectS2;
        hResult = pipeTex -> LockRect(0, &rectS2, NULL, NULL);

        if (FAILED(hResult))
        {
            MessageBox(0, L"Failed", L"Info", 0);
            return 0;
        }
        // Get the pointer to the color values 
        // From now on, we will read that pointer as an array
        D3DCOLOR* pixelsS1 = (D3DCOLOR*)rectS1.pBits;
        D3DCOLOR* pixelsS2 = (D3DCOLOR*)rectS2.pBits;
        // We will check the area of the intersected rect (dest) 
        // In this rectangle, we have to check that in the same spot: 
        // A pixel from each texture collide 
        for (int rx = dest.left; rx < dest.right; rx++)
        {
            for (int ry = dest.top; ry < dest.bottom; ry++)
            {
                // Translation from the "dest" rect to sprite1 coordinates 
                int s1x = rx - screenPos.x;
                int s1y = ry - screenPos.y;
                // Translation from the "dest" rect to sprite2 coordinates
                int s2x = rx - pipePoints[0].x; 
                int s2y = ry - pipePoints[0].y;
                // Check the alpha value of each texture pixel 
                // The alpha value is the leftmost byte
                BYTE a = (pixelsS1[s1y * 128 + s1x] & 0xFF000000) >> 24;
                BYTE b = (pixelsS2[s2y * 480 + s2x] & 0xFF000000) >> 24;
                // If both pixels are opaque, we found a collision 
                // We have to unlock the textures and return 
                if (a == 255 && b == 255)
                {
                    birdTex->UnlockRect(0); pipeTex->UnlockRect(0);
                    return 1;
                }
            }
        }
        // If we reached here, it means that we did not find a collision
        birdTex->UnlockRect(0);
        pipeTex->UnlockRect(0);
        return 0;

        return true;
    }
    return 0;
} 

If you want to do the collision on the CPU, your best bet is to create the textures twice.如果您想在 CPU 上进行碰撞,最好的办法是创建两次纹理。 The first time as normal, and another time as a STAGING resource.第一次正常,另一次作为 STAGING 资源。 Use the Ex version of the loader and provide it D3D11_USAGE_STAGING .使用加载程序的Ex版本并提供D3D11_USAGE_STAGING

ComPtr<ID3D11Resource> birdTexCPU;

...

hr = CreateWICTextureFromFileEx(device, "birdtex.png", 0, 
   D3D11_USAGE_STAGING, 0, D3D11_CPU_ACCESS_READ, 0,
   WIC_LOADER_DEFAULT,
   birdTexCPU.ReleaseAndGetAddressOf(), nullptr);

You can of course just create the texture from disk as a STAGING, then create a DEFAULT copy from that using CopyTexture if you want to minimize disk bandwidth.您当然可以只从磁盘创建纹理作为 STAGING,然后如果您想最小化磁盘带宽,则使用CopyTexture从该纹理创建一个默认副本。

At that point, you can access the actual texture data in CPU memory via Map .此时,您可以通过Map访问 CPU memory 中的实际纹理数据。 DirectX Tool Kit has a helper class for it to make sure it always calls Unmap . DirectX Tool Kit有一个助手 class 以确保它始终调用Unmap

#include "DirectXHelpers.h"

...

{
    DirectX::MapGuard texdata(context, birdTexCPU.Get(), 0, D3D11_MAP_READ, 0);

    // You have a pointer now from texdata.get();

}

You should catch the texture data on the CPU in some standard memory instead of a Direct3D 11 resource at this point as it's easier to use, but you could leave it in STAGING memory if you wanted.此时您应该在某些标准 memory 而不是 Direct3D 11 资源中捕获 CPU 上的纹理数据,因为它更易于使用,但如果需要,您可以将其保留在 STAGING memory 中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM