index buffer generation using final vertex data (#1816)

This results a smaller output file for some meshes.
This commit is contained in:
attilaz 2019-07-13 18:07:33 +02:00 committed by Бранимир Караџић
parent 45fb76865e
commit 72d0a0c4fa
8 changed files with 105 additions and 91 deletions

Binary file not shown.

View File

@ -11,8 +11,6 @@
#include <tinystl/allocator.h> #include <tinystl/allocator.h>
#include <tinystl/string.h> #include <tinystl/string.h>
#include <tinystl/unordered_map.h>
#include <tinystl/unordered_set.h>
#include <tinystl/vector.h> #include <tinystl/vector.h>
namespace stl = tinystl; namespace stl = tinystl;
@ -63,15 +61,12 @@ struct Index3
int32_t m_position; int32_t m_position;
int32_t m_texcoord; int32_t m_texcoord;
int32_t m_normal; int32_t m_normal;
int32_t m_vertexIndex;
int32_t m_vbc; // Barycentric ID. Holds eigher 0, 1 or 2. int32_t m_vbc; // Barycentric ID. Holds eigher 0, 1 or 2.
}; };
typedef stl::unordered_map<uint64_t, Index3> Index3Map;
struct TriIndices struct TriIndices
{ {
uint64_t m_index[3]; Index3 m_index[3];
}; };
typedef stl::vector<TriIndices> TriangleArray; typedef stl::vector<TriIndices> TriangleArray;
@ -498,7 +493,6 @@ int main(int _argc, const char* _argv[])
Vec3Array positions; Vec3Array positions;
Vec3Array normals; Vec3Array normals;
Vec3Array texcoords; Vec3Array texcoords;
Index3Map indexMap;
TriangleArray triangles; TriangleArray triangles;
GroupArray groups; GroupArray groups;
@ -539,7 +533,6 @@ int main(int _argc, const char* _argv[])
Index3 index; Index3 index;
index.m_texcoord = -1; index.m_texcoord = -1;
index.m_normal = -1; index.m_normal = -1;
index.m_vertexIndex = -1;
if (hasBc) if (hasBc)
{ {
index.m_vbc = edge < 3 ? edge : (1+(edge+1) )&1; index.m_vbc = edge < 3 ? edge : (1+(edge+1) )&1;
@ -583,29 +576,10 @@ int main(int _argc, const char* _argv[])
index.m_position = (pos < 0) ? pos + numPositions : pos - 1; index.m_position = (pos < 0) ? pos + numPositions : pos - 1;
} }
const uint64_t hash0 = uint64_t(index.m_position)<< 0;
const uint64_t hash1 = uint64_t(index.m_texcoord)<<20;
const uint64_t hash2 = uint64_t(index.m_normal )<<40;
const uint64_t hash3 = uint64_t(index.m_vbc )<<60;
const uint64_t hash = hash0^hash1^hash2^hash3;
stl::pair<Index3Map::iterator, bool> result = indexMap.insert(stl::make_pair(hash, index) );
if (!result.second)
{
Index3& oldIndex = result.first->second;
BX_UNUSED(oldIndex);
BX_CHECK(true
&& oldIndex.m_position == index.m_position
&& oldIndex.m_texcoord == index.m_texcoord
&& oldIndex.m_normal == index.m_normal
, "Hash collision!"
);
}
switch (edge) switch (edge)
{ {
case 0: case 1: case 2: case 0: case 1: case 2:
triangle.m_index[edge] = hash; triangle.m_index[edge] = index;
if (2 == edge) if (2 == edge)
{ {
if (ccw) if (ccw)
@ -620,12 +594,12 @@ int main(int _argc, const char* _argv[])
if (ccw) if (ccw)
{ {
triangle.m_index[2] = triangle.m_index[1]; triangle.m_index[2] = triangle.m_index[1];
triangle.m_index[1] = hash; triangle.m_index[1] = index;
} }
else else
{ {
triangle.m_index[1] = triangle.m_index[2]; triangle.m_index[1] = triangle.m_index[2];
triangle.m_index[2] = hash; triangle.m_index[2] = index;
} }
triangles.push_back(triangle); triangles.push_back(triangle);
@ -770,38 +744,50 @@ int main(int _argc, const char* _argv[])
bool hasNormal; bool hasNormal;
bool hasTexcoord; bool hasTexcoord;
{ {
Index3Map::const_iterator it = indexMap.begin(); TriangleArray::const_iterator it = triangles.begin();
hasNormal = -1 != it->second.m_normal; hasNormal = -1 != it->m_index[0].m_normal;
hasTexcoord = -1 != it->second.m_texcoord; hasTexcoord = -1 != it->m_index[0].m_texcoord;
if (!hasTexcoord) if (!hasTexcoord)
{ {
for (Index3Map::iterator jt = indexMap.begin(), jtEnd = indexMap.end(); jt != jtEnd && !hasTexcoord; ++jt) for (TriangleArray::iterator jt = triangles.begin(), jtEnd = triangles.end(); jt != jtEnd && !hasTexcoord; ++jt)
{ {
hasTexcoord |= -1 != jt->second.m_texcoord; for (uint32_t i = 0; i < 3; ++i)
{
hasTexcoord |= -1 != jt->m_index[i].m_texcoord;
}
} }
if (hasTexcoord) if (hasTexcoord)
{ {
for (Index3Map::iterator jt = indexMap.begin(), jtEnd = indexMap.end(); jt != jtEnd; ++jt) for (TriangleArray::iterator jt = triangles.begin(), jtEnd = triangles.end(); jt != jtEnd; ++jt)
{ {
jt->second.m_texcoord = -1 == jt->second.m_texcoord ? 0 : jt->second.m_texcoord; for (uint32_t i = 0; i < 3; ++i)
{
jt->m_index[i].m_texcoord = -1 == jt->m_index[i].m_texcoord ? 0 : jt->m_index[i].m_texcoord;
}
} }
} }
} }
if (!hasNormal) if (!hasNormal)
{ {
for (Index3Map::iterator jt = indexMap.begin(), jtEnd = indexMap.end(); jt != jtEnd && !hasNormal; ++jt) for (TriangleArray::iterator jt = triangles.begin(), jtEnd = triangles.end(); jt != jtEnd && !hasNormal; ++jt)
{ {
hasNormal |= -1 != jt->second.m_normal; for (uint32_t i = 0; i < 3; ++i)
{
hasNormal |= -1 != jt->m_index[i].m_normal;
}
} }
if (hasNormal) if (hasNormal)
{ {
for (Index3Map::iterator jt = indexMap.begin(), jtEnd = indexMap.end(); jt != jtEnd; ++jt) for (TriangleArray::iterator jt = triangles.begin(), jtEnd = triangles.end(); jt != jtEnd; ++jt)
{ {
jt->second.m_normal = -1 == jt->second.m_normal ? 0 : jt->second.m_normal; for (uint32_t i = 0; i < 3; ++i)
{
jt->m_index[i].m_normal = -1 == jt->m_index[i].m_normal ? 0 : jt->m_index[i].m_normal;
}
} }
} }
} }
@ -875,7 +861,12 @@ int main(int _argc, const char* _argv[])
uint8_t* vertices = vertexData; uint8_t* vertices = vertexData;
uint16_t* indices = indexData; uint16_t* indices = indexData;
const uint32_t tableSize = 65536 * 2;
const uint32_t hashmod = tableSize - 1;
uint32_t* table = new uint32_t[tableSize];
bx::memSet(table, 0xff, tableSize * sizeof(uint32_t));
stl::string material = groups.begin()->m_material; stl::string material = groups.begin()->m_material;
PrimitiveArray primitives; PrimitiveArray primitives;
@ -942,11 +933,8 @@ int main(int _argc, const char* _argv[])
, primitives , primitives
); );
primitives.clear(); primitives.clear();
for (Index3Map::iterator indexIt = indexMap.begin(); indexIt != indexMap.end(); ++indexIt) bx::memSet(table, 0xff, tableSize * sizeof(uint32_t));
{
indexIt->second.m_vertexIndex = -1;
}
++writtenPrimitives; ++writtenPrimitives;
writtenVertices += numVertices; writtenVertices += numVertices;
@ -968,56 +956,81 @@ int main(int _argc, const char* _argv[])
TriIndices& triangle = triangles[tri]; TriIndices& triangle = triangles[tri];
for (uint32_t edge = 0; edge < 3; ++edge) for (uint32_t edge = 0; edge < 3; ++edge)
{ {
uint64_t hash = triangle.m_index[edge]; Index3& index = triangle.m_index[edge];
Index3& index = indexMap[hash];
if (index.m_vertexIndex == -1) float* position = (float*)(vertices + positionOffset);
bx::memCopy(position, &positions[index.m_position], 3*sizeof(float) );
if (hasColor)
{ {
index.m_vertexIndex = numVertices++; uint32_t* color0 = (uint32_t*)(vertices + color0Offset);
*color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff);
float* position = (float*)(vertices + positionOffset); }
bx::memCopy(position, &positions[index.m_position], 3*sizeof(float) );
if (hasBc)
if (hasColor) {
const float bc[3] =
{ {
uint32_t* color0 = (uint32_t*)(vertices + color0Offset); (index.m_vbc == 0) ? 1.0f : 0.0f,
*color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff); (index.m_vbc == 1) ? 1.0f : 0.0f,
} (index.m_vbc == 2) ? 1.0f : 0.0f,
};
if (hasBc) bgfx::vertexPack(bc, true, bgfx::Attrib::Color1, decl, vertices);
}
if (hasTexcoord)
{
float uv[2];
bx::memCopy(uv, &texcoords[index.m_texcoord], 2*sizeof(float) );
if (flipV)
{ {
const float bc[3] = uv[1] = -uv[1];
{
(index.m_vbc == 0) ? 1.0f : 0.0f,
(index.m_vbc == 1) ? 1.0f : 0.0f,
(index.m_vbc == 2) ? 1.0f : 0.0f,
};
bgfx::vertexPack(bc, true, bgfx::Attrib::Color1, decl, vertices);
} }
if (hasTexcoord) bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
{ }
float uv[2];
bx::memCopy(uv, &texcoords[index.m_texcoord], 2*sizeof(float) ); if (hasNormal)
{
if (flipV) float normal[4];
{ bx::store(normal, bx::normalize(bx::load<bx::Vec3>(&normals[index.m_normal]) ) );
uv[1] = -uv[1]; normal[3] = 0.0f;
} bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
}
if (hasNormal)
{
float normal[4];
bx::store(normal, bx::normalize(bx::load<bx::Vec3>(&normals[index.m_normal]) ) );
bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
}
vertices += stride;
} }
*indices++ = (uint16_t)index.m_vertexIndex; uint32_t hash = bx::hash<bx::HashMurmur2A>(vertices, stride);
size_t bucket = hash & hashmod;
uint32_t vertexIndex = UINT32_MAX;
for (size_t probe = 0; probe <= hashmod; ++probe)
{
uint32_t& item = table[bucket];
if (item == ~0u)
{
vertices += stride;
item = numVertices++;
vertexIndex = item;
break;
}
if (0 == bx::memCmp(vertexData + item * stride, vertices, stride))
{
vertexIndex = item;
break;
}
bucket = (bucket + probe + 1) & hashmod;
}
if ( vertexIndex == UINT32_MAX )
{
bx::printf("hash table insert failed");
exit(bx::kExitFailure);
}
*indices++ = (uint16_t)vertexIndex;
++numIndices; ++numIndices;
} }
} }
@ -1045,6 +1058,7 @@ int main(int _argc, const char* _argv[])
bx::printf("size: %d\n", uint32_t(bx::seek(&writer) ) ); bx::printf("size: %d\n", uint32_t(bx::seek(&writer) ) );
bx::close(&writer); bx::close(&writer);
delete [] table;
delete [] indexData; delete [] indexData;
delete [] vertexData; delete [] vertexData;