【问题标题】:DirectX/C++: Texture Coordinates not "correct" in-engine correctly after Obj exportDirectX/C++:Obj 导出后,纹理坐标在引擎中不正确“正确”
【发布时间】:2015-01-12 03:39:59
【问题描述】:

如果我绘制一个平面,则纹理坐标映射正确。 (4 个顶点,4 个 TC,6 个索引(2 个多边形))

即使它被细分,(9 Verts, 9 TC, 27 Indices(8 polys)) 纹理也会显示:

(玛雅复平面)

我可以使用我的[编写] Obj 转换器并将纹理坐标加载到缓冲区中。但是,如果我在 Maya 中挤出一个面,甚至应用平面 UV 贴图来“修复”损坏的 uv,(上图)纹理坐标在引擎中会变得非常狂野。 (以下)

Obj 纹理坐标格式有问题吗?

更新:我使用 D3D11_PRIMITIVE_TOPOLOGY_LINELIST 进行绘制,并注意到索引也发生了变化.. 这会是问题吗?或者我应该在http://www.gamedev.net/topic/600234-texcoord-count-is-different-than-vertex-count/ 上重建纹理坐标

【问题讨论】:

  • 在你将 .obj 文件加载到你的程序中后检查你的 TU/TV 坐标,看起来它有问题。
  • vertex struct 数组被发送到着色器之前,我设置了一个监视。这些值似乎是合法的。我确实注意到有些值比 1 大一点点。 (1.000671) 我认为这是存储为float 的结果,如果SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;... 会不会太重要?

标签: c++ directx-11 texture-mapping coordinate-systems uv-mapping


【解决方案1】:

这个问题是由纹理坐标索引不等于顶点索引引起的。为了解决这个问题,必须对纹理坐标索引进行排序,以便与顶点索引对齐。

对于这个问题,我能够使用符合我理解的蛮力方法来解决,这种方法很慢,将整个顶点/纹理坐标编目为一个键,并从它们的顶点和纹理坐标的完整显式数组中重建索引,填充适合我的应用程序需求的自定义结构。

还有其他更快的解决方案涉及使用哈希 http://programminglinuxgames.blogspot.com/2010/03/wavefront-obj-file-format-opengl-vertex.html

法线的相关问题: OpenGL - Index buffers difficulties

还有3 index buffers

还有一个很好的解释: Why is my OBJ parser rendering meshes like this?

还有更多关于 obj 格式的资源: http://en.wikipedia.org/wiki/Wavefront_.obj_file

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

此外,DirectX 库中的 MeshFromObj10 教程可以帮助一些人,以有效的方式完成。除了找到第三方来源之外,没有简单的编码方法。

【讨论】:

    【解决方案2】:

    看看这些东西,它可能对你有帮助:

    DirectX 使用左坐标系。我认为当您导出到 .obj 文件时,您会从 Maya/3ds Max 获得右手坐标系 ://msdn.microsoft.com/en-us/library/windows/desktop/bb204853(v=vs.85).aspx

    在 Maya 和程序中比较您的顶点数。

    找出你的 TU/TV 坐标中出现 1.000671 的原因,这看起来有点高。

    确保导出为三角形而不是矩形。

    在 Maya 中显示您的法线,看起来该对象所在的地面/矩形的某些部分丢失了。或者您可以尝试在 D3D11_RASTERIZER_DESC 中禁用剔除。

    我现在没有在我的计算机上安装 Maya,但我认为您可以在其中获得一个图形视图,显示纹理上精确的 TU/TV 坐标。

    http://www.youtube.com/watch?v=T-fFpmBYP_Q 该视频显示在 4,21。

    编辑:

    提供一些代码示例:

    struct D3D11TextureVertexType
    {
        XMFLOAT3 Position;
        XMFLOAT2 TX;
    };
    

    这就是你可以将顶点放在管道上的方法:

    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;
        }
    

    这是 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;
    }
    

    【讨论】:

    • 哇,这太棒了!我想我找到了问题所在:我为vertex.size() 运行了for 循环,而不是在复制值时 tex/coord 数组的大小,似乎如果 tex/coord 数组中的总元素 = num_Elements 在顶点数组中,对象显示正常。如果 tex/coords 的数量大于顶点的数量,那么某些值将以令人讨厌的指针方式未定义。我要重写测试一下。
    • 认为纹理坐标元素的数量总是等于顶点的数量...?
    • 这是我发送到显卡的结构:struct VertexType { XMFLOAT3 position; XMFLOAT2 纹理; XMFLOAT3 正常; };所以 3 个位置坐标,2 个 TU/TV 坐标和 3 个法线坐标。每个顶点。每个三角形 3 个顶点,每个矩形 6 个顶点。以此类推。
    • 这里也一样,只是没有法线,虽然我有数据。 (我写了一个 obj 文件阅读器,输出为 raw vector< vector <float> > 它被复制到标准顶点结构中)
    • 你不需要普通数据,除非你想使用 BumpMapping 和 Lightning 等,或者 CULL_BACK。先让这个工作。制作一个只有 4-6 个三角形的新 Obj。检查结果。我相信这会让调试更容易:)
    【解决方案3】:

    从 Maya 尝试在执行拉伸后重新导出纹理以正确的 uv 映射。

    挤压会创建新的面,而现有的 uv 映射不适用于这些面。尝试使用几何清理工具。

    据我所知,您是在制作 UV 贴图后编辑模型,而不是将 UV 贴图更新为挤出对象(这仍然是规划器)。

    您也可以尝试包含纹理的所有选项,而不仅仅是 .obj 中的模型

    虽然有一段时间没有使用 Maya :(

    【讨论】:

    • 我想我会尝试在 Blender 中导入 obj 输出;如果导入有效,可能是我的 obj 导入器。
    • 好的,它可以很好地导入 Blender,这很好。我必须在代码方面做一些事情。我将研究无穷小的浮点问题。
    猜你喜欢
    • 2020-07-12
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    • 2016-11-03
    • 2017-10-02
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    相关资源
    最近更新 更多