繁体   English   中英

如何从OBJ文件中正确读取信息并使用它来通过DirectX 11渲染模型

[英]How to correctly read information from OBJ file and use it to render a model with DirectX 11

我正在尝试使用DirectX以OBJ文件格式呈现模型。 我正在使用简单的多维数据集模型,但得到了一些非常奇怪的结果(下图)

我尝试通过手动填充vertecies数组来渲染多维数据集,并且效果很好。 研究了OBJ文件格式后,我想到应该做类似的事情,但是我不明白为什么这不起作用。


发送两个函数和结构描述:

  1. initGeometry
    在此功能中,我设置了几何图形,着色器并从文件中读取信息。 我认为我在此函数的末尾做错了什么,因为我没有更改着色器部分和初始化部分,只是添加了填充顶点数组的新方法
  2. 渲染
    此功能从我的第一个版本起就没有任何变化,在第一个版本中,我填写了Vertecies数组。
  3. 结构
    只是一些结构描述。
HRESULT RenderDevice::initGeometry() {

    ///////READING INFO FROM FILE//////////
    ifstream *inp = new ifstream("test.obj");
    ofstream *out = new ofstream("result.txt");
    char str[256];
    while (!inp->eof()) {
        inp->getline(str, 256);
        meshInfo.coord.push_back(new std::string(str));
    }

    HRESULT hr = S_OK;
    ID3DBlob *pVSBlob = NULL;
    hr = compileShaderFromFile(L"texture.fx", "VS", "vs_4_0", &pVSBlob);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Can't compile Vertex Shader", L"Error", MB_OK);
        return hr;
    }
    hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);
    if (FAILED(hr)) {
        pVSBlob->Release();
        return hr;
    }

    D3D11_INPUT_ELEMENT_DESC layout[] = {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
    };
    UINT numElemenets = ARRAYSIZE(layout);

    hr = g_pd3dDevice->CreateInputLayout(layout, numElemenets, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &g_pVertexLayout);
    pVSBlob->Release();
    if (FAILED(hr)) {
        return hr;
    }
    g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
    ID3DBlob *pPSBlob = NULL;
    hr = compileShaderFromFile(L"texture.fx", "PS", "ps_4_0", &pPSBlob);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Can't compile Pixel Shader", L"Error", MB_OK);
        return hr;
    }

    hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);
    pPSBlob->Release();
    if (FAILED(hr)) {
        return hr;
    }
    pPSBlob = NULL;
    hr = compileShaderFromFile(L"texture.fx", "PSSolid", "ps_4_0", &pPSBlob);
    if (FAILED(hr)) {
        MessageBox(NULL, L"Can't compile Solid Pixel Shader", L"Error", MB_OK);
        return hr;
    }
    hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShaderSolid);
    pPSBlob->Release();
    if (FAILED(hr)) {
        return hr;
    }

    /////////SPLITING INFO INTO DIFFERENT VECTORS/////////////////
    for (int i = 0; i < meshInfo.coord.size(); i++) {
        if (meshInfo.coord[i]->c_str()[0] == 'v' && meshInfo.coord[i]->c_str()[1] != 'n') {
            float tmpx, tmpy, tmpz;
            sscanf_s(meshInfo.coord[i]->c_str(), "v %f %f %f", &tmpx, &tmpy, &tmpz);
            meshInfo.positions.push_back(XMFLOAT3(tmpx, tmpy, tmpz));
        } else if (meshInfo.coord[i]->c_str()[0] == 'v' && meshInfo.coord[i]->c_str()[1] == 'n') {
            float tmpx, tmpy, tmpz;
            sscanf_s(meshInfo.coord[i]->c_str(), "vn %f %f %f", &tmpx, &tmpy, &tmpz);
            meshInfo.normals.push_back(XMFLOAT3(tmpx, tmpy, tmpz));
        } else if (meshInfo.coord[i]->c_str()[0] == 'f') {
            int iX, iY, iZ, nX, nY, nZ;
            sscanf_s(meshInfo.coord[i]->c_str(), "f %d//%d %d//%d %d//%d", &iX, &nX, &iY, &nY, &iZ, &nZ);
            meshInfo.indexiesPoints.push_back(iX);
            meshInfo.indexiesPoints.push_back(iY);
            meshInfo.indexiesPoints.push_back(iZ);

            meshInfo.indexiesNormals.push_back(nX);
            meshInfo.indexiesNormals.push_back(nY);
            meshInfo.indexiesNormals.push_back(nZ);
        }
    }

    meshInfo.indexiesAmount = meshInfo.indexiesPoints.size();

    meshInfo.vertexAmount = meshInfo.positions.size();
    meshInfo.normalsAmount = meshInfo.normals.size();
    Vertex *vertices = new Vertex[meshInfo.indexiesAmount];

    //////////////FILLING VERTECIES ARRAY///////////////
    for (int i = 0; i < meshInfo.indexiesAmount; i++) {
        vertices[i].normal.x = meshInfo.normals[meshInfo.indexiesNormals[i] - 1].x;
        vertices[i].normal.y = meshInfo.normals[meshInfo.indexiesNormals[i] - 1].y;
        vertices[i].normal.z = meshInfo.normals[meshInfo.indexiesNormals[i] - 1].z;

        vertices[i].pos.x = meshInfo.positions[meshInfo.indexiesPoints[i] - 1].x;
        vertices[i].pos.y = meshInfo.positions[meshInfo.indexiesPoints[i] - 1].y;
        vertices[i].pos.z = meshInfo.positions[meshInfo.indexiesPoints[i] - 1].z;
    } 

    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(Vertex) * meshInfo.indexiesAmount;
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;

    D3D11_SUBRESOURCE_DATA initData;
    ZeroMemory(&initData, sizeof(initData));
    initData.pSysMem = vertices;
    hr = g_pd3dDevice->CreateBuffer(&bd, &initData, &g_pVertexBuffer);
    if (FAILED(hr)) {
        return hr;
    }


    ///////////////////FILLING INIXIES ARRAY///////////////////
    WORD *indixies = new WORD[meshInfo.indexiesAmount];
    for (int i = 0; i < meshInfo.indexiesAmount; i++) {
        indixies[i] = meshInfo.indexiesPoints[i];
    }

    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(int) * meshInfo.indexiesAmount;
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = 0;
    initData.pSysMem = indixies;
    hr = g_pd3dDevice->CreateBuffer(&bd, &initData, &g_pIndexBuffer);
    if (FAILED(hr)) {
        return hr;
    }

    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);

    g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);

    g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(ConstantBuffer);
    bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bd.CPUAccessFlags = 0;
    hr = g_pd3dDevice->CreateBuffer(&bd, NULL, &g_pCBMatrixes);
    if (FAILED(hr)) {
        return hr;
    }

    return S_OK;
}
void RenderDevice::render() {
    float clearColor[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
    g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, clearColor);

    g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
    updateLigth();

    for (int i = 0; i < 6; i++) {
        updateMatrix(MX_SETWORLD, i * (XM_PI * 2) / 6);
        g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
        g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pCBMatrixes);
        g_pImmediateContext->VSSetConstantBuffers(1, 1, &g_pCBLigth);
        g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pCBMatrixes);
        g_pImmediateContext->PSSetConstantBuffers(1, 1, &g_pCBLigth);
        g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
        g_pImmediateContext->DrawIndexed(meshInfo.indexiesAmount, 0, 0);
    }


    g_pImmediateContext->PSSetShader(g_pPixelShaderSolid, NULL, 0);
    for (int m = 0; m < 2; m++) {
        updateMatrix(m, 0);
        g_pImmediateContext->DrawIndexed(meshInfo.indexiesAmount, 0, 0);
    }

    g_pSwapChain->Present(0, 0);
}
typedef struct Vertex {
    XMFLOAT3 pos;
    XMFLOAT3 normal;
}Vertex;

typedef struct MeshInfo {
    int vertexAmount;
    int normalsAmount;
    vector<XMFLOAT3> positions;
    vector<XMFLOAT3> normals;
    vector<string*> coord;
    vector<int> indexiesPoints;
    vector<int> indexiesNormals;
    int indexiesAmount;
}MeshInfo;


typedef struct ConstantBuffer {
    XMMATRIX mWorld;
    XMMATRIX mView;
    XMMATRIX mProjection;
    XMFLOAT4 vLigthDir[2];
    XMFLOAT4 vLigthColor[2];
    XMFLOAT4 vOutputColor;
}ConstantBuffer;

我希望在程序的窗口中看到6个多维数据集, 但是我得到了这个东西

OBJ文件格式使用基于一个的编号存储索引(第一个顶点索引为1) Wavefron Obg文件格式 DirectX使用基于零的编号(第一个顶点索引为0,与C,C ++相同)。

因此,您应该转换索引值以使用它们。 您可以这样做:

for (int i = 0; i < meshInfo.indexiesAmount; i++) {
    indixies[i] = meshInfo.indexiesPoints[i] - 1;
}

我实际上找到了解决我问题的方法。 主要的问题是为正确提取证件制定正确的命令。 但是在.OBJ文件中,仅写入UNIQUE顶点,法线和纹理坐标。 它们也彼此分开(例如,可以是8个UNIQUE顶点坐标和6个UNIQUE法线坐标)。 最主要的是部分发生了面部描述。 每个面孔都指向特定的位置索引,法线和纹理坐标,这意味着我们可以在不同的时间使用相同的法线,位置和纹理坐标(我知道这很明显)。 而且我意识到我完全不需要indexies数组,因为我填写的Vertecies数组已经是一个模型! 我最终使用了Draw方法,而不是ID3D11DeviceContext中的DrawIndexed 这就是我从搅拌机获得更复杂形状(例如Susanna)的结果

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM