Procházet zdrojové kódy

using meshoptimizer for vertex cache/fetch optim and index/vertex buffer compression

attilaz před 6 roky
rodič
revize
ed885c3c5a

+ 8 - 8
examples/assets/meshes/meshes.ninja

@@ -1,18 +1,18 @@
 meshes = $pwd/../../runtime/meshes
 
 build $meshes/bunny.bin:           geometryc_pack_normal_barycentric $pwd/bunny.obj
-build $meshes/bunny_decimated.bin: geometryc_pack_normal             $pwd/bunny_decimated.obj
+build $meshes/bunny_decimated.bin: geometryc_pack_normal_compressed  $pwd/bunny_decimated.obj
 build $meshes/bunny_patched.bin:   geometryc_pack_normal             $pwd/bunny_patched.obj
 build $meshes/column.bin:          geometryc_pack_normal             $pwd/column.obj
 build $meshes/cube.bin:            geometryc_pack_normal             $pwd/cube.obj
 build $meshes/hollowcube.bin:      geometryc_pack_normal_barycentric $pwd/hollowcube.obj
 build $meshes/orb.bin:             geometryc_pack_normal_barycentric $pwd/orb.obj
 build $meshes/platform.bin:        geometryc_pack_normal             $pwd/platform.obj
-build $meshes/tree.bin:            geometryc_pack_normal             $pwd/tree.obj
-build $meshes/tree1b_lod0_1.bin:   geometryc_pack_normal             $pwd/tree1b_lod0_1.obj
-build $meshes/tree1b_lod0_2.bin:   geometryc_pack_normal             $pwd/tree1b_lod0_2.obj
-build $meshes/tree1b_lod1_1.bin:   geometryc_pack_normal             $pwd/tree1b_lod1_1.obj
-build $meshes/tree1b_lod1_2.bin:   geometryc_pack_normal             $pwd/tree1b_lod1_2.obj
-build $meshes/tree1b_lod2_1.bin:   geometryc_pack_normal             $pwd/tree1b_lod2_1.obj
-build $meshes/tree1b_lod2_2.bin:   geometryc_pack_normal             $pwd/tree1b_lod2_2.obj
+build $meshes/tree.bin:            geometryc_pack_normal_compressed  $pwd/tree.obj
+build $meshes/tree1b_lod0_1.bin:   geometryc_pack_normal_compressed  $pwd/tree1b_lod0_1.obj
+build $meshes/tree1b_lod0_2.bin:   geometryc_pack_normal_compressed  $pwd/tree1b_lod0_2.obj
+build $meshes/tree1b_lod1_1.bin:   geometryc_pack_normal_compressed  $pwd/tree1b_lod1_1.obj
+build $meshes/tree1b_lod1_2.bin:   geometryc_pack_normal_compressed  $pwd/tree1b_lod1_2.obj
+build $meshes/tree1b_lod2_1.bin:   geometryc_pack_normal_compressed  $pwd/tree1b_lod2_1.obj
+build $meshes/tree1b_lod2_2.bin:   geometryc_pack_normal_compressed  $pwd/tree1b_lod2_2.obj
 build $meshes/test_scene.bin:      geometryc_pack_normal             $pwd/../sky/test_scene.obj

+ 32 - 4
examples/common/bgfx_utils.cpp

@@ -17,7 +17,7 @@ namespace stl = tinystl;
 #include <bx/readerwriter.h>
 #include <bx/string.h>
 #include "entry/entry.h"
-#include <ib-compress/indexbufferdecompression.h>
+#include <meshoptimizer/src/meshoptimizer.h>
 
 #include "bgfx_utils.h"
 
@@ -418,8 +418,9 @@ struct Mesh
 	void load(bx::ReaderSeekerI* _reader)
 	{
 #define BGFX_CHUNK_MAGIC_VB  BX_MAKEFOURCC('V', 'B', ' ', 0x1)
+#define BGFX_CHUNK_MAGIC_VBC BX_MAKEFOURCC('V', 'B', 'C', 0x0)
 #define BGFX_CHUNK_MAGIC_IB  BX_MAKEFOURCC('I', 'B', ' ', 0x0)
-#define BGFX_CHUNK_MAGIC_IBC BX_MAKEFOURCC('I', 'B', 'C', 0x0)
+#define BGFX_CHUNK_MAGIC_IBC BX_MAKEFOURCC('I', 'B', 'C', 0x1)
 #define BGFX_CHUNK_MAGIC_PRI BX_MAKEFOURCC('P', 'R', 'I', 0x0)
 
 		using namespace bx;
@@ -454,6 +455,34 @@ struct Mesh
 					group.m_vbh = bgfx::createVertexBuffer(mem, m_decl);
 				}
 				break;
+			case BGFX_CHUNK_MAGIC_VBC:
+				{
+					read(_reader, group.m_sphere);
+					read(_reader, group.m_aabb);
+					read(_reader, group.m_obb);
+
+					read(_reader, m_decl);
+
+					uint16_t stride = m_decl.getStride();
+
+					uint16_t numVertices;
+					read(_reader, numVertices);
+
+					const bgfx::Memory* mem = bgfx::alloc(numVertices*stride);
+
+					uint32_t compressedSize;
+					bx::read(_reader, compressedSize);
+
+					void* compressedVertices = BX_ALLOC(allocator, compressedSize);
+					bx::read(_reader, compressedVertices, compressedSize);
+
+					meshopt_decodeVertexBuffer(mem->data, numVertices, stride, (uint8_t*)compressedVertices, compressedSize);
+
+					BX_FREE(allocator, compressedVertices);
+
+					group.m_vbh = bgfx::createVertexBuffer(mem, m_decl);
+				}
+				break;
 
 			case BGFX_CHUNK_MAGIC_IB:
 				{
@@ -479,8 +508,7 @@ struct Mesh
 
 					bx::read(_reader, compressedIndices, compressedSize);
 
-					ReadBitstream rbs( (const uint8_t*)compressedIndices, compressedSize);
-					DecompressIndexBuffer( (uint16_t*)mem->data, numIndices / 3, rbs);
+					meshopt_decodeIndexBuffer(mem->data, numIndices, 2, (uint8_t*)compressedIndices, compressedSize);
 
 					BX_FREE(allocator, compressedIndices);
 

binární
examples/runtime/meshes/bunny.bin


binární
examples/runtime/meshes/bunny_patched.bin


binární
examples/runtime/meshes/column.bin


binární
examples/runtime/meshes/hollowcube.bin


binární
examples/runtime/meshes/orb.bin


binární
examples/runtime/meshes/platform.bin


binární
examples/runtime/meshes/test_scene.bin


binární
examples/runtime/meshes/tree1b_lod0_1.bin


binární
examples/runtime/meshes/tree1b_lod0_2.bin


binární
examples/runtime/meshes/tree1b_lod1_1.bin


binární
examples/runtime/meshes/tree1b_lod1_2.bin


binární
examples/runtime/meshes/tree1b_lod2_1.bin


binární
examples/runtime/meshes/tree1b_lod2_2.bin


+ 4 - 0
scripts/build.ninja

@@ -4,6 +4,10 @@ rule geometryc_pack_normal
     command = geometryc -f $in -o $out --packnormal 1
     description = Converting geometry $in...
 
+rule geometryc_pack_normal_compressed
+    command = geometryc -f $in -o $out --packnormal 1 -c
+    description = Converting geometry $in...
+
 rule geometryc_pack_normal_barycentric
     command = geometryc -f $in -o $out --packnormal 1 --barycentric
     description = Converting geometry $in...

+ 2 - 2
scripts/example-common.lua

@@ -28,8 +28,8 @@ project ("example-common")
 	}
 
 	files {
-		path.join(BGFX_DIR, "3rdparty/ib-compress/**.cpp"),
-		path.join(BGFX_DIR, "3rdparty/ib-compress/**.h"),
+		path.join(BGFX_DIR, "3rdparty/meshoptimizer/src/**.cpp"),
+		path.join(BGFX_DIR, "3rdparty/meshoptimizer/src/**.h"),
 		path.join(BGFX_DIR, "3rdparty/dear-imgui/**.cpp"),
 		path.join(BGFX_DIR, "3rdparty/dear-imgui/**.h"),
 		path.join(BGFX_DIR, "examples/common/**.cpp"),

+ 2 - 4
scripts/geometryc.lua

@@ -15,10 +15,8 @@ project "geometryc"
 	}
 
 	files {
-		path.join(BGFX_DIR, "3rdparty/forsyth-too/**.cpp"),
-		path.join(BGFX_DIR, "3rdparty/forsyth-too/**.h"),
-		path.join(BGFX_DIR, "3rdparty/ib-compress/**.cpp"),
-		path.join(BGFX_DIR, "3rdparty/ib-compress/**.h"),
+		path.join(BGFX_DIR, "3rdparty/meshoptimizer/src/**.cpp"),
+		path.join(BGFX_DIR, "3rdparty/meshoptimizer/src/**.h"),
 		path.join(BGFX_DIR, "src/vertexdecl.**"),
 		path.join(BGFX_DIR, "tools/geometryc/**.cpp"),
 		path.join(BGFX_DIR, "tools/geometryc/**.h"),

+ 90 - 102
tools/geometryc/geometryc.cpp

@@ -18,8 +18,7 @@
 #include <tinystl/string.h>
 namespace stl = tinystl;
 
-#include <forsyth-too/forsythtriangleorderoptimizer.h>
-#include <ib-compress/indexbuffercompression.h>
+#include <meshoptimizer/src/meshoptimizer.h>
 
 #define BGFX_GEOMETRYC_VERSION_MAJOR 1
 #define BGFX_GEOMETRYC_VERSION_MINOR 0
@@ -103,8 +102,9 @@ typedef std::vector<Primitive> PrimitiveArray;
 static uint32_t s_obbSteps = 17;
 
 #define BGFX_CHUNK_MAGIC_VB  BX_MAKEFOURCC('V', 'B', ' ', 0x1)
+#define BGFX_CHUNK_MAGIC_VBC BX_MAKEFOURCC('V', 'B', 'C', 0x0)
 #define BGFX_CHUNK_MAGIC_IB  BX_MAKEFOURCC('I', 'B', ' ', 0x0)
-#define BGFX_CHUNK_MAGIC_IBC BX_MAKEFOURCC('I', 'B', 'C', 0x0)
+#define BGFX_CHUNK_MAGIC_IBC BX_MAKEFOURCC('I', 'B', 'C', 0x1)
 #define BGFX_CHUNK_MAGIC_PRI BX_MAKEFOURCC('P', 'R', 'I', 0x0)
 
 long int fsize(FILE* _file)
@@ -116,41 +116,54 @@ long int fsize(FILE* _file)
 	return size;
 }
 
-void triangleReorder(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices, uint16_t _cacheSize)
+void optimizeVertexCache(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices)
 {
 	uint16_t* newIndexList = new uint16_t[_numIndices];
-	Forsyth::OptimizeFaces(_indices, _numIndices, _numVertices, 0, newIndexList, _cacheSize);
-	bx::memCopy(_indices, newIndexList, _numIndices*2);
-	delete [] newIndexList;
+	meshopt_optimizeVertexCache(newIndexList, _indices, _numIndices, _numVertices);
+	bx::memCopy(_indices, newIndexList, _numIndices * 2);
+	delete[] newIndexList;
 }
 
-void triangleCompress(bx::WriterI* _writer, uint16_t* _indices, uint32_t _numIndices, uint8_t* _vertexData, uint32_t _numVertices, uint16_t _stride)
+uint32_t optimizeVertexFetch(uint16_t* _indices, uint32_t _numIndices, uint8_t* _vertexData, uint32_t _numVertices, uint16_t _stride)
 {
-	uint32_t* vertexRemap = (uint32_t*)malloc(_numVertices*sizeof(uint32_t) );
+	unsigned char* newVertices = (unsigned char*)malloc(_numVertices * _stride );
+	size_t vertexCount = meshopt_optimizeVertexFetch(newVertices, _indices, _numIndices, _vertexData, _numVertices, _stride);
+	bx::memCopy(_vertexData, newVertices, _numVertices * _stride);
+	free(newVertices);
 
-	WriteBitstream writer;
-	CompressIndexBuffer(_indices, _numIndices/3, vertexRemap, _numVertices, IBCF_AUTO, writer);
-	writer.Finish();
-	printf( "uncompressed: %10d, compressed: %10d, ratio: %0.2f%%\n"
-		, _numIndices*2
-		, (uint32_t)writer.ByteSize()
-		, 100.0f - float(writer.ByteSize() ) / float(_numIndices*2)*100.0f
-		);
+	return uint32_t(vertexCount);
+}
 
-	BX_UNUSED(_vertexData, _stride);
-	uint8_t* outVertexData = (uint8_t*)malloc(_numVertices*_stride);
-	for (uint32_t ii = 0; ii < _numVertices; ++ii)
-	{
-		uint32_t remap = vertexRemap[ii];
-		remap = UINT32_MAX == remap ? ii : remap;
-		bx::memCopy(&outVertexData[remap*_stride], &_vertexData[ii*_stride], _stride);
-	}
-	bx::memCopy(_vertexData, outVertexData, _numVertices*_stride);
-	free(outVertexData);
+void writeCompressedIndices(bx::WriterI* _writer, const uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices)
+{
+	size_t maxSize = meshopt_encodeIndexBufferBound(_numIndices, _numVertices);
+	unsigned char* compressedIndices = (unsigned char*)malloc(maxSize);
+	size_t compressedSize = meshopt_encodeIndexBuffer(compressedIndices, maxSize, _indices, _numIndices);
+	printf( "indices uncompressed: %10d, compressed: %10d, ratio: %0.2f%%\n"
+		, _numIndices*2
+		, (uint32_t)compressedSize
+		, 100.0f - float(compressedSize ) / float(_numIndices*2)*100.0f
+	);
 
-	free(vertexRemap);
+	bx::write(_writer, (uint32_t)compressedSize);
+	bx::write(_writer, compressedIndices, (uint32_t)compressedSize );
+	free(compressedIndices);
+}
 
-	bx::write(_writer, writer.RawData(), (uint32_t)writer.ByteSize() );
+void writeCompressedVertices(bx::WriterI* _writer,  const uint8_t* _vertices, uint32_t _numVertices, uint16_t _stride)
+{
+	size_t maxSize = meshopt_encodeVertexBufferBound(_numVertices, _stride);
+	unsigned char* compressedVertices = (unsigned char*)malloc(maxSize);
+	size_t compressedSize = meshopt_encodeVertexBuffer(compressedVertices, maxSize, _vertices, _numVertices, _stride);
+	printf("vertices uncompressed: %10d, compressed: %10d, ratio: %0.2f%%\n"
+		, _numVertices * _stride
+		, (uint32_t)compressedSize
+		, 100.0f - float(compressedSize) / float(_numVertices * _stride)*100.0f
+	);
+
+	bx::write(_writer, (uint32_t)compressedSize);
+	bx::write(_writer, compressedVertices, (uint32_t)compressedSize );
+	free(compressedVertices);
 }
 
 void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices)
@@ -282,8 +295,7 @@ void write(bx::WriterI* _writer
 		, const bgfx::VertexDecl& _decl
 		, const uint16_t* _indices
 		, uint32_t _numIndices
-		, const uint8_t* _compressedIndices
-		, uint32_t _compressedSize
+		, bool _compress
 		, const stl::string& _material
 		, const PrimitiveArray& _primitives
 		)
@@ -292,20 +304,33 @@ void write(bx::WriterI* _writer
 	using namespace bgfx;
 
 	uint32_t stride = _decl.getStride();
-	write(_writer, BGFX_CHUNK_MAGIC_VB);
-	write(_writer, _vertices, _numVertices, stride);
 
-	write(_writer, _decl);
+	if (_compress)
+	{
+		write(_writer, BGFX_CHUNK_MAGIC_VBC);
+		write(_writer, _vertices, _numVertices, stride);
+
+		write(_writer, _decl);
+
+		write(_writer, uint16_t(_numVertices) );
+		writeCompressedVertices(_writer, _vertices, _numVertices, uint16_t(stride));
+	}
+	else
+	{
+		write(_writer, BGFX_CHUNK_MAGIC_VB);
+		write(_writer, _vertices, _numVertices, stride);
+
+		write(_writer, _decl);
 
-	write(_writer, uint16_t(_numVertices) );
-	write(_writer, _vertices, _numVertices*stride);
+		write(_writer, uint16_t(_numVertices) );
+		write(_writer, _vertices, _numVertices*stride);
+	}
 
-	if (NULL != _compressedIndices)
+	if (_compress)
 	{
 		write(_writer, BGFX_CHUNK_MAGIC_IBC);
 		write(_writer, _numIndices);
-		write(_writer, _compressedSize);
-		write(_writer, _compressedIndices, _compressedSize);
+		writeCompressedIndices(_writer, _indices, _numIndices, _numVertices);
 	}
 	else
 	{
@@ -682,7 +707,7 @@ int main(int _argc, const char* _argv[])
 					bx::fromString(&py, argv[2]);
 					bx::fromString(&pz, argv[3]);
 
-					if (argc > 4)
+					if (argc == 5 || argc == 8)
 					{
 						bx::fromString(&pw, argv[4]);
 					}
@@ -854,7 +879,10 @@ int main(int _argc, const char* _argv[])
 	uint16_t* indexData = new uint16_t[triangles.size() * 3];
 	int32_t numVertices = 0;
 	int32_t numIndices = 0;
-	int32_t numPrimitives = 0;
+
+	int32_t writtenPrimitives = 0;
+	int32_t writtenVertices = 0;
+	int32_t writtenIndices = 0;
 
 	uint8_t* vertices = vertexData;
 	uint16_t* indices = indexData;
@@ -877,15 +905,19 @@ int main(int _argc, const char* _argv[])
 	uint32_t positionOffset = decl.getOffset(bgfx::Attrib::Position);
 	uint32_t color0Offset   = decl.getOffset(bgfx::Attrib::Color0);
 
-	bx::DefaultAllocator crtAllocator;
-	bx::MemoryBlock  memBlock(&crtAllocator);
+	Group sentinelGroup;
+	sentinelGroup.m_startTriangle = 0;
+	sentinelGroup.m_numTriangles = UINT32_MAX;
+	groups.push_back(sentinelGroup);
 
 	uint32_t ii = 0;
 	for (GroupArray::const_iterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt, ++ii)
 	{
+		bool sentinel = groupIt->m_startTriangle == 0 && groupIt->m_numTriangles == UINT32_MAX;
 		for (uint32_t tri = groupIt->m_startTriangle, end = tri + groupIt->m_numTriangles; tri < end; ++tri)
 		{
 			if (0 != bx::strCmp(material.c_str(), groupIt->m_material.c_str() )
+			|| sentinel
 			||  65533 <= numVertices)
 			{
 				prim.m_numVertices = numVertices - prim.m_startVertex;
@@ -900,25 +932,14 @@ int main(int _argc, const char* _argv[])
 					calcTangents(vertexData, uint16_t(numVertices), decl, indexData, numIndices);
 				}
 
-				bx::MemoryWriter memWriter(&memBlock);
-
 				triReorderElapsed -= bx::getHPCounter();
 				for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
 				{
 					const Primitive& prim1 = *primIt;
-					triangleReorder(indexData + prim1.m_startIndex, prim1.m_numIndices, numVertices, 32);
-					if (compress)
-					{
-						triangleCompress(
-							  &memWriter
-							, indexData  + prim1.m_startIndex
-							, prim1.m_numIndices
-							, vertexData + prim1.m_startVertex
-							, numVertices
-							, uint16_t(stride)
-							);
-					}
+					optimizeVertexCache(indexData + prim1.m_startIndex, prim1.m_numIndices, numVertices);
 				}
+				numVertices = optimizeVertexFetch(indexData, numIndices, vertexData, numVertices, uint16_t(stride));
+
 				triReorderElapsed += bx::getHPCounter();
 
 				write(&writer
@@ -927,8 +948,7 @@ int main(int _argc, const char* _argv[])
 					, decl
 					, indexData
 					, numIndices
-					, (uint8_t*)memBlock.more()
-					, memBlock.getSize()
+					, compress
 					, material
 					, primitives
 					);
@@ -939,15 +959,21 @@ int main(int _argc, const char* _argv[])
 					indexIt->second.m_vertexIndex = -1;
 				}
 
+				++writtenPrimitives;
+				writtenVertices += numVertices;
+				writtenIndices += numIndices;
+
 				vertices = vertexData;
 				indices  = indexData;
 				numVertices = 0;
 				numIndices  = 0;
 				prim.m_startVertex = 0;
 				prim.m_startIndex  = 0;
-				++numPrimitives;
 
 				material = groupIt->m_material;
+
+				if (sentinel)
+					break;
 			}
 
 			TriIndices& triangle = triangles[tri];
@@ -1025,45 +1051,7 @@ int main(int _argc, const char* _argv[])
 			);
 	}
 
-	if (0 < primitives.size() )
-	{
-		if (hasTangent)
-		{
-			calcTangents(vertexData, uint16_t(numVertices), decl, indexData, numIndices);
-		}
-
-		bx::MemoryWriter memWriter(&memBlock);
-
-		triReorderElapsed -= bx::getHPCounter();
-		for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
-		{
-			const Primitive& prim1 = *primIt;
-			triangleReorder(indexData + prim1.m_startIndex, prim1.m_numIndices, numVertices, 32);
-			if (compress)
-			{
-				triangleCompress(&memWriter
-					, indexData  + prim1.m_startIndex
-					, prim1.m_numIndices
-					, vertexData + prim1.m_startVertex
-					, numVertices
-					, uint16_t(stride)
-					);
-			}
-		}
-		triReorderElapsed += bx::getHPCounter();
-
-		write(&writer
-			, vertexData
-			, numVertices
-			, decl
-			, indexData
-			, numIndices
-			, (uint8_t*)memBlock.more()
-			, memBlock.getSize()
-			, material
-			, primitives
-			);
-	}
+	BX_CHECK(0 == primitives.size(), "Not all primitives are written");
 
 	printf("size: %d\n", uint32_t(bx::seek(&writer) ) );
 	bx::close(&writer);
@@ -1080,9 +1068,9 @@ int main(int _argc, const char* _argv[])
 		, double(convertElapsed)/bx::getHPFrequency()
 		, num
 		, uint32_t(groups.size() )
-		, numPrimitives
-		, numVertices
-		, numIndices
+		, writtenPrimitives
+		, writtenVertices
+		, writtenIndices
 		);
 
 	return bx::kExitSuccess;