1

My DirectX application does not render the texture correctly. Result:

Cat

Expected from VS editor:

enter image description here

As you can see the cat texture is not completely drawn.

I 'm using WaveFrontReader to load the .OBJ and the .MTL files and WicTextureLoader to load the PNG/JPG.

My HLSL:

cbuffer constants : register(b0)
{
    row_major float4x4 transform;
    row_major float4x4 projection;
    float3 lightvector;
}

struct vs_in
{
    float3 position : POS;
    float3 normal   : NOR;
    float2 texcoord : TEX;
    float4 color    : COL;
};

struct vs_out
{
    float4 position : SV_POSITION;
    float2 texcoord : TEX;
    float4 color    : COL;
};

Texture2D    mytexture : register(t0);
SamplerState mysampler : register(s0);

vs_out vs_main(vs_in input)
{
    float light = clamp(dot(normalize(mul(float4(input.normal, 0.0f), transform).xyz), normalize(-lightvector)), 0.0f, 1.0f) * 0.8f + 0.2f;

    vs_out output;

    output.position = mul(float4(input.position, 1.0f), mul(transform, projection));
    output.texcoord = input.texcoord;
    output.color    = float4(input.color.rgb * light, input.color.a);

    return output;
}

float4 ps_main(vs_out input) : SV_TARGET
{
    return mytexture.Sample(mysampler, input.texcoord) * input.color;
}

My preparation:

void Config3DWindow()
{
const wchar_t* tf = L"1.hlsl";

d2d.m_swapChain1->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&frameBuffer));
d2d.device->CreateRenderTargetView(frameBuffer, nullptr, &frameBufferView);

frameBuffer->GetDesc(&depthBufferDesc); // base on framebuffer properties
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;

CComPtr<ID3DBlob> vsBlob;
D3DCompileFromFile(tf, nullptr, nullptr, "vs_main", "vs_5_0", 0, 0, &vsBlob, nullptr);
d2d.device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &vertexShader);
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] =
{
    { "POS", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,                            0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NOR", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEX", 0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
d2d.device->CreateInputLayout(inputElementDesc, ARRAYSIZE(inputElementDesc), vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &inputLayout);

///////////////////////////////////////////////////////////////////////////////////////////////
CComPtr<ID3DBlob> psBlob;
D3DCompileFromFile(tf, nullptr, nullptr, "ps_main", "ps_5_0", 0, 0, &psBlob, nullptr);
d2d.device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, &pixelShader);


D3D11_BUFFER_DESC constantBufferDesc = {};
constantBufferDesc.ByteWidth = sizeof(Constants) + 0xf & 0xfffffff0;
constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;


d2d.device->CreateBuffer(&constantBufferDesc, nullptr, &constantBuffer);
}

Loading the obj:

WaveFrontReader<UINT> wfr;
wfr.Load(L"12221_Cat_v1_l3.oobj");
wfr.LoadMTL(L"12221_Cat_v1_l3.mtl");
obj.CreateDirect3D2(wfr);

CreateDirect3D2() function:

std::vector<float> Vertices;
 //    float VertexDataX[] = // float3 position, float3 normal, float2 texcoord, float4 color

auto numV = wf.vertices.size();
Vertices.resize(numV * 12);
for (size_t i = 0; i < numV; i++)
{
    auto& v = wf.vertices[i];
    float* i2 = Vertices.data() + (i * 12);

    // position
    i2[0] = v.position.x;
    i2[1] = v.position.y;
    i2[2] = v.position.z;

    // normal
    i2[3] = v.normal.x;
    i2[4] = v.normal.y;
    i2[5] = v.normal.z;

    // tx
    i2[6] = v.textureCoordinate.x;
    i2[7] = v.textureCoordinate.y;

    // Colors
    i2[8] = 1.0f;
    i2[9] = 1.0f;
    i2[10] = 1.0f;
    i2[11] = 1.0f;

}

D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.ByteWidth = Vertices.size() * sizeof(float);
vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vertexData = { Vertices.data() }; // in data.h
vertexBuffer = 0;
d2d.device->CreateBuffer(&vertexBufferDesc, &vertexData, &vertexBuffer);


// Indices
std::vector<UINT>& Indices = wf.indices;

D3D11_BUFFER_DESC indexBufferDesc = {};
IndicesSize = Indices.size() * sizeof(UINT);

indexBufferDesc.ByteWidth = IndicesSize;
indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA indexData = { Indices.data() }; // in data.h
indexBuffer = 0;
d2d.device->CreateBuffer(&indexBufferDesc, &indexData, &indexBuffer);

for (auto& ma : wf.materials)
{
    CComPtr<ID3D11Resource> tex;
    CComPtr<ID3D11ShaderResourceView> texv;

    CreateWICTextureFromFile(d2d.device, d2d.context, ma.strTexture, &tex, &texv,0);

    if (tex && texv)
    {
        OBJFT ot;
        ot.texture = tex;
        ot.textureView = texv;
        textures.push_back(ot);
    }
    tex = 0;
    texv = 0;

}

The drawing function:

void Present(OBJF& o, int Count, _3DP& _3, D2D1_COLOR_F bcol)
{
    float w = static_cast<float>(depthBufferDesc.Width);  // width
    float h = static_cast<float>(depthBufferDesc.Height); // height
    float n = 1000.0f;                                    // near
    float f = 1000000.0f;                                 // far

    matrix rotateX = { 1, 0, 0, 0, 0, static_cast<float>(cos(_3.rotation[0])), -static_cast<float>(sin(_3.rotation[0])), 0, 0, static_cast<float>(sin(_3.rotation[0])), static_cast<float>(cos(_3.rotation[0])), 0, 0, 0, 0, 1 };
    matrix rotateY = { static_cast<float>(cos(_3.rotation[1])), 0, static_cast<float>(sin(_3.rotation[1])), 0, 0, 1, 0, 0, -static_cast<float>(sin(_3.rotation[1])), 0, static_cast<float>(cos(_3.rotation[1])), 0, 0, 0, 0, 1 };
    matrix rotateZ = { static_cast<float>(cos(_3.rotation[2])), -static_cast<float>(sin(_3.rotation[2])), 0, 0, static_cast<float>(sin(_3.rotation[2])), static_cast<float>(cos(_3.rotation[2])), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
    matrix scale = { _3.scale[0], 0, 0, 0, 0, _3.scale[1], 0, 0, 0, 0, _3.scale[2], 0, 0, 0, 0, 1 };
    matrix translate = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, _3.translation[0], _3.translation[1], _3.translation[2], 1 };

    ///////////////////////////////////////////////////////////////////////////////////////////
    D3D11_MAPPED_SUBRESOURCE mappedSubresource = {};
    d2d.context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubresource);
    Constants* constants = reinterpret_cast<Constants*>(mappedSubresource.pData);
    constants->Transform = rotateX * rotateY * rotateZ * scale * translate;
    constants->Projection = { 2 * n / w, 0, 0, 0, 0, 2 * n / h, 0, 0, 0, 0, f / (f - n), 1, 0, 0, n * f / (n - f), 0 };
    constants->LightVector = { 1.0f, 1.0f, 1.0f };
    d2d.context->Unmap(constantBuffer, 0);

    ///////////////////////////////////////////////////////////////////////////////////////////

    FLOAT backgroundColor[4] = { 0.00f, 0.00f, 0.00f, 1.0f };
    if (bcol.a > 0)
    {
        backgroundColor[0] = bcol.r;
        backgroundColor[1] = bcol.g;
        backgroundColor[2] = bcol.b;
        backgroundColor[3] = bcol.a;
    }

    UINT stride = 12 * 4; // vertex size (12 floats: float3 position, float3 normal, float2 texcoord, float4 color)
    UINT offset = 0;

    D3D11_VIEWPORT viewport = { 0.0f, 0.0f, w, h, 0.0f, 1.0f };

///////////////////////////////////////////////////////////////////////////////////////////

    auto deviceContext = d2d.context;
    deviceContext->ClearRenderTargetView(frameBufferView, backgroundColor);
    deviceContext->ClearDepthStencilView(depthBufferView, D3D11_CLEAR_DEPTH, 1.0f, 0);

    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    deviceContext->IASetInputLayout(inputLayout);
    deviceContext->IASetVertexBuffers(0, 1, &o.vertexBuffer.p, &stride, &offset);
    deviceContext->IASetIndexBuffer(o.indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    deviceContext->VSSetShader(vertexShader, nullptr, 0);
    deviceContext->VSSetConstantBuffers(0, 1, &constantBuffer.p);
    deviceContext->RSSetViewports(1, &viewport);
    deviceContext->PSSetShader(pixelShader, nullptr, 0);

    std::vector<ID3D11ShaderResourceView*> rsx;
    for (auto& t : o.textures)
        rsx.push_back(t.textureView);
    ID3D11ShaderResourceView** rr = rsx.data();
    deviceContext->PSSetShaderResources(0, rsx.size(), rr);

    deviceContext->PSSetSamplers(0, 1, &samplerState.p);

    deviceContext->OMSetRenderTargets(1, &frameBufferView.p, depthBufferView);
    deviceContext->OMSetDepthStencilState(depthStencilState, 0);

    ///////////////////////////////////////////////////////////////////////////////////////////

    DXGI_RGBA ra = { 1,1,1,1 };
    deviceContext->DrawIndexed(o.IndicesSize, 0, 0);
    d2d.m_swapChain1->Present(1, 0);
}

Entire project here: https://drive.google.com/open?id=1BbW3DUd20bAwei4KjnkUPwgm5Ia1aRxl

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • I find remarkable that the texture seems to work correctly for the ears. So, texture mapping cannot be totally wrong. (For totally wrong texture mapping, I usually get black or some smashed stripes.) – Scheff's Cat Apr 06 '20 at 10:54
  • Yes me too. But when I open the very same file in Paint3D or VS, it opens correctly. Is it the texture problem anyway? – Michael Chourdakis Apr 06 '20 at 10:56
  • I must admit I'm no expert in Direct3D (maybe, a little bit more in OpenGL). Just to find out whether texturing is correct or not - have you tried to render without lighting (i.e. replace `float light = clamp(dot(normalize(mul(float4(input.normal, 0.0f), transform).xyz), normalize(-lightvector)), 0.0f, 1.0f) * 0.8f + 0.2f;` by `float light = 1.0f;`)? I wondered a bit that you do lighting calculation in vertex shader where I would expect it in pixel shader. As it is, it might result in Gouraud shading as I was used to prior OpenGL 3 but I'm a bit uncertain about this. – Scheff's Cat Apr 06 '20 at 11:15
  • I had done that before, same result – Michael Chourdakis Apr 06 '20 at 11:25
  • Texturing without lighting -> Still the black pixels in part of the cat. – Michael Chourdakis Apr 06 '20 at 11:33
  • Out of curiosity, I tried your model in my (not-yet-ready) tool and got this: [**Red Cat**](https://i.stack.imgur.com/H8i5H.png). I noticed that the `.mtl` contains data for bump mapping. On my side, these data is just ignored as I don't support such things (and my self-written OBJ loader cannot map this data into my target API). About your loader, I'm not sure what happens. You may try to exclude the bump mapping stuff from the `.mtl` (temporarily) and check whether this changes anything on your side. – Scheff's Cat Apr 06 '20 at 12:32
  • Same result, even without the bump – Michael Chourdakis Apr 06 '20 at 13:06

1 Answers1

2

This is what I got after I was able to reproduce the issue of OP on my side:

Snapshot of OPs sample code

My only change was that I exluded lighting in the shader code:

vs_out vs_main(vs_in input)
{
    float light = 1.0f;
    //float light = clamp(dot(normalize(mul(float4(input.normal, 0.0f), transform).xyz), normalize(-lightvector)), 0.0f, 1.0f) * 0.8f + 0.2f;

    vs_out output;

    output.position = mul(float4(input.position, 1.0f), mul(transform, projection));
    output.texcoord = input.texcoord;
    output.color    = float4(input.color.rgb * light, input.color.a);

    return output;
}

Then I became aware of the cat's eye on the cat's tail.

That reminded me that a lot of image formats store the image from top to down.

OpenGL textures (and probably Direct3D as well) has usually the origin in the lower left corner. Hence, it's not un-usual that texture images are mirrored vertically (during or after loading the image from file and before sending it to GPU).

To prove my suspicion, I mirrored the image manually (in GIMP) and then (without re-compiling) got this:

Snapshot of OPs sample code after I fixed image

It looks like my suspicion was right.

Something is wrong with the image or texture loading in the loader of OP.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • Excellent. Thanks a lot. Btw I 've another question for you, how to center my object to view. If you know the answer I 'll post another question. – Michael Chourdakis Apr 06 '20 at 13:21
  • 1
    @MichaelChourdakis I usually take the bounding sphere and use a (not completely trivial) formula to fit it into view frustum. Afterwards, I apply the translation from current to computed position to observer (aka cam. matrix). I believe this is worth another question... ;-) (which might be answered from a Direct3D expert.) – Scheff's Cat Apr 06 '20 at 13:25