0
votes

I am working on a project in which I use DirectX Toolkit to load FBX models. As I understood, DXTK does not support HLSL shaders for its models, so I have to get the model information (vertex buffer, index buffer, etc.) from the model object and implement a standart Direct3D drawing, if I want to use HLSL shaders for the rendering.

My problem is, that I can't reach the texture coordinates from the vertex shader. For testing, I set the vertex shader to pass through the coordinates to the pixel shader, where I color the whole object with the texture coordinates like this:

float4(input.texCoord, 0.0f, 1.0f);

In the result, the whole object is black, so the texcoords are (0.0, 0.0) everywhere. I checked the model with the DXTK Model::Draw(...) funcion, and it is textured the correct way, so my model, and my model loading code seems correct.

I learnt that DXTK model loading uses the following vertex buffer declaration:

const D3D11_INPUT_ELEMENT_DESC VertexPositionNormalTangentColorTexture::InputElements[] =
{
    { "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NORMAL",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TANGENT",     0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR",       0, DXGI_FORMAT_R8G8B8A8_UNORM,     0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD",    0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

So I tried to match my vertex shader input structure like this:

struct VertexShaderInput
{
    float3 pos : SV_Position;
    float3 normal : NORMAL;
    float4 tangent : TANGENT;
    float4 color : COLOR;
    float2 texCoord : TEXCOORD;
};

Here is how I load the model:

void SceneObject::LoadMesh(
    std::shared_ptr<DX::DeviceResources> deviceResources,
    const wchar_t* modelFile)
{
    auto device = deviceResources->GetD3DDevice();
    EffectFactory fx(device);
    this->model = Model::CreateFromCMO(device, modelFile, fx, true);
}

And here is my draw function:

void SceneObject::Draw(std::shared_ptr<DX::DeviceResources> deviceResources)
{
    auto device = deviceResources->GetD3DDevice();
    auto context = deviceResources->GetD3DDeviceContext();
    CommonStates states(device);

    context->UpdateSubresource(
        this->vsConstantBuffer.Get(),
        0,
        NULL,
        &this->vsConstantBufferData,
        0,
        0);

    context->UpdateSubresource(
        this->psConstantBuffer.Get(),
        0,
        NULL,
        &this->psConstantBufferData,
        0,
        0);

    //model->Draw(context, states, local, view, proj);
    XMVECTOR qid = XMQuaternionIdentity();
    const XMVECTORF32 scale = { 1.f, 1.f, 1.f };
    const XMVECTORF32 translate = { 0.f, 0.f, 0.f };
    //XMVECTOR rotate = XMQuaternionRotationRollPitchYaw(0, XM_PI / 2.f, -XM_PI / 2.f);
    XMVECTOR rotate = XMQuaternionRotationRollPitchYaw(0, 0, 0);
    XMMATRIX worldMatrix = XMLoadFloat4x4(&this->vsConstantBufferData.model);
    XMMATRIX local = XMMatrixMultiply(worldMatrix, XMMatrixTransformation(g_XMZero, qid, scale, g_XMZero, rotate, translate));
    //this->model->Draw(context, states, local, XMLoadFloat4x4(&vsConstantBufferData.view), XMLoadFloat4x4(&vsConstantBufferData.projection), false);

    XMStoreFloat4x4(&this->vsConstantBufferData.model, local);

    for each(auto& mesh in model->meshes)
    {
        for each (auto& part in mesh->meshParts)
        {
            context->IASetVertexBuffers(
                0,
                1,
                part->vertexBuffer.GetAddressOf(),
                &part->vertexStride,
                &part->vertexOffset
                );

            context->IASetIndexBuffer(
                part->indexBuffer.Get(),
                part->indexFormat,
                0
                );

            context->IASetPrimitiveTopology(part->primitiveType);

            //context->IASetInputLayout(inputLayout.Get());
            context->IASetInputLayout(part->inputLayout.Get());

            // Attach our vertex shader.
            context->VSSetShader(
                vertexShader.Get(),
                nullptr,
                0
                );

            // Send the constant buffer to the graphics device.
            context->VSSetConstantBuffers(
                0,
                1,
                vsConstantBuffer.GetAddressOf()
                );

            // Attach our pixel shader.
            context->PSSetShader(
                pixelShader.Get(),
                nullptr,
                0
                );

            // Send the constant buffer to the graphics device.
            context->PSSetConstantBuffers(
                1,
                1,
                psConstantBuffer.GetAddressOf()
                );

            context->PSSetShaderResources(0, 1, diffuseTexture.GetAddressOf());
            context->PSSetSamplers(0, 1, linearSampler.GetAddressOf());

            // Draw the objects.
            context->DrawIndexed(
                part->indexCount,
                part->startIndex,
                0
                );
        }
    }
}

If you need more code, you can check my whole project here: https://github.com/GiGu92/WaterRenderingDemo

What am I messing up?

1
I managed to get around the problem temporarily, as I implemented procedurally generated plane mesh, but you can still browse my project at the github link above. See the commit "minor changes (texcoords still not working)", that is where I am still trying to draw a loaded model with my shader.Gábor Szalóki

1 Answers

1
votes

Your code above doesn't indicate where you are creating your vertex shader.

For CMOs, take a look at Src\Shaders\DGSLEffect.fx for how they are used with custom shaders.

The default EffectFactory or DGSLEffectFactory is setting up a standard vertex & pixel shader for rendering the Model as a BasicEffect, SkinnedEffect, or DGSLEffect. Details on doing custom rendering are covered in the wiki, but I suggest your first get it rendering using the default effects as you expect it. See the tutorial.

You can override the entire pipeline if desired in a number of ways:

  • Implement your own IEffect* interfaces and IEffectFactory to use with the Model loader
  • Override the shaders while rendering directly with ModelMesh / ModelMeshParts

For CMO files, the vertex format is indeed either VertexPositionNormalTangentColorTexture or VertexPositionNormalTangentColorTextureSkinning, although for SDKMESH files it is a bit more variable.

As always, ensure you have the debug device enabled and check the HRESULT of any Direct3D function that returns one to ensure you aren't missing some configuration or API usage problem.