简体   繁体   中英

DX11 C++ Shader can't receive Instance Buffer content

i would like to draw Instances of an obj File. After i implemented the Instancing instead of drawing each Object by his own draw() function (which worked just fine), the Instances are not positioned correctly. Probably the data from the InstanceBuffer is not set in the shader correctly.

D3DMain.cpp - creating input layout

struct INSTANCE {
//D3DXMATRIX matTrans;
    D3DXVECTOR3 
};

/***/

// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
    //vertex buffer
    {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  12, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0,  24, D3D11_INPUT_PER_VERTEX_DATA, 0},

    //instance buffer
    {"INSTTRANS", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1},
    //{"INSTTRANS", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
    //{"INSTTRANS", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
    //{"INSTTRANS", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
};
if (FAILED(d3ddev->CreateInputLayout(ied, 4, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout))) throw(std::string("Input Layout Creation Error"));
d3ddevcon->IASetInputLayout(pLayout);

World.cpp - setting up instance buffer

    std::vector<INSTANCE> instanceBuffer;
    INSTANCE insertInstance;

    D3DXMATRIX scaleMat, transMat;
    D3DXMatrixScaling(&scaleMat, 50.0f, 50.0f, 50.0f);

    int i=0;
    for (std::list<SINSTANCES>::iterator it = sInstances.begin(); it != sInstances.end(); it++) {
        if ((*it).TypeID == typeId) {
            //do something
            D3DXMatrixTranslation(&transMat, (*it).pos.x, (*it).pos.y, (*it).pos.z);
            insertInstance.matTrans = (*it).pos;//scaleMat * transMat;
            instanceBuffer.push_back(insertInstance);
            i++;
        }
    }
    instanceCount[typeId] = i;


    //create new IB
    D3D11_BUFFER_DESC instanceBufferDesc;
    ZeroMemory(&instanceBufferDesc, sizeof(instanceBufferDesc));
    instanceBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    instanceBufferDesc.ByteWidth = sizeof(INSTANCE) * i;
    instanceBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    instanceBufferDesc.CPUAccessFlags = 0;
    instanceBufferDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA instanceData;
    ZeroMemory(&instanceData, sizeof(instanceData));
    instanceData.pSysMem = &instanceBuffer[0];

    if (FAILED(d3ddev->CreateBuffer(&instanceBufferDesc, &instanceData, &instanceBufferMap[typeId]))) throw(std::string("Failed to Update Instance Buffer"));

OpenDrawObj.cpp - drawing .obj file

UINT stride[2] = {sizeof(VERTEX), sizeof(INSTANCE)};
    UINT offset[2] = {0, 0};

    ID3D11Buffer* combinedBuffer[2] = {meshVertBuff, instanceBuffer};
    d3ddevcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    d3ddevcon->IASetVertexBuffers(0, 2, combinedBuffer, stride, offset);
    d3ddevcon->IASetIndexBuffer(meshIndexBuff, DXGI_FORMAT_R32_UINT, 0);

    std::map<std::wstring, OBJMATERIAL>::iterator fit;
    for (std::vector<DRAWLIST>::iterator it = drawList.begin(); it != drawList.end(); it++) {
        fit = objMaterials.find((*it).material);
        if (fit != objMaterials.end()) {
            if ((*fit).second.texture != NULL) {
                d3ddevcon->PSSetShaderResources(0, 1, &((*fit).second.texture));
            }
            d3ddevcon->DrawIndexedInstanced((*it).indexCount, instanceCount, (*it).startIndex, 0, 0);
        }
    }

the drawing function (above) is called here: I pass the instance buffer (map(int, ID3D11Buffer*) and the instance numbers)

(*it).second->draw(0.0f, 0.0f, 0.0f, 0, instanceBufferMap[typeId], instanceCount[typeId]);

shader.hlsl

struct VIn
{
float4 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
//row_major float4x4 instTrans : INSTTRANS;
float4 instTrans : INSTTRANS;
uint instanceID : SV_InstanceID;
};



VOut VShader(VIn input)
{
VOut output;

//first: transforming instance
//output.position = mul(input.instTrans, input.position);
output.position = input.position;
output.position.xyz *= 50.0; //scale
output.position.z += input.instTrans.z; //apply only z value

float4 transPos = mul(world, output.position); //transform position with world matrix

output.position = mul(view, transPos);  //project to screen

the "input.instTrans" in the last file is incorrect and contains ramdom data. Do you have any ideas?

So i found the bug, it was at an totally unexpected location... So here is the code snippet:

ID3D10Blob *VS, *VS2, *PS, *PS2; //<- i only used VS and PS before

//volume shader
if (FAILED(D3DX11CompileFromFile(L"resources/volume.hlsl", 0, 0, "VShader", "vs_5_0", D3D10_SHADER_PREFER_FLOW_CONTROL | D3D10_SHADER_SKIP_OPTIMIZATION, 0, 0, &VS, 0, 0))) throw(std::string("Volume Shader Error 1"));
if (FAILED(D3DX11CompileFromFile(L"resources/volume.hlsl", 0, 0, "PShader", "ps_5_0", D3D10_SHADER_PREFER_FLOW_CONTROL | D3D10_SHADER_SKIP_OPTIMIZATION, 0, 0, &PS, 0, 0))) throw(std::string("Volume Shader Error 2"));
// encapsulate both shaders into shader objects
if (FAILED(d3ddev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pvolumeVS))) throw(std::string("Volume Shader Error 1A"));
if (FAILED(d3ddev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pvolumePS))) throw(std::string("Volume Shader Error 2A"));

//sky shader
if (FAILED(D3DX11CompileFromFile(L"resources/sky.hlsl", 0, 0, "VShader", "vs_5_0", D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, 0, &VS2, 0, 0))) throw(std::string("Sky Shader Error 1"));
if (FAILED(D3DX11CompileFromFile(L"resources/sky.hlsl", 0, 0, "PShader", "ps_5_0", D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, 0, &PS2, 0, 0))) throw(std::string("Sky Shader Error 2"));
// encapsulate both shaders into shader objects
if (FAILED(d3ddev->CreateVertexShader(VS2->GetBufferPointer(), VS2->GetBufferSize(), NULL, &pskyVS))) throw(std::string("Sky Shader Error 1A"));
if (FAILED(d3ddev->CreatePixelShader(PS2->GetBufferPointer(), PS2->GetBufferSize(), NULL, &pskyPS))) throw(std::string("Sky Shader Error 2A"));

Using two buffers for compiling the shaders solved the problem, though i have no idea why. Thank you for the support, though ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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