DirectX/C++: Texture Coordinates not "correct" in-engine correctly after Obj export

2.1k views Asked by At

If I draw a single plane, the texture coordinates are mapped correctly. (4 Verts, 4 TC, 6 Indices(2 polys))

Even if it's subdivided, (9 Verts, 9 TC, 27 Indices(8 polys)) the texture will display: enter image description here

(Maya complex plane) enter image description here

I can take my [written] Obj converter and load the Texture coordinates into the buffer. However, if I extrude a face in Maya, and even applying a planar UV map to "repair" the broken uv's, (above) the texture coordinates get really wild in-engine. (below) enter image description here

Is there an issue with Obj texture coordinate format?

Update: I've drawn with D3D11_PRIMITIVE_TOPOLOGY_LINELIST, and noticed a change in indexing as well..enter image description here Would this be the issue? or should I reconstruct texture coords as brushed on at http://www.gamedev.net/topic/600234-texcoord-count-is-different-than-vertex-count/

3

There are 3 answers

0
Rashid Ellis On BEST ANSWER

This issue was caused by the texture coordinates index not being equal to the vertex index. To resolve the problem, the texture coordinate index had to be ordered such as to line up with the vertex index.

For this issue, I was able to resolve using a brute force method that fit my understanding, which is slow, that catalogs the entire Vertex/Texture Coordinates as a key and reconstructs the full explicit array of vertices and Texture coordinates from their indices, filling a custom struct that fits the needs of my application.

enter image description here

There are other faster solutions that involve using a hash http://programminglinuxgames.blogspot.com/2010/03/wavefront-obj-file-format-opengl-vertex.html

A related issue with normals: OpenGL - Index buffers difficulties

And 3 index buffers

And a good explaination: Why is my OBJ parser rendering meshes like this?

And further resources on obj format: http://en.wikipedia.org/wiki/Wavefront_.obj_file

OBJ resources: http://www.martinreddy.net/gfx/3d/OBJ.spec http://www.fileformat.info/format/wavefrontobj/egff.htm

Also, the MeshFromObj10 Tutorial from the DirectX library helps some, getting it done in an efficient way. There's no easy way around coding it, outside of find a third party source.

2
Abdullah Leghari On

From Maya try re-exporting the texture after performing extrude for correct uv mapping.

Extruding creates new faces and existing uv mapping doesn't apply to those. Try using Geometry clean tool.

As far as I get you are editing the model after the UV map had been made and not updating the UV map to extruded object (which is still planner).

You can also try expert all option which includes the texture, not just the model in .obj

Haven't used Maya for a while though :(

7
Mikael Törnqvist On

Check out these things, it might help you:

DirectX uses left hadned coordinate systems. I think you will get a right handed coordinate system from Maya/3ds Max when you export to .obj files ://msdn.microsoft.com/en-us/library/windows/desktop/bb204853(v=vs.85).aspx

Compare your vertecies count, in Maya and then in your program.

Figure out the reason why you get 1.000671 in your TU/TV coordinates, this looks like it is a bit high.

Make sure you export as Triangles and not Rectangles.

Show your normals in Maya, it looks like some part of the ground/rectangle this object is standing on is missing. Or you could try to disable culling in your D3D11_RASTERIZER_DESC.

I don't have Maya installed on my computer right now, but i think you can get a graphical view in there that shows you the excact TU/TV coordinates on your texture.

http ://www.youtube.com/watch?v=T-fFpmBYP_Q That view is displayed in this video at 4,21.

EDIT:

Providing some code examples:

struct D3D11TextureVertexType
{
    XMFLOAT3 Position;
    XMFLOAT2 TX;
};

This is how you could put the vertices on the pipe:

hr = m_pd3dImmediateContext->Map(MyID3D11Buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    if (FAILED(hr)) return hr;

    pData = (D3D11TextureVertexType*)mappedResource.pData;
    memcpy(pData, MYOBJECTVERTICES/*this is D3D11TextureVertexType*/, sizeof(D3D11TextureVertexType) * VertexCount);

    m_pd3dImmediateContext->Unmap(MyID3D11Buffer, 0);

    stride = sizeof(D3D11TextureVertexType);
    offset = 0;

    m_pd3dImmediateContext->IASetVertexBuffers(0, 1, &MyID3D11Buffer, &stride, &offset);
    m_pd3dImmediateContext->IASetIndexBuffer(m_AdjRectangleIBuffer, DXGI_FORMAT_R32_UINT, 0);
    m_pd3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    result = m_TextureShader->Render(m_pd3dImmediateContext, 6, worldMatrix, viewMatrix, orthoMatrix, m_Textures[Q.textureID]->pSRV);           if (!result)
    {
        return S_FALSE;
    }

This is some intresting functions in the TextureShaderClass

bool Render(ID3D11DeviceContext* deviceContext, int indexCount, DirectX::CXMMATRIX worldMatrix, DirectX::CXMMATRIX viewMatrix, DirectX::CXMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture)
{
    bool result;

    result = SetShaderParameters(deviceContext, worldMatrix, viewMatrix, projectionMatrix, texture);
    if (!result)
    {
        return false;
    }

    RenderShader(deviceContext, indexCount);

    return true;
}

bool InitializeShader(ID3D11Device* device, const WCHAR* filename)
{
    HRESULT result;
    ID3D10Blob* errorMessage;
    ID3D10Blob* vertexShaderBuffer;
    ID3D10Blob* pixelShaderBuffer;
    D3D11_INPUT_ELEMENT_DESC polygonLayout[2];
    unsigned int numElements;
    D3D11_BUFFER_DESC matrixBufferDesc;
    D3D11_SAMPLER_DESC samplerDesc;

    errorMessage = 0;
    vertexShaderBuffer = 0;
    pixelShaderBuffer = 0;



    result = D3DCompileFromFile(filename, NULL, NULL, "TextureVertexShader", "vs_5_0", 0, 0, &vertexShaderBuffer, &errorMessage);
    if (FAILED(result))
    {
        if (errorMessage)
        {
            //OutputShaderErrorMessage(errorMessage, hwnd, filename);
        }
        else
        {
            MessageBox(0, filename, L"Missing Shader File", MB_OK);
        }

        return false;
    }

    result = D3DCompileFromFile(filename, NULL, NULL, "TexturePixelShader", "ps_5_0", 0, 0, &pixelShaderBuffer, &errorMessage);
    if (FAILED(result))
    {
        if (errorMessage)
        {
            //OutputShaderErrorMessage(errorMessage, hwnd, psFilename);
        }
        else
        {
            MessageBox(0, filename, L"Missing Shader File", MB_OK);
        }

        return false;
    }

    result = device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &m_vertexShader);
    if (FAILED(result))
    {
        return false;
    }

    result = device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &m_pixelShader);
    if (FAILED(result))
    {
        return false;
    }

    polygonLayout[0].SemanticName = "POSITION";
    polygonLayout[0].SemanticIndex = 0;
    polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
    polygonLayout[0].InputSlot = 0;
    polygonLayout[0].AlignedByteOffset = 0;
    polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    polygonLayout[0].InstanceDataStepRate = 0;

    polygonLayout[1].SemanticName = "TEXCOORD";
    polygonLayout[1].SemanticIndex = 0;
    polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
    polygonLayout[1].InputSlot = 0;
    polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
    polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    polygonLayout[1].InstanceDataStepRate = 0;

    numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);

    result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &m_layout);
    if (FAILED(result))
    {
        return false;
    }

    vertexShaderBuffer->Release();
    vertexShaderBuffer = 0;

    pixelShaderBuffer->Release();
    pixelShaderBuffer = 0;

    matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
    matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    matrixBufferDesc.MiscFlags = 0;
    matrixBufferDesc.StructureByteStride = 0;

    result = device->CreateBuffer(&matrixBufferDesc, NULL, &m_matrixBuffer);
    if (FAILED(result))
    {
        return false;
    }

    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.MipLODBias = 0.0f;
    samplerDesc.MaxAnisotropy = 1;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    samplerDesc.BorderColor[0] = 0;
    samplerDesc.BorderColor[1] = 0;
    samplerDesc.BorderColor[2] = 0;
    samplerDesc.BorderColor[3] = 0;
    samplerDesc.MinLOD = 0;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    result = device->CreateSamplerState(&samplerDesc, &m_sampleState);
    if (FAILED(result))
    {
        return false;
    }

    return true;
}
bool SetShaderParameters(ID3D11DeviceContext* deviceContext, DirectX::CXMMATRIX worldMatrix, DirectX::CXMMATRIX  viewMatrix, DirectX::CXMMATRIX  projectionMatrix, ID3D11ShaderResourceView* texture)
{
    HRESULT result;
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    MatrixBufferType* dataPtr;
    unsigned int bufferNumber;

    result = deviceContext->Map(m_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    if (FAILED(result))
    {
        return false;
    }

    dataPtr = (MatrixBufferType*)mappedResource.pData;

    DirectX::XMMATRIX world = worldMatrix;
    world = XMMatrixTranspose(world);
    DirectX::XMMATRIX view = viewMatrix;
    view = XMMatrixTranspose(view);
    DirectX::XMMATRIX projection = projectionMatrix;
    projection = XMMatrixTranspose(projection);

    dataPtr->world = world;
    dataPtr->view = view;
    dataPtr->projection = projection;

    deviceContext->Unmap(m_matrixBuffer, 0);

    bufferNumber = 0;

    deviceContext->VSSetConstantBuffers(bufferNumber, 1, &m_matrixBuffer);

    deviceContext->PSSetShaderResources(0, 1, &texture);

    return true;
}

void RenderShader(ID3D11DeviceContext* deviceContext, int indexCount)
{
    deviceContext->IASetInputLayout(m_layout);

    deviceContext->VSSetShader(m_vertexShader, NULL, 0);
    deviceContext->PSSetShader(m_pixelShader, NULL, 0);

    deviceContext->PSSetSamplers(0, 1, &m_sampleState);

    deviceContext->DrawIndexed(indexCount, 0, 0);

    return;
}