DirectX11仅在填充的索引和顶点缓冲区中绘制一半的顶点

时间:2018-07-12 21:24:45

标签: c++ windows visual-studio directx direct3d

我有一个似乎无法解决的问题。

我使用TinyObjLoader导入obj文件,并将顶点和索引缓冲区复制到GPU内存以绘制模型。此模型中只有个三角形。没有4+边的多边形,也没有负索引

唯一的问题是我无法绘制完整模型,只能绘制具有正确顶点,正确法线和正确纹理的顶点的1/2到2/3。

我使用#defines将代码分成两种方法来说明此问题。 请注意,要想使它起作用,需要大量的反复试验,因为DirectX11上在线缺乏教程和教育。如果您发现代码的结构方式有任何问题,请随时发表评论。

  1. 方法1是失败的代码。在这里,我制作了顶点的副本以具有不同的法线。这在我的模型中至关重要,因为每个曲面都需要不同的阴影。注意:我知道我可以使用std :: unordered_map使此渲染更加优化,以处理法线指向同一方向的某些重复顶点。

    #ifdef DUPVERTICES
    std::vector<float> vertex_buffer;
    std::vector<uint32_t> index_buffer;
    
    struct T_Vertex
    {
        float vX;
        float vY;
        float vZ;
        float nX;
        float nY;
        float nZ;
        float tX;
        float tY;
        uint32_t vXIndex;
        uint32_t vYIndex;
        uint32_t vZIndex;
        uint32_t nXIndex;
        uint32_t nYIndex;
        uint32_t nZIndex;
        uint32_t tXIndex;
        uint32_t tYIndex;
    };
    
    std::vector<T_Vertex> temp_vertices;
    size_t index_offset = 0;
    for (size_t f = 0; f < shapes[0].mesh.num_face_vertices.size(); f++) {
        int fv = shapes[0].mesh.num_face_vertices[f];
        // Loop over vertices in the face.
        for (size_t v = 0; v < fv; v++) {
    
            // access to vertex
            tinyobj::index_t idx = shapes[0].mesh.indices[index_offset + v];
            if (idx.vertex_index < 0 || idx.normal_index < 0 || idx.texcoord_index < 0)
                continue;
            T_Vertex temp_vertex;
            temp_vertex.vX = idx.normal_index > 0 ? attrib.vertices[3 * idx.vertex_index + 0] : 0;
            temp_vertex.vY = idx.normal_index > 0 ? attrib.vertices[3 * idx.vertex_index + 1] : 0;
            temp_vertex.vZ = idx.normal_index > 0 ? attrib.vertices[3 * idx.vertex_index + 2] : 0;
            temp_vertex.nX = idx.normal_index > 0 ? attrib.normals[3 * idx.normal_index + 0] : 0;
            temp_vertex.nY = idx.normal_index > 0 ? attrib.normals[3 * idx.normal_index + 1] : 0;
            temp_vertex.nZ = idx.normal_index > 0 ? attrib.normals[3 * idx.normal_index + 2] : 0;
            temp_vertex.tX = idx.texcoord_index > 0 ? attrib.texcoords[2 * idx.texcoord_index + 0] : 0;
            temp_vertex.tY = idx.texcoord_index > 0 ? attrib.texcoords[2 * idx.texcoord_index + 1] : 0;
    
            temp_vertex.vXIndex = 3 * idx.vertex_index + 0;
            temp_vertex.vYIndex = 3 * idx.vertex_index + 1;
            temp_vertex.vZIndex = 3 * idx.vertex_index + 2;
            temp_vertex.nXIndex = 3 * idx.normal_index + 0;
            temp_vertex.nYIndex = 3 * idx.normal_index + 1;
            temp_vertex.nZIndex = 3 * idx.normal_index + 2;
            temp_vertex.tXIndex = 2 * idx.texcoord_index + 0;
            temp_vertex.tYIndex = 2 * idx.texcoord_index + 1;
            temp_vertices.push_back(temp_vertex);
        }
        index_offset += fv;
    }
    
    for (auto& temp_vertex : temp_vertices)
    {
        vertex_buffer.push_back(temp_vertex.vX);
        vertex_buffer.push_back(temp_vertex.vY);
        vertex_buffer.push_back(temp_vertex.vZ);
        vertex_buffer.push_back(temp_vertex.nX);
        vertex_buffer.push_back(temp_vertex.nY);
        vertex_buffer.push_back(temp_vertex.nZ);
        vertex_buffer.push_back(temp_vertex.tX); //Set to 0 for no texture
        vertex_buffer.push_back(temp_vertex.tY); //Set to 0 for no texture
        vertex_buffer.push_back(0.0F);
    
        index_buffer.push_back(temp_vertex.vXIndex);
        index_buffer.push_back(temp_vertex.vYIndex);
        index_buffer.push_back(temp_vertex.vZIndex);
        index_buffer.push_back(temp_vertex.nXIndex);
        index_buffer.push_back(temp_vertex.nYIndex);
        index_buffer.push_back(temp_vertex.nZIndex);
        index_buffer.push_back(0);
        index_buffer.push_back(0);
        index_buffer.push_back(0);
    }
    
  2. 方法2有效(减去纹理),但是没有重复的顶点,因此法线方向不利于渲染。但是,在此配置中,每个单个顶点都绘制在正确的位置。请注意,这两个代码的步幅,顶点和索引缓冲区结构相同,缓冲区的大小不同。

    #else
    std::vector<float> vertex_buffer;
    for (int i = 0, j = 0; i < attrib.vertices.size(); i += 3, j += 2)
    {
        vertex_buffer.push_back(attrib.vertices[i + 0]);
        vertex_buffer.push_back(attrib.vertices[i + 1]);
        vertex_buffer.push_back(attrib.vertices[i + 2]);
        vertex_buffer.push_back(attrib.normals[i + 0]);
        vertex_buffer.push_back(attrib.normals[i + 1]);
        vertex_buffer.push_back(attrib.normals[i + 2]);
        vertex_buffer.push_back(0);//attrib.texcoords[j + 0]);
        vertex_buffer.push_back(0);//attrib.texcoords[j + 1]);
        vertex_buffer.push_back(0.0F);
    }
    
    std::vector<UINT> index_buffer;
    for (int i = 0, j = 0; i < shapes[0].mesh.indices.size(); i += 3, j += 2)
    {
        index_buffer.push_back(shapes[0].mesh.indices[i + 0].vertex_index);
        index_buffer.push_back(shapes[0].mesh.indices[i + 1].vertex_index);
        index_buffer.push_back(shapes[0].mesh.indices[i + 2].vertex_index);
        index_buffer.push_back(shapes[0].mesh.indices[i + 0].normal_index);
        index_buffer.push_back(shapes[0].mesh.indices[i + 1].normal_index);
        index_buffer.push_back(shapes[0].mesh.indices[i + 2].normal_index);
        index_buffer.push_back(0);
        index_buffer.push_back(0);
        index_buffer.push_back(0);
    }
    uint32_t vertexes_size = vertex_buffer.size() * sizeof(float);
    uint32_t indexes_size = index_buffer.size() * sizeof(uint32_t);
    int stride_bytes = 36;
    #endif
    
  3. 这是我创建缓冲区的地方,两种方法的代码相同

    //Set Vertex Buffer Array
    g_Mesh11.m_pMeshArray = new SDKMESH_MESH;
    g_Mesh11.m_pVertexBufferArray = new SDKMESH_VERTEX_BUFFER_HEADER;
    int t = g_Mesh11.m_pMeshArray[0].VertexBuffers[0];
    g_Mesh11.m_pMeshArray[0].VertexBuffers[0] = 0;
    D3D11_BUFFER_DESC vertex_buf_desc;
    vertex_buf_desc.ByteWidth = vertexes_size;
    vertex_buf_desc.Usage = D3D11_USAGE_DEFAULT;
    vertex_buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertex_buf_desc.CPUAccessFlags = 0;
    vertex_buf_desc.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA init_vertex_data;
    init_vertex_data.pSysMem = &vertex_buffer[0];
    dxCtr->m_pDevice->CreateBuffer(&vertex_buf_desc, &init_vertex_data, &g_Mesh11.m_pVertexBufferArray[g_Mesh11.m_pMeshArray[0].VertexBuffers[0]].pVB11);
    g_Mesh11.m_pVertexBufferArray[g_Mesh11.m_pMeshArray[0].VertexBuffers[0]].StrideBytes = stride_bytes;
    g_Mesh11.m_pVertexBufferArray[g_Mesh11.m_pMeshArray[0].VertexBuffers[0]].SizeBytes = vertexes_size;
    
    //Set Index Buffer array
    g_Mesh11.m_pMeshArray[0].IndexBuffer = 0;
    g_Mesh11.m_pIndexBufferArray = new SDKMESH_INDEX_BUFFER_HEADER;
    g_Mesh11.m_pIndexBufferArray[g_Mesh11.m_pMeshArray[0].IndexBuffer].IndexType = IT_32BIT;
    D3D11_BUFFER_DESC index_buf_desc;
    index_buf_desc.ByteWidth = indexes_size;
    index_buf_desc.Usage = D3D11_USAGE_DEFAULT;
    index_buf_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    index_buf_desc.CPUAccessFlags = 0;
    index_buf_desc.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA init_index_data;
    init_index_data.pSysMem = &index_buffer[0];
    dxCtr->m_pDevice->CreateBuffer(&index_buf_desc, &init_index_data, &g_Mesh11.m_pIndexBufferArray[g_Mesh11.m_pMeshArray[0].IndexBuffer].pIB11);
    g_Mesh11.m_pIndexBufferArray[g_Mesh11.m_pMeshArray[0].IndexBuffer].SizeBytes = indexes_size;
    
    //Set subset
    SDKMESH_SUBSET v_subset;
    v_subset.MaterialID = 0;
    v_subset.PrimitiveType = PT_TRIANGLE_LIST;
    v_subset.IndexCount = index_buffer.size();
    v_subset.VertexCount = vertex_buffer.size();
    v_subset.VertexStart = 0;
    v_subset.IndexStart = 0;
    g_Mesh11.m_pMeshArray[0].pSubsets = new uint32_t;
    g_Mesh11.m_pMeshArray[0].pSubsets[0] = 0;
    g_Mesh11.m_pMeshArray[0].NumSubsets = 1;
    g_Mesh11.m_pSubsetArray = new SDKMESH_SUBSET;
    g_Mesh11.m_pSubsetArray[g_Mesh11.m_pMeshArray[0].pSubsets[0]] = v_subset;
    

其他信息:

  1. 我尝试使用低多边形数模型,但问题仍然存在,因此我没有达到顶点的某些限制。

  2. 这是数组的大小

attrib.vertices.size = 150201

attrib.normals.size = 173712

attrib.normals.size = 135956

shapes[0].mesh.indices.size() = 300978

  • 在上述示例的方法1中

temp_vertices.size() = 300978(与索引大小匹配,因此在temp_vertices中我没有丢失任何顶点)

vertex_buffer.size() = index_buffer.size() = 2708802

  • 在以上示例的方法2中

vertex_buffer.size() = index_buffer.size() = 450603

  1. 这是输入布局

    // Create our vertex input layout
    const 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 },
        { "TEXCOORD",  0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
    
  2. 这里是顶点着色器

        cbuffer cbPerObject : register( b0 )
    {
        matrix      g_mWorldViewProjection  : packoffset( c0 );
        matrix      g_mWorld                : packoffset( c4 );
    };
    
    //--------------------------------------------------------------------------------------
    // Input / Output structures
    //--------------------------------------------------------------------------------------
    struct VS_INPUT
    {
        float4 vPosition    : POSITION;
        float3 vNormal      : NORMAL;
        float2 vTexcoord    : TEXCOORD0;
    };
    
    struct VS_OUTPUT
    {
        float3 vNormal      : NORMAL;
        float2 vTexcoord    : TEXCOORD0;
        float4 vPosition    : SV_POSITION;
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex Shader
    //--------------------------------------------------------------------------------------
    VS_OUTPUT VSMain( VS_INPUT Input )
    {
        VS_OUTPUT Output;
    
        Output.vPosition = mul( Input.vPosition, g_mWorldViewProjection );
        Output.vNormal = mul( Input.vNormal, (float3x3)g_mWorld );
        Output.vTexcoord = Input.vTexcoord;
    
        return Output;
    }
    
  3. 我意识到输入布局,着色器和我的vertex_buffer矢量之间存在不一致。输入布局主要是32个字节,我的缓冲区是36个字节,其中texcoord是3个字节,着色器是36个字节,但是位置是4个字节,而texcoords是2个字节。

着色器和初始化来自DXUT,而我对此并没有感到困惑。它正确绘制了提供的Tiny.sdkmesh模型,该模型的步幅为32字节,与输入布局的步幅匹配。

如果有人可以帮助解释为什么着色器VS_INPUT与输入布局不同,那么它也将大有帮助。

将顶点着色器更改为数学输入布局会导致编译错误。更改输入布局以向texcoord添加一个额外的字节并没有真正的作用。

注意:我尝试从末端移除vertex_buffer.push_back(0.0F);index_buffer.push_back(0);并将stride_bytes更改为32,但是它不再正确绘制顶点。

我已经用尽了反复试验的方法来测试并寻求帮助,以弄清我在做什么错。

谢谢

1 个答案:

答案 0 :(得分:0)

解剖了可工作的tiny.sdkmesh文件后,我发现我做错了。

每个顶点索引只有1个条目/字节(即32个字节)

我之前尝试过,但是没有成功,这是工作代码:

仍在寻找解释以帮助理解Input_Layout与Vertex Shader为什么字节数不同的原因

    std::vector<float> vertex_buffer;
    std::vector<uint32_t> index_buffer;

    struct T_Vertex
    {
        float vX;
        float vY;
        float vZ;
        float nX;
        float nY;
        float nZ;
        float tX;
        float tY;

        uint32_t vIndex;
    };

    std::vector<T_Vertex> temp_vertices;
    size_t index_offset = 0;
    int ind = 0;
    for (size_t f = 0; f < shapes[0].mesh.num_face_vertices.size(); f++) {
        int fv = shapes[0].mesh.num_face_vertices[f];
        // Loop over vertices in the face.
        for (size_t v = 0; v < fv; v++) {

            // access to vertex
            tinyobj::index_t idx = shapes[0].mesh.indices[index_offset + v];
            if (idx.vertex_index < 0 || idx.normal_index < 0 || idx.texcoord_index < 0)
                continue;
            T_Vertex temp_vertex;
            temp_vertex.vX = idx.normal_index > 0 ? attrib.vertices[3 * idx.vertex_index + 0] : 0;
            temp_vertex.vY = idx.normal_index > 0 ? attrib.vertices[3 * idx.vertex_index + 1] : 0;
            temp_vertex.vZ = idx.normal_index > 0 ? attrib.vertices[3 * idx.vertex_index + 2] : 0;
            temp_vertex.nX = idx.normal_index > 0 ? attrib.normals[3 * idx.normal_index + 0] : 0;
            temp_vertex.nY = idx.normal_index > 0 ? attrib.normals[3 * idx.normal_index + 1] : 0;
            temp_vertex.nZ = idx.normal_index > 0 ? attrib.normals[3 * idx.normal_index + 2] : 0;
            temp_vertex.tX = idx.texcoord_index > 0 ? attrib.texcoords[2 * idx.texcoord_index + 0] : 0;
            temp_vertex.tY = idx.texcoord_index > 0 ? attrib.texcoords[2 * idx.texcoord_index + 1] : 0;

            temp_vertices.push_back(temp_vertex);
            temp_vertex.vIndex = ++ind;
        }
        index_offset += fv;
    }

    for (auto& temp_vertex : temp_vertices)
    {
        vertex_buffer.push_back(temp_vertex.vX);
        vertex_buffer.push_back(temp_vertex.vY);
        vertex_buffer.push_back(temp_vertex.vZ);
        vertex_buffer.push_back(temp_vertex.nX);
        vertex_buffer.push_back(temp_vertex.nY);
        vertex_buffer.push_back(temp_vertex.nZ);
        vertex_buffer.push_back(temp_vertex.tX); //Set to 0 for no texture
        vertex_buffer.push_back(temp_vertex.tY); //Set to 0 for no texture

        index_buffer.push_back(temp_vertex.vIndex);
    }

    uint32_t vertexes_size = vertex_buffer.size() * sizeof(float);
    uint32_t indexes_size = index_buffer.size() * sizeof(uint32_t);
    int stride_bytes = 32;