robustify collect_vertex_data some more

This commit is contained in:
David Rose 2005-04-14 03:54:10 +00:00
parent d36604ab05
commit 500f17c091
10 changed files with 133 additions and 58 deletions

View File

@ -47,11 +47,16 @@
PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage"); PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage");
PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active"); PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active");
PStatCollector GraphicsStateGuardian::_texture_count_pcollector("Prepared Textures");
PStatCollector GraphicsStateGuardian::_active_texture_count_pcollector("Prepared Textures:Active");
PStatCollector GraphicsStateGuardian::_total_buffer_count_pcollector("Vertex buffer count");
PStatCollector GraphicsStateGuardian::_active_vertex_buffer_count_pcollector("Vertex buffer count:Active vertex");
PStatCollector GraphicsStateGuardian::_active_index_buffer_count_pcollector("Vertex buffer count:Active index");
PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms"); PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms");
PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active"); PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active");
PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffers"); PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffer size");
PStatCollector GraphicsStateGuardian::_active_vertex_buffers_pcollector("Vertex buffers:Active vertex"); PStatCollector GraphicsStateGuardian::_active_vertex_buffers_pcollector("Vertex buffer size:Active vertex");
PStatCollector GraphicsStateGuardian::_active_index_buffers_pcollector("Vertex buffers:Active index"); PStatCollector GraphicsStateGuardian::_active_index_buffers_pcollector("Vertex buffer size:Active index");
PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes"); PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes");
PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active"); PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active");
PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory"); PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory");
@ -1552,6 +1557,8 @@ init_frame_pstats() {
_active_geom_node_pcollector.clear_level(); _active_geom_node_pcollector.clear_level();
_active_vertex_buffers_pcollector.clear_level(); _active_vertex_buffers_pcollector.clear_level();
_active_index_buffers_pcollector.clear_level(); _active_index_buffers_pcollector.clear_level();
_active_vertex_buffer_count_pcollector.clear_level();
_active_index_buffer_count_pcollector.clear_level();
// Also clear out our other counters while we're here. // Also clear out our other counters while we're here.
_vertices_tristrip_pcollector.clear_level(); _vertices_tristrip_pcollector.clear_level();
@ -1606,8 +1613,8 @@ add_to_geom_record(GeomContext *gc) {
// Access: Protected // Access: Protected
// Description: Records that the indicated data array has been drawn // Description: Records that the indicated data array has been drawn
// this frame. This function is only used to update the // this frame. This function is only used to update the
// PStats active_vertex_buffers collector; it gets compiled out // PStats active_vertex_buffers collector; it gets
// if we aren't using PStats. // compiled out if we aren't using PStats.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian:: void GraphicsStateGuardian::
add_to_vertex_buffer_record(VertexBufferContext *vbc) { add_to_vertex_buffer_record(VertexBufferContext *vbc) {
@ -1617,6 +1624,7 @@ add_to_vertex_buffer_record(VertexBufferContext *vbc) {
if (PStatClient::is_connected()) { if (PStatClient::is_connected()) {
if (_current_vertex_buffers.insert(vbc).second) { if (_current_vertex_buffers.insert(vbc).second) {
_active_vertex_buffers_pcollector.add_level(vbc->get_data()->get_data_size_bytes()); _active_vertex_buffers_pcollector.add_level(vbc->get_data()->get_data_size_bytes());
_active_vertex_buffer_count_pcollector.add_level(1);
} }
} }
} }
@ -1638,6 +1646,7 @@ add_to_index_buffer_record(IndexBufferContext *ibc) {
if (PStatClient::is_connected()) { if (PStatClient::is_connected()) {
if (_current_index_buffers.insert(ibc).second) { if (_current_index_buffers.insert(ibc).second) {
_active_index_buffers_pcollector.add_level(ibc->get_data()->get_data_size_bytes()); _active_index_buffers_pcollector.add_level(ibc->get_data()->get_data_size_bytes());
_active_index_buffer_count_pcollector.add_level(1);
} }
} }
} }

View File

@ -332,6 +332,11 @@ public:
// Statistics // Statistics
static PStatCollector _total_texusage_pcollector; static PStatCollector _total_texusage_pcollector;
static PStatCollector _active_texusage_pcollector; static PStatCollector _active_texusage_pcollector;
static PStatCollector _texture_count_pcollector;
static PStatCollector _active_texture_count_pcollector;
static PStatCollector _total_buffer_count_pcollector;
static PStatCollector _active_vertex_buffer_count_pcollector;
static PStatCollector _active_index_buffer_count_pcollector;
static PStatCollector _total_geom_pcollector; static PStatCollector _total_geom_pcollector;
static PStatCollector _active_geom_pcollector; static PStatCollector _active_geom_pcollector;
static PStatCollector _total_buffers_pcollector; static PStatCollector _total_buffers_pcollector;

View File

@ -46,6 +46,7 @@ load_from_loader(EggLoader &loader) {
SceneGraphReducer gr; SceneGraphReducer gr;
int num_reduced = gr.flatten(loader._root, combine_siblings_bits); int num_reduced = gr.flatten(loader._root, combine_siblings_bits);
// gr.collect_vertex_data(loader._root);
egg2pg_cat.info() << "Flattened " << num_reduced << " nodes.\n"; egg2pg_cat.info() << "Flattened " << num_reduced << " nodes.\n";
} }

View File

@ -27,7 +27,8 @@
#include "mutexHolder.h" #include "mutexHolder.h"
PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage"); PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage");
PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffers"); PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffer size");
PStatCollector PreparedGraphicsObjects::_total_buffer_count_pcollector("Vertex buffer count");
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::Constructor // Function: PreparedGraphicsObjects::Constructor
@ -449,6 +450,7 @@ release_vertex_buffer(VertexBufferContext *vbc) {
vbc->_data->clear_prepared(this); vbc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes()); _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
// We have to set the Data pointer to NULL at this point, since // We have to set the Data pointer to NULL at this point, since
// the Data itself might destruct at any time after it has been // the Data itself might destruct at any time after it has been
@ -482,6 +484,7 @@ release_all_vertex_buffers() {
VertexBufferContext *vbc = (*vbci); VertexBufferContext *vbc = (*vbci);
vbc->_data->clear_prepared(this); vbc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes()); _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
vbc->_data = (qpGeomVertexArrayData *)NULL; vbc->_data = (qpGeomVertexArrayData *)NULL;
_released_vertex_buffers.insert(vbc); _released_vertex_buffers.insert(vbc);
@ -532,6 +535,7 @@ prepare_vertex_buffer_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase
// GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to // GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to
// count it again here. // count it again here.
//_total_buffers_pcollector.add_level(vbc->get_data_size_bytes()); //_total_buffers_pcollector.add_level(vbc->get_data_size_bytes());
_total_buffer_count_pcollector.add_level(1);
} }
return vbc; return vbc;
@ -596,6 +600,7 @@ release_index_buffer(IndexBufferContext *ibc) {
ibc->_data->clear_prepared(this); ibc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes()); _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
// We have to set the Data pointer to NULL at this point, since // We have to set the Data pointer to NULL at this point, since
// the Data itself might destruct at any time after it has been // the Data itself might destruct at any time after it has been
@ -629,6 +634,7 @@ release_all_index_buffers() {
IndexBufferContext *ibc = (*ibci); IndexBufferContext *ibc = (*ibci);
ibc->_data->clear_prepared(this); ibc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes()); _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
ibc->_data = (qpGeomPrimitive *)NULL; ibc->_data = (qpGeomPrimitive *)NULL;
_released_index_buffers.insert(ibc); _released_index_buffers.insert(ibc);
@ -679,6 +685,7 @@ prepare_index_buffer_now(qpGeomPrimitive *data, GraphicsStateGuardianBase *gsg)
// GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to // GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to
// count it again here. // count it again here.
//_total_buffers_pcollector.add_level(ibc->get_data_size_bytes()); //_total_buffers_pcollector.add_level(ibc->get_data_size_bytes());
_total_buffer_count_pcollector.add_level(1);
} }
return ibc; return ibc;

View File

@ -116,6 +116,7 @@ private:
static PStatCollector _total_texusage_pcollector; static PStatCollector _total_texusage_pcollector;
static PStatCollector _total_buffers_pcollector; static PStatCollector _total_buffers_pcollector;
static PStatCollector _total_buffer_count_pcollector;
friend class GraphicsStateGuardian; friend class GraphicsStateGuardian;
}; };

View File

@ -17,6 +17,7 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
#include "geomTransformer.h" #include "geomTransformer.h"
#include "sceneGraphReducer.h"
#include "geomNode.h" #include "geomNode.h"
#include "qpgeom.h" #include "qpgeom.h"
#include "qpgeomVertexRewriter.h" #include "qpgeomVertexRewriter.h"
@ -528,29 +529,23 @@ apply_state(GeomNode *node, const RenderState *state) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::collect_vertex_data // Function: GeomTransformer::collect_vertex_data
// Access: Public // Access: Public
// Description: Transforms the vertices and the normals in the // Description: Collects together GeomVertexDatas from different
// indicated Geom by the indicated matrix. Returns true // geoms into one big (or several big) GeomVertexDatas.
// if the Geom was changed, false otherwise. // Returns the number of unique GeomVertexDatas created.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool GeomTransformer:: int GeomTransformer::
collect_vertex_data(Geom *geom, bool keep_names) { collect_vertex_data(qpGeom *geom, int collect_bits) {
if (!geom->is_of_type(qpGeom::get_class_type())) { const qpGeomVertexData *vdata = geom->get_vertex_data();
return false;
}
qpGeom *qpgeom = DCAST(qpGeom, geom);
const qpGeomVertexData *vdata = qpgeom->get_vertex_data();
if (vdata->get_num_vertices() > _max_collect_vertices) { if (vdata->get_num_vertices() > _max_collect_vertices) {
// Don't even bother. // Don't even bother.
return false; return 0;
} }
const qpGeomVertexFormat *format = vdata->get_format(); const qpGeomVertexFormat *format = vdata->get_format();
NewCollectedKey key; NewCollectedKey key;
if (keep_names) { if ((collect_bits & SceneGraphReducer::CVD_name) != 0) {
key._name = vdata->get_name(); key._name = vdata->get_name();
} }
key._format = format; key._format = format;
@ -561,12 +556,13 @@ collect_vertex_data(Geom *geom, bool keep_names) {
if (ai != _already_collected.end()) { if (ai != _already_collected.end()) {
// We've previously collected this vertex data; reuse it. // We've previously collected this vertex data; reuse it.
const AlreadyCollectedData &acd = (*ai).second; const AlreadyCollectedData &acd = (*ai).second;
qpgeom->offset_vertices(acd._data, acd._offset); geom->offset_vertices(acd._data, acd._offset);
return true; return 0;
} }
// We haven't collected this vertex data yet; append the vertices // We haven't collected this vertex data yet; append the vertices
// onto the new data. // onto the new data.
int num_created = 0;
NewCollectedData::iterator ni = _new_collected_data.find(key); NewCollectedData::iterator ni = _new_collected_data.find(key);
PT(qpGeomVertexData) new_data; PT(qpGeomVertexData) new_data;
@ -576,6 +572,7 @@ collect_vertex_data(Geom *geom, bool keep_names) {
new_data = new qpGeomVertexData(vdata->get_name(), format, new_data = new qpGeomVertexData(vdata->get_name(), format,
vdata->get_usage_hint()); vdata->get_usage_hint());
_new_collected_data[key] = new_data; _new_collected_data[key] = new_data;
++num_created;
} }
int offset = new_data->get_num_vertices(); int offset = new_data->get_num_vertices();
@ -588,6 +585,7 @@ collect_vertex_data(Geom *geom, bool keep_names) {
_new_collected_data[key] = new_data; _new_collected_data[key] = new_data;
offset = 0; offset = 0;
new_num_vertices = vdata->get_num_vertices(); new_num_vertices = vdata->get_num_vertices();
++num_created;
} }
new_data->set_num_vertices(new_num_vertices); new_data->set_num_vertices(new_num_vertices);
@ -604,12 +602,12 @@ collect_vertex_data(Geom *geom, bool keep_names) {
old_array->get_data(), copy_bytes); old_array->get_data(), copy_bytes);
} }
qpgeom->offset_vertices(new_data, offset);
AlreadyCollectedData &acd = _already_collected[vdata]; AlreadyCollectedData &acd = _already_collected[vdata];
acd._data = new_data; acd._data = new_data;
acd._offset = offset; acd._offset = offset;
geom->offset_vertices(new_data, offset);
return true; return num_created;
} }
@ -621,20 +619,38 @@ collect_vertex_data(Geom *geom, bool keep_names) {
// GeomVertexData structure. This is designed to // GeomVertexData structure. This is designed to
// minimize context switches on the graphics card. // minimize context switches on the graphics card.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool GeomTransformer:: int GeomTransformer::
collect_vertex_data(GeomNode *node, bool keep_names) { collect_vertex_data(GeomNode *node, int collect_bits) {
bool any_changed = false; int num_created = 0;
GeomTransformer *dynamic = NULL;
GeomNode::CDWriter cdata(node->_cycler); GeomNode::CDWriter cdata(node->_cycler);
GeomNode::Geoms::iterator gi; GeomNode::Geoms::iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
GeomNode::GeomEntry &entry = (*gi); GeomNode::GeomEntry &entry = (*gi);
PT(Geom) new_geom = entry._geom->make_copy(); if (entry._geom->is_of_type(qpGeom::get_class_type())) {
if (collect_vertex_data(new_geom, keep_names)) { PT(qpGeom) new_geom = DCAST(qpGeom, entry._geom->make_copy());
entry._geom = new_geom; entry._geom = new_geom;
any_changed = true;
if ((collect_bits & SceneGraphReducer::CVD_avoid_dynamic) != 0 &&
new_geom->get_vertex_data()->get_usage_hint() < qpGeomUsageHint::UH_static) {
// This one has some dynamic properties. Collect it
// independently of the outside world.
if (dynamic == (GeomTransformer *)NULL) {
dynamic = new GeomTransformer(*this);
}
num_created += dynamic->collect_vertex_data(new_geom, collect_bits);
} else {
num_created += collect_vertex_data(new_geom, collect_bits);
}
} }
} }
return any_changed; if (dynamic != (GeomTransformer *)NULL) {
delete dynamic;
}
return num_created;
} }

View File

@ -28,6 +28,7 @@
class GeomNode; class GeomNode;
class RenderState; class RenderState;
class InternalName; class InternalName;
class qpGeom;
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
// Class : GeomTransformer // Class : GeomTransformer
@ -72,8 +73,8 @@ public:
bool apply_state(GeomNode *node, const RenderState *state); bool apply_state(GeomNode *node, const RenderState *state);
bool collect_vertex_data(Geom *geom, bool keep_names); int collect_vertex_data(qpGeom *geom, int collect_bits);
bool collect_vertex_data(GeomNode *node, bool keep_names); int collect_vertex_data(GeomNode *node, int collect_bits);
private: private:
int _max_collect_vertices; int _max_collect_vertices;

View File

@ -574,37 +574,50 @@ choose_name(PandaNode *preserve, PandaNode *source1, PandaNode *source2) {
int SceneGraphReducer:: int SceneGraphReducer::
r_collect_vertex_data(PandaNode *node, int collect_bits, r_collect_vertex_data(PandaNode *node, int collect_bits,
GeomTransformer &transformer) { GeomTransformer &transformer) {
int num_collected = 0; int num_created = 0;
if ((collect_bits & CVD_model) != 0 && int this_node_bits = 0;
node->is_of_type(ModelNode::get_class_type())) { if (node->is_of_type(ModelNode::get_class_type())) {
// When we come to a model node, start a new collection. this_node_bits |= CVD_model;
}
if (!node->get_transform()->is_identity()) {
this_node_bits |= CVD_transform;
}
if ((collect_bits & this_node_bits) != 0) {
// We need to start a unique collection here.
GeomTransformer new_transformer(transformer); GeomTransformer new_transformer(transformer);
if (node->is_geom_node()) {
// When we come to geom node, collect.
if (new_transformer.collect_vertex_data(DCAST(GeomNode, node), collect_bits)) {
++num_created;
}
}
PandaNode::Children children = node->get_children(); PandaNode::Children children = node->get_children();
int num_children = children.get_num_children(); int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) { for (int i = 0; i < num_children; ++i) {
num_collected += num_created +=
r_collect_vertex_data(children.get_child(i), collect_bits, new_transformer); r_collect_vertex_data(children.get_child(i), collect_bits, new_transformer);
} }
return num_collected;
}
if (node->is_geom_node()) { } else {
// When we come to geom node, collect. // Keep the same collection.
bool keep_names = ((collect_bits & SceneGraphReducer::CVD_name) != 0);
if (transformer.collect_vertex_data(DCAST(GeomNode, node), keep_names)) { if (node->is_geom_node()) {
++num_collected; if (transformer.collect_vertex_data(DCAST(GeomNode, node), collect_bits)) {
++num_created;
}
}
PandaNode::Children children = node->get_children();
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
num_created +=
r_collect_vertex_data(children.get_child(i), collect_bits, transformer);
} }
} }
// Then recurse. return num_created;
PandaNode::Children children = node->get_children();
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
num_collected +=
r_collect_vertex_data(children.get_child(i), collect_bits, transformer);
}
return num_collected;
} }

View File

@ -62,8 +62,25 @@ PUBLISHED:
}; };
enum CollectVertexData { enum CollectVertexData {
// If set, two GeomVertexDatas with different names will not be
// collected together.
CVD_name = 0x001, CVD_name = 0x001,
// If set, a ModelNode begins a subgraph of nodes whose
// GeomVertexDatas will not be collected with nodes outside the
// subgraph.
CVD_model = 0x002, CVD_model = 0x002,
// If set, a non-identity transform begins a subgraph of nodes
// whose GeomVertexDatas will not be collected with nodes outside
// the subgraph.
CVD_transform = 0x004,
// If set, GeomVertexDatas with any usage_hint other than
// UH_static will not be collected with any other Geoms in a
// different GeomNode. However, two different Geoms within the
// same node might still be collected together.
CVD_avoid_dynamic = 0x008,
}; };
INLINE void apply_attribs(PandaNode *node, int attrib_types = ~0); INLINE void apply_attribs(PandaNode *node, int attrib_types = ~0);

View File

@ -151,13 +151,18 @@ static LevelCollectorProperties level_properties[] = {
{ 1, "Texture memory:In use", { 0.0, 1.0, 1.0 } }, { 1, "Texture memory:In use", { 0.0, 1.0, 1.0 } },
{ 1, "Texture manager", { 1.0, 0.0, 0.0 }, "MB", 12, 1048576 }, { 1, "Texture manager", { 1.0, 0.0, 0.0 }, "MB", 12, 1048576 },
{ 1, "Texture manager:Resident", { 1.0, 1.0, 0.0 } }, { 1, "Texture manager:Resident", { 1.0, 1.0, 0.0 } },
{ 1, "Prepared Textures", { 0.6, 0.8, 0.0 }, "", 500 },
{ 1, "Prepared Textures:Active", { 0.0, 0.6, 0.8 } },
{ 1, "Prepared Geoms", { 1.0, 0.0, 0.5 }, "", 500 }, { 1, "Prepared Geoms", { 1.0, 0.0, 0.5 }, "", 500 },
{ 1, "Prepared Geoms:Active", { 0.5, 1.0, 0.8 } }, { 1, "Prepared Geoms:Active", { 0.5, 1.0, 0.8 } },
{ 1, "Prepared GeomNodes", { 1.0, 0.0, 0.5 }, "", 500 }, { 1, "Prepared GeomNodes", { 1.0, 0.0, 0.5 }, "", 500 },
{ 1, "Prepared GeomNodes:Active", { 0.5, 1.0, 0.8 } }, { 1, "Prepared GeomNodes:Active", { 0.5, 1.0, 0.8 } },
{ 1, "Vertex buffers:Active vertex", { 1.0, 0.0, 0.5 } }, { 1, "Vertex buffer size", { 0.0, 0.0, 1.0 }, "MB", 12, 1048576 },
{ 1, "Vertex buffers:Active index" , { 0.5, 0.6, 1.0 } }, { 1, "Vertex buffer size:Active vertex", { 1.0, 0.0, 0.5 } },
{ 1, "Vertex buffers", { 0.0, 0.0, 1.0 }, "MB", 12, 1048576 }, { 1, "Vertex buffer size:Active index" , { 0.5, 0.6, 1.0 } },
{ 1, "Vertex buffer count", { 0.0, 0.6, 0.8 }, "", 500 },
{ 1, "Vertex buffer count:Active vertex", { 0.8, 0.0, 0.6 } },
{ 1, "Vertex buffer count:Active index", { 0.8, 0.6, 0.3 } },
{ 1, "Vertices", { 0.5, 0.2, 0.0 }, "K", 10, 1000 }, { 1, "Vertices", { 0.5, 0.2, 0.0 }, "K", 10, 1000 },
{ 1, "Vertices:Other", { 0.2, 0.2, 0.2 } }, { 1, "Vertices:Other", { 0.2, 0.2, 0.2 } },
{ 1, "Vertices:Triangles", { 0.8, 0.8, 0.8 } }, { 1, "Vertices:Triangles", { 0.8, 0.8, 0.8 } },