2

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/

Rashid Ellis
  • 330
  • 3
  • 22
  • Check your TU/TV Coordinates after you have loaded the .obj file into your program, It looks like it is something wrong with those. – Mikael Törnqvist Nov 14 '14 at 17:35
  • I set a watch for the `vertex` struct array, before it gets sent to the shader. The values seem legit. I did notice that some of the values were larger than 1, by smidgens. (1.000671) I think that this is a result of being stored as `float`, would this matter too much if `SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;...`? – Rashid Ellis Nov 14 '14 at 18:01

3 Answers3

3

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.

Community
  • 1
  • 1
Rashid Ellis
  • 330
  • 3
  • 22
2

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;
}
  • Wow this is great! I think I've found the issue: I ran a `for` loop for the `vertex.size()` and not the size of the tex/coord array while copying the values over, seems that if the total elements in the tex/coord array = num_Elements in the vertex array, the object displays fine. If the number of tex/coords is greater then the number of vertices, than some values will be undefined in a nasty pointer sort of way. I'm going to rewrite to test. – Rashid Ellis Nov 14 '14 at 18:52
  • Figured the number of texture coordinates elements would always equal the number of vertices...? – Rashid Ellis Nov 14 '14 at 18:55
  • This is my structure I send to my Graphics card: struct VertexType { XMFLOAT3 position; XMFLOAT2 texture; XMFLOAT3 normal; }; so 3 Coordinates for Position, 2 Coordinates for TU/TV and 3 Coordinates for Normals. Per Vertex. 3 Vertex per triangle, 6 vertices per Rectangle. And so on. – Mikael Törnqvist Nov 14 '14 at 18:57
  • Same here, only no normals, although I have the data. (I wrote a obj file reader with an output of raw `vector< vector >` It's copied into the standard vertex struct) – Rashid Ellis Nov 14 '14 at 19:02
  • You don't need the normal data unless you want to use BumpMapping and Lightning etc, or CULL_BACK. Get this working first. Make a new Obj with only 4-6 triangles. Check the result. I'm sure that will make this easier to debug :) – Mikael Törnqvist Nov 14 '14 at 19:06
  • I'm not sure how to implement the extra sizing to consider the size of the texture coords. If I increase the size of the Vertex array to the number of Texture coords, wouldn't that give me faulty vertex values? Is there a way to define `BufferDescription.ByteWidth = sizeof(vtest) * sz_Texcoord;` to account for both entries? or better yet, have the vertex structure with two separate array data members? I've tested some implementation of this but nothing was passed through. – Rashid Ellis Nov 15 '14 at 00:11
  • It appears that the object file has multiple indices per vertex/texture coordinate/normal I'm going to work on it and get back. – Rashid Ellis Nov 16 '14 at 00:14
1

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 :(

Abdullah Leghari
  • 2,332
  • 3
  • 24
  • 40
  • I think I'll try to import obj output in Blender; If import works, likely it's my obj importer. – Rashid Ellis Nov 14 '14 at 18:03
  • Ok, It's importing fine into Blender, which is good. I must be doing something code-wise. I'll look into the float issue with the infinitesimals. – Rashid Ellis Nov 14 '14 at 18:25