DirectX 11精灵2D相机

3

长时间的读者,第一次发帖。我有一个问题已经毁掉了我的脑细胞,花了几个小时也没有任何进展。所以我想把它放在这里,得到新鲜的眼睛...

基本上,我正在尝试使用C++和DirectX 11创建一个2D游戏。我之前用过C#和XNA,并在DirectX中制作了一些3D物体,但没有做过这么大的项目。

我正在尝试使用基本相机和基本精灵批处理程序在屏幕中央绘制一个精灵,但是什么都没有显示出来,我无法找出原因。我会发布一些代码来给大家一个想法。

这是我在相机类中设置所有矩阵的地方,它们保持不变(现在,稍后会更改为移动等):

XMStoreFloat4x4(&m_world, XMMatrixIdentity());
XMStoreFloat4x4(&m_proj, XMMatrixOrthographicOffCenterLH(0.0f, width, height, 0.0f, 0.0f, 1.0f));

m_position = XMFLOAT3(width / 2, height / 2, 0);
m_look = XMFLOAT3(0, 0, 1);
m_up = XMFLOAT3(0, 1, 0);

XMVECTOR p = XMLoadFloat3(&m_position);
XMVECTOR l = XMLoadFloat3(&m_look);
XMVECTOR u = XMLoadFloat3(&m_up);

XMStoreFloat4x4(&m_view, XMMatrixLookToLH(p, l, u));

然后将此输入精灵批处理的开始方法,该方法将信息传递给着色器:

D3D11_MAPPED_SUBRESOURCE data;
ZeroMemory(&data, sizeof(data));
m_deviceContext->Map(m_cBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &data);
ConstantBuffer* cb = (ConstantBuffer*)data.pData;

XMMATRIX w = XMLoadFloat4x4(&world);
XMMATRIX v = XMLoadFloat4x4(&view);
XMMATRIX p = XMLoadFloat4x4(&proj);

w = XMMatrixTranspose(w);
v = XMMatrixTranspose(v);
p = XMMatrixTranspose(p);

XMStoreFloat4x4(&world, w);
XMStoreFloat4x4(&view, v);
XMStoreFloat4x4(&proj, p);

cb->World = world;
cb->View = view;
cb->Proj = proj;

m_deviceContext->Unmap(m_cBuffer, 0);

最后是着色器本身:

cbuffer ConstantBuffer : register(b0)
{
    float4x4 World;
    float4x4 View;
    float4x4 Proj;
};

SamplerState sam : register(s0);
Texture2D tex : register(t0);

struct VertexIn
{
    float3 Position : POSITION;
    float2 Texture : TEXCOORD;
    float4 Color : COLOR;
};

struct PixelIn
{
    float4 Position : SV_POSITION;
    float2 Texture : TEXCOORD;
    float4 Color : COLOR;
};

PixelIn VS(VertexIn vin)
{
    float4 position = float4(vin.Position, 1.0f);
    position = mul(position, World);
    position = mul(position, View);
    position = mul(position, Proj);

    PixelIn vout;
    vout.Position = position;
    vout.Texture = vin.Texture;
    vout.Color = vin.Color;

    return vout;
}

float4 PS(PixelIn pin) : SV_Target
{
    float4 textureColor = tex.Sample(sam, pin.Texture);

    return pin.Color * textureColor;   
}

如您所见,这很简单。但是屏幕上没有任何东西被绘制出来。我已经尝试不使用矩阵,省略了世界矩阵,使用透视投影矩阵,使用look at而不是look to矩阵,使用(0, 0, 0)作为中心通过XMMatrixOrthographicLH并将精灵位置转换为屏幕空间。
我甚至大大简化了精灵批处理,只限制每次绘制一个精灵!
我使用的是不可变索引缓冲区(0、1、2、0、2、3)和动态顶点缓冲区,其更新如下:
D3D11_MAPPED_SUBRESOURCE data;
ZeroMemory(&data, sizeof(data));
m_deviceContext->Map(m_vBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &data);
Vertex* vertex = (Vertex*)data.pData;

for(UINT i = 0; i < sprite->Vertices.size(); ++i)
{
    vertex[i] = sprite->Vertices[i];
}

m_deviceContext->Unmap(m_vBuffer, 0);

m_deviceContext->DrawIndexed(6, 0, 0);

我曾用类似的方法渲染3D模型。事实上,这更难一些,因为我有一个动态索引缓冲和更多的常量缓冲区数据,而且着色器更加复杂。
我想这可能是由于数据在某个地方丢失的问题,但似乎所有的数据都正确地传递了,直到DrawIndexed方法调用为止。我已经仔细检查了缓冲区的创建和状态,并且当前它处于CULL_NONE状态,只是为了确保它没有被剔除。
为了澄清,我将发布缓冲区创建和精灵创建的内容:
HRESULT result = S_OK;

device->GetImmediateContext(&m_deviceContext);

D3D11_BUFFER_DESC cbd;
ZeroMemory(&cbd, sizeof(cbd));
cbd.ByteWidth = sizeof(ConstantBuffer);
cbd.Usage = D3D11_USAGE_DYNAMIC;
cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbd.MiscFlags = 0;
cbd.StructureByteStride = 0;

result = device->CreateBuffer(&cbd, 0, &m_cBuffer);

if (FAILED(result))
{
    return 0;
}

vector<short> indices;
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
indices.push_back(0);
indices.push_back(2);
indices.push_back(3);

D3D11_SUBRESOURCE_DATA indexData;
ZeroMemory(&indexData, sizeof(indexData));
indexData.pSysMem = &indices;

D3D11_BUFFER_DESC ibd;
ZeroMemory(&ibd, sizeof(ibd));
ibd.ByteWidth = 6 * sizeof(short);
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
ibd.StructureByteStride = 0;

result = device->CreateBuffer(&ibd, &indexData, &m_iBuffer);

if (FAILED(result))
{
    return 0;
}

D3D11_BUFFER_DESC vbd;
ZeroMemory(&vbd, sizeof(vbd));
vbd.ByteWidth = 4 * sizeof(Vertex);
vbd.Usage = D3D11_USAGE_DYNAMIC;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbd.MiscFlags = 0;
vbd.StructureByteStride = 0;

result = device->CreateBuffer(&vbd, 0, &m_vBuffer);

if (FAILED(result))
{
    return 0;
}

return 1;

精灵:

ID3D11Resource* resource;
ZeroMemory(&resource, sizeof(resource));
texture->GetResource(&resource);

ID3D11Texture2D* tex = (ID3D11Texture2D*)resource;

D3D11_TEXTURE2D_DESC t;
ZeroMemory(&t, sizeof(t));
tex->GetDesc(&t);

Vertex v[4];
ZeroMemory(&v, sizeof(v));

v[0].Position = XMFLOAT3((float)destinationRectangle.value.left, (float)destinationRectangle.value.top, z);
v[1].Position = XMFLOAT3((float)destinationRectangle.value.right, (float)destinationRectangle.value.top, z);
v[2].Position = XMFLOAT3((float)destinationRectangle.value.right, (float)destinationRectangle.value.bottom, z);
v[3].Position = XMFLOAT3((float)destinationRectangle.value.left, (float)destinationRectangle.value.bottom, z);

v[0].Texture = XMFLOAT2((float)(sourceRectangle.value.left / t.Width), (float)(sourceRectangle.value.top / t.Height));
v[1].Texture = XMFLOAT2((float)(sourceRectangle.value.right / t.Width), (float)(sourceRectangle.value.top / t.Height));
v[2].Texture = XMFLOAT2((float)(sourceRectangle.value.right / t.Width), (float)(sourceRectangle.value.bottom / t.Height));
v[3].Texture = XMFLOAT2((float)(sourceRectangle.value.left / t.Width), (float)(sourceRectangle.value.bottom / t.Height));

v[0].Color = color;
v[1].Color = color;
v[2].Color = color;
v[3].Color = color;

Sprite* sprite = new Sprite();
sprite->Vertices.push_back(v[0]);
sprite->Vertices.push_back(v[1]);
sprite->Vertices.push_back(v[2]);
sprite->Vertices.push_back(v[3]);
sprite->Texture = texture;

m_sprites.push_back(sprite);

我是不是疯了?我是不是太傻了?还是说有更简单的方法来做这件事?谢谢。感激任何帮助!

还想指出一下,我正在绘制的精灵在800x600的屏幕上有一个矩形(左=300,右=500,顶部=350,底部=450),颜色全为白色。纹理已正确加载,甚至尝试仅在着色器中输出颜色以确保,但没有成功。

哦,我尝试绘制的精灵的Z值设置为0.5f,尽管我尝试过将其设置为不同的值,但我期望这个值可以正常工作。

2个回答

3

我在另一个网站上找到了答案,感谢 MJP。问题出在这行代码上:

indexData.pSysMem = &indices;

应该把它改成这样:

正确的形式为:

indexData.pSysMem = &indices[0];

显然,我发送的是指向整个向量而不是第一个实例的指针,因此索引缓冲区不知道我在说什么!

就像我所说的,我刚刚从XNA编程开始学习DirectX编程。 ;)

我希望这能帮助其他处于类似位置的人。


0
你是否配置了深度模板以便使用2D呢? 同时尝试将摄像机位置设为负Z轴,因为你当前的设置是0。

你好。感谢您的回复。我已经尝试将相机位置设置为负Z值,并尝试使用LookAt矩阵创建,使其朝向中央精灵位置的方向。我已将DepthEnable设置为false,因为我已经意识到需要这样做。以下是我的DepthStencil描述: - Ashley Mills
D3D11_DEPTH_STENCIL_DESC dsDesc; ZeroMemory(&dsDesc, sizeof(dsDesc)); dsDesc.DepthEnable = false; dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; dsDesc.DepthFunc = D3D11_COMPARISON_LESS; dsDesc.StencilEnable = false; - Ashley Mills
dsDesc.StencilReadMask = 0xFF; dsDesc.StencilWriteMask = 0xFF; dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 还要添加这个 - Sergiu Craitoiu
我只是为了节省空间而省略了那部分内容 :) 没有任何错误。它清除了渲染目标并以正确的颜色呈现。只是没有精灵。这真是个谜。我对一些事情进行了失败检查(设备创建、缓冲区创建、加载纹理),但还不是所有的事情都检查过。我已经在调试中逐步执行了我的代码,就我所知,所有的值都符合预期。我猜想这可能是一个矩阵问题,因为说实话,我的矩阵数学并不是很好(毕竟那些方便的辅助函数就是为了解决这个问题的) :) - Ashley Mills
我计划稍后实现它以节省计算量。但就我现在所做的事情而言,我只是试图得到一些显示!正如我所说,我对矩阵不太擅长,但我现在发现了问题 :) - Ashley Mills
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接