我有一个似乎无法解决的问题。
我使用TinyObjLoader导入obj文件,并将顶点和索引缓冲区复制到GPU内存以绘制模型。此模型中只有个三角形。没有4+边的多边形,也没有负索引
唯一的问题是我无法绘制完整模型,只能绘制具有正确顶点,正确法线和正确纹理的顶点的1/2到2/3。
我使用#defines将代码分成两种方法来说明此问题。 请注意,要想使它起作用,需要大量的反复试验,因为DirectX11上在线缺乏教程和教育。如果您发现代码的结构方式有任何问题,请随时发表评论。
方法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有效(减去纹理),但是没有重复的顶点,因此法线方向不利于渲染。但是,在此配置中,每个单个顶点都绘制在正确的位置。请注意,这两个代码的步幅,顶点和索引缓冲区结构相同,缓冲区的大小不同。
#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
这是我创建缓冲区的地方,两种方法的代码相同
//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;
其他信息:
我尝试使用低多边形数模型,但问题仍然存在,因此我没有达到顶点的某些限制。
这是数组的大小
attrib.vertices.size = 150201
attrib.normals.size = 173712
attrib.normals.size = 135956
shapes[0].mesh.indices.size() = 300978
temp_vertices.size() = 300978
(与索引大小匹配,因此在temp_vertices
中我没有丢失任何顶点)
vertex_buffer.size() = index_buffer.size() = 2708802
vertex_buffer.size() = index_buffer.size() = 450603
这是输入布局
// 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 },
};
这里是顶点着色器
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;
}
我意识到输入布局,着色器和我的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,但是它不再正确绘制顶点。
我已经用尽了反复试验的方法来测试并寻求帮助,以弄清我在做什么错。
谢谢
答案 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;