@@ -90,9 +90,61 @@ void Mesh::resetLightUniformValues()
9090 _spotLightUniformRangeInverseValues.assign (maxSpotLight, 0 .0f );
9191}
9292
93+
94+
95+ void Mesh::enableInstancing (bool instance, int count)
96+ {
97+ _instancing = instance;
98+ _instanceCount = count;
99+ }
100+
101+ void Mesh::setInstanceCount (int count) {
102+ AXASSERT (_instancing, " Instancing should be enabled on this mesh." );
103+
104+ _instanceCount = count;
105+ }
106+
107+ void Mesh::addInstanceChild (Node* child)
108+ {
109+ AX_SAFE_RETAIN (child);
110+ _instances.push_back (child);
111+ _instanceTransformDirty = true ;
112+
113+ if (_instances.size () > _instanceCount)
114+ {
115+ _instanceCount *= 2 ;
116+ _instanceTransformBufferDirty = true ;
117+ }
118+ }
119+
120+ void Mesh::shrinkToFitInstances ()
121+ {
122+ if (_instanceCount > _instances.size ())
123+ {
124+ _instanceCount = _instances.size ();
125+ _instanceTransformBufferDirty = true ;
126+ }
127+ }
128+
129+ void Mesh::rebuildInstances ()
130+ {
131+ _instanceTransformDirty = true ;
132+ }
133+
134+ void Mesh::setDynamicInstancing (bool dynamic)
135+ {
136+ _dynamicInstancing = dynamic;
137+ }
138+
93139Mesh::Mesh ()
94140 : _skin(nullptr )
95141 , _visible(true )
142+ , _instancing(false )
143+ , _instanceTransformBuffer(nullptr )
144+ , _instanceTransformBufferDirty(false )
145+ , _instanceCount(0 )
146+ , _dynamicInstancing(false )
147+ , _instanceMatrixCache(nullptr )
96148 , meshIndexFormat(CustomCommand::IndexFormat::U_SHORT)
97149 , _meshIndexData(nullptr )
98150 , _blend(BlendFunc::ALPHA_NON_PREMULTIPLIED)
@@ -103,12 +155,16 @@ Mesh::Mesh()
103155Mesh::~Mesh ()
104156{
105157 for (auto && tex : _textures)
106- {
107158 AX_SAFE_RELEASE (tex.second );
108- }
159+
160+ for (auto && ins : _instances)
161+ AX_SAFE_RELEASE (ins);
162+
109163 AX_SAFE_RELEASE (_skin);
110164 AX_SAFE_RELEASE (_meshIndexData);
111165 AX_SAFE_RELEASE (_material);
166+ AX_SAFE_RELEASE (_instanceTransformBuffer);
167+ AX_SAFE_DELETE_ARRAY (_instanceMatrixCache);
112168}
113169
114170backend::Buffer* Mesh::getVertexBuffer () const
@@ -343,7 +399,7 @@ void Mesh::setMaterial(Material* material)
343399 auto & attributes = program->getActiveAttributes ();
344400 auto meshVertexData = _meshIndexData->getMeshVertexData ();
345401 auto attributeCount = meshVertexData->getMeshVertexAttribCount ();
346- AXASSERT (attributes.size () <= attributeCount, " missing attribute data" );
402+ // AXASSERT(attributes.size() <= attributeCount, "missing attribute data");
347403 }
348404#endif
349405 // TODO
@@ -387,6 +443,56 @@ void Mesh::draw(Renderer* renderer,
387443 if (isTransparent)
388444 flags |= Node::FLAGS_RENDER_AS_3D;
389445
446+ if (_instancing && _instanceCount > 0 )
447+ {
448+ if (!_instanceTransformBuffer || _instanceTransformBufferDirty)
449+ {
450+ AX_SAFE_RELEASE (_instanceTransformBuffer);
451+
452+ _instanceTransformBuffer = backend::Device::getInstance ()->newBuffer (
453+ _instanceCount * 64 , backend::BufferType::VERTEX, backend::BufferUsage::DYNAMIC);
454+
455+ _instanceMatrixCache = new float [_instanceCount * 16 ];
456+ for (int i = 0 ; i < _instanceCount; i++)
457+ {
458+ _instanceMatrixCache[i * 16 + 0 ] = 1 .0f ;
459+ _instanceMatrixCache[i * 16 + 1 ] = 0 .0f ;
460+ _instanceMatrixCache[i * 16 + 2 ] = 0 .0f ;
461+ _instanceMatrixCache[i * 16 + 3 ] = 0 .0f ;
462+ _instanceMatrixCache[i * 16 + 4 ] = 0 .0f ;
463+ _instanceMatrixCache[i * 16 + 5 ] = 1 .0f ;
464+ _instanceMatrixCache[i * 16 + 6 ] = 0 .0f ;
465+ _instanceMatrixCache[i * 16 + 7 ] = 0 .0f ;
466+ _instanceMatrixCache[i * 16 + 8 ] = 0 .0f ;
467+ _instanceMatrixCache[i * 16 + 9 ] = 0 .0f ;
468+ _instanceMatrixCache[i * 16 + 10 ] = 1 .0f ;
469+ _instanceMatrixCache[i * 16 + 11 ] = 0 .0f ;
470+ _instanceMatrixCache[i * 16 + 12 ] = 0 .0f ;
471+ _instanceMatrixCache[i * 16 + 13 ] = 0 .0f ;
472+ _instanceMatrixCache[i * 16 + 14 ] = 0 .0f ;
473+ _instanceMatrixCache[i * 16 + 15 ] = 1 .0f ;
474+ }
475+
476+ // Fill the buffer with identity matrix.
477+ _instanceTransformBuffer->updateData (_instanceMatrixCache, _instanceCount * 64 );
478+
479+ _instanceTransformBufferDirty = false ;
480+ }
481+
482+ if (_instanceTransformDirty || _dynamicInstancing)
483+ {
484+ _instanceTransformDirty = false ;
485+
486+ int memOffset = 0 ;
487+ for (auto & _ : _instances)
488+ {
489+ auto & mat = _->getNodeToParentTransform ();
490+ std::copy (mat.m , mat.m + 16 , _instanceMatrixCache + 16 * memOffset++);
491+ }
492+ _instanceTransformBuffer->updateSubData (_instanceMatrixCache, 0 , _instanceCount * 64 );
493+ }
494+ }
495+
390496 // TODO
391497 // _meshCommand.init(globalZ,
392498 // _material,
@@ -428,6 +534,13 @@ void Mesh::draw(Renderer* renderer,
428534 command.setTransparent (isTransparent);
429535 command.set3D (!_material->isForce2DQueue ());
430536 command.setWireframe (wireframe);
537+ if (_instancing && _instances.size () > 0 )
538+ {
539+ command.setDrawType (CustomCommand::DrawType::ELEMENT_INSTANCE);
540+ command.setInstanceBuffer (_instanceTransformBuffer, _instances.size ());
541+ }
542+ else if (_instancing)
543+ return ;
431544 }
432545
433546 _meshIndexData->setPrimitiveType (_material->_drawPrimitive );
0 commit comments