[PROPOSAL] Add wireframe rendering and function classification improvements. (#778)

* Add wireframe rendering and function classification improvements.

* Fix platform compilation.

* Update CommandBufferGL.cpp

GL_LINE and GL_FILL are no present in mobile devices, so the raw value has been used instead.

* Update CommandBufferGL.cpp

* Try fix IOS compilation

* Update CommandBufferMTL.h [skip ci]

* GLES & D3D11 wireframe

Added crude but okay wireframe mode for GLES and D3D11 devices.
This commit is contained in:
Turky Mohammed 2022-08-06 11:17:55 +03:00 committed by GitHub
parent c21408cd73
commit 399dac7478
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 122 additions and 57 deletions

View File

@ -111,8 +111,6 @@ static Texture2D* getDummyTexture()
Mesh::Mesh()
: _skin(nullptr)
, _visible(true)
, _isTransparent(false)
, _force2DQueue(false)
, meshIndexFormat(CustomCommand::IndexFormat::U_SHORT)
, _meshIndexData(nullptr)
, _blend(BlendFunc::ALPHA_NON_PREMULTIPLIED)
@ -390,12 +388,13 @@ void Mesh::draw(Renderer* renderer,
uint32_t flags,
unsigned int lightMask,
const Vec4& color,
bool forceDepthWrite)
bool forceDepthWrite,
bool wireframe)
{
if (!isVisible())
return;
bool isTransparent = (_isTransparent || color.w < 1.f);
bool isTransparent = (_material->isTransparent() || color.w < 1.f);
float globalZ = isTransparent ? 0 : globalZOrder;
if (isTransparent)
flags |= Node::FLAGS_RENDER_AS_3D;
@ -416,8 +415,6 @@ void Mesh::draw(Renderer* renderer,
else
_material->getStateBlock().setDepthWrite(true);
_material->getStateBlock().setBlend(_force2DQueue || isTransparent);
// set default uniforms for Mesh
// 'u_color' and others
const auto scene = Director::getInstance()->getRunningScene();
@ -441,7 +438,8 @@ void Mesh::draw(Renderer* renderer,
command.init(globalZ, transform);
command.setSkipBatching(isTransparent);
command.setTransparent(isTransparent);
command.set3D(!_force2DQueue);
command.set3D(!_material->isForce2DQueue());
command.setWireframe(wireframe);
}
_meshIndexData->setPrimitiveType(_material->_drawPrimitive);

View File

@ -224,7 +224,8 @@ public:
uint32_t flags,
unsigned int lightMask,
const Vec4& color,
bool forceDepthWrite);
bool forceDepthWrite,
bool wireframe);
/**skin setter*/
void setSkin(MeshSkin* skin);
@ -239,11 +240,6 @@ public:
*/
void calculateAABB();
/**
* force set this Mesh renderer to 2D render queue
*/
void setForce2DQueue(bool force2D) { _force2DQueue = force2D; }
std::string getTextureFileName() { return _texFile; }
Mesh();
@ -257,8 +253,7 @@ protected:
std::map<NTextureData::Usage, Texture2D*> _textures; // textures that submesh is using
MeshSkin* _skin; // skin
bool _visible; // is the submesh visible
bool _isTransparent; // is this mesh transparent, it is a property of material in fact
bool _force2DQueue; // add this mesh to 2D render queue
CustomCommand::IndexFormat meshIndexFormat;
std::string _name;

View File

@ -276,7 +276,9 @@ MeshRenderer::MeshRenderer()
, _lightMask(-1)
, _shaderUsingLight(false)
, _forceDepthWrite(false)
, _wireframe(false)
, _usingAutogeneratedGLProgram(true)
, _transparentMaterialHint(false)
{}
MeshRenderer::~MeshRenderer()
@ -408,7 +410,7 @@ MeshRenderer* MeshRenderer::createMeshRendererNode(NodeData* nodedata, ModelData
texParams.sAddressMode = textureData->wrapS;
texParams.tAddressMode = textureData->wrapT;
tex->setTexParameters(texParams);
mesh->_isTransparent = (materialData->getTextureData(NTextureData::Usage::Transparency) != nullptr);
_transparentMaterialHint = materialData->getTextureData(NTextureData::Usage::Transparency) != nullptr;
}
}
textureData = materialData->getTextureData(NTextureData::Usage::Normal);
@ -512,6 +514,7 @@ void MeshRenderer::genMaterial(bool useLight)
for (auto&& mesh : _meshes)
{
auto material = materials[mesh->getMeshIndexData()->getMeshVertexData()];
material->setTransparent(_transparentMaterialHint);
// keep original state block if exist
auto oldmaterial = mesh->getMaterial();
if (oldmaterial)
@ -573,8 +576,7 @@ void MeshRenderer::createNode(NodeData* nodedata, Node* root, const MaterialData
texParams.sAddressMode = textureData->wrapS;
texParams.tAddressMode = textureData->wrapT;
tex->setTexParameters(texParams);
mesh->_isTransparent =
(materialData->getTextureData(NTextureData::Usage::Transparency) != nullptr);
_transparentMaterialHint = materialData->getTextureData(NTextureData::Usage::Transparency) != nullptr;
}
}
textureData = materialData->getTextureData(NTextureData::Usage::Normal);
@ -811,7 +813,7 @@ void MeshRenderer::draw(Renderer* renderer, const Mat4& transform, uint32_t flag
for (auto&& mesh : _meshes)
{
mesh->draw(renderer, _globalZOrder, transform, flags, _lightMask, Vec4(color.r, color.g, color.b, color.a),
_forceDepthWrite);
_forceDepthWrite, _wireframe);
}
}
@ -946,14 +948,6 @@ Mesh* MeshRenderer::getMesh() const
return _meshes.at(0);
}
void MeshRenderer::setForce2DQueue(bool force2D)
{
for (const auto& mesh : _meshes)
{
mesh->setForce2DQueue(force2D);
}
}
///////////////////////////////////////////////////////////////////////////////////
MeshRendererCache* MeshRendererCache::_cacheInstance = nullptr;
MeshRendererCache* MeshRendererCache::getInstance()

View File

@ -178,6 +178,11 @@ public:
void setLightMask(unsigned int mask) { _lightMask = mask; }
unsigned int getLightMask() const { return _lightMask; }
/** enables wireframe rendering mode for this mesh renderer only, this can be very useful for debugging and
understanding generated meshes. */
void setWireframe(bool value) { _wireframe = value; }
bool isWireframe() const { return _wireframe; }
/** render all meshes within this mesh renderer */
virtual void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override;
@ -194,15 +199,11 @@ public:
*/
void setMaterial(Material* material, int meshIndex);
/** Adds a new material to a particular mesh in this mesh renderer.
* if meshIndex == -1, then it will be applied to all the meshes that belong to this mesh renderer.
/** Gets the material of a specific mesh in this mesh renderer.
*
* @param meshIndex Index of the mesh to apply the material to.
* @param meshIndex Index of the mesh to get the material from. 0 is the default index.
*/
Material* getMaterial(int meshIndex) const;
/** force render this mesh renderer in 2D queue. */
void setForce2DQueue(bool force2D);
Material* getMaterial(int meshIndex = 0) const;
/** Get list of meshes used in this mesh renderer. */
const Vector<Mesh*>& getMeshes() const { return _meshes; }
@ -265,7 +266,9 @@ protected:
unsigned int _lightMask;
bool _shaderUsingLight; // Is the current shader using lighting?
bool _forceDepthWrite; // Always write to depth buffer
bool _wireframe; // render in wireframe mode
bool _usingAutogeneratedGLProgram;
bool _transparentMaterialHint; // Generate transparent materials when building from files
struct AsyncLoadParam
{

View File

@ -506,6 +506,18 @@ std::string Material::getName() const
return _name;
}
void Material::setTransparent(bool value)
{
_isTransparent = value;
getStateBlock().setBlend(_force2DQueue || _isTransparent);
}
void Material::setForce2DQueue(bool value)
{
_force2DQueue = value;
getStateBlock().setBlend(_force2DQueue || _isTransparent);
}
Material::Material() : _name(""), _currentTechnique(nullptr), _target(nullptr) {}
Material::~Material() {}

View File

@ -155,6 +155,27 @@ public:
*/
axis::backend::PrimitiveType getPrimitiveType() const { return _drawPrimitive; }
/**
* Enable material transparent rendering.
* WARNING: depth testing will not work.
*/
void setTransparent(bool value);
/**
* Is material transparent?
*/
bool isTransparent() const { return _isTransparent; }
/**
* Enable material 2D queue rendering.
*/
void setForce2DQueue(bool value);
/**
* Is material in 2D render queue?
*/
bool isForce2DQueue() const { return _force2DQueue; }
protected:
Material();
~Material();
@ -189,6 +210,9 @@ protected:
std::unordered_map<std::string, int> _textureSlots;
int _textureSlotIndex = 0;
bool _isTransparent = false; // is this mesh transparent.
bool _force2DQueue = false; // render meshes using this material in 2D render queue.
axis::backend::PrimitiveType _drawPrimitive =
axis::backend::PrimitiveType::TRIANGLE; // primitive draw type for meshes
};

View File

@ -92,6 +92,10 @@ public:
void set3D(bool value) { _is3D = value; }
/**Get the depth by current model view matrix.*/
float getDepth() const { return _depth; }
/**Whether the command should be rendered in wireframe mode.*/
bool isWireframe() const { return _isWireframe; }
/**Set wireframe render mode for this command.*/
void setWireframe(bool value) { _isWireframe = value; }
/// Can use the result to change the descriptor content.
inline PipelineDescriptor& getPipelineDescriptor() { return _pipelineDescriptor; }
@ -123,9 +127,12 @@ protected:
/** Is the command been rendered on 3D pass. */
bool _is3D = false;
/** Depth from the model view matrix.*/
/** Depth from the model view matrix. */
float _depth = 0.f;
/** Polygon render mode set to LINE, which represents wireframe mode. */
bool _isWireframe = false;
Mat4 _mv;
PipelineDescriptor _pipelineDescriptor;

View File

@ -731,12 +731,13 @@ void Renderer::drawCustomCommand(RenderCommand* command)
{
_commandBuffer->setIndexBuffer(cmd->getIndexBuffer());
_commandBuffer->drawElements(cmd->getPrimitiveType(), cmd->getIndexFormat(), cmd->getIndexDrawCount(),
cmd->getIndexDrawOffset());
cmd->getIndexDrawOffset(), cmd->isWireframe());
_drawnVertices += cmd->getIndexDrawCount();
}
else
{
_commandBuffer->drawArrays(cmd->getPrimitiveType(), cmd->getVertexDrawStart(), cmd->getVertexDrawCount());
_commandBuffer->drawArrays(cmd->getPrimitiveType(), cmd->getVertexDrawStart(), cmd->getVertexDrawCount(),
cmd->isWireframe());
_drawnVertices += cmd->getVertexDrawCount();
}
_drawnBatches++;

View File

@ -153,7 +153,10 @@ public:
* @param count For each instance, the number of indexes to draw
* @see `drawElements(PrimitiveType primitiveType, IndexFormat indexType, unsigned int count, unsigned int offset)`
*/
virtual void drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count) = 0;
virtual void drawArrays(PrimitiveType primitiveType,
std::size_t start,
std::size_t count,
bool wireframe = false) = 0;
/**
* Draw primitives with an index list.
@ -167,7 +170,8 @@ public:
virtual void drawElements(PrimitiveType primitiveType,
IndexFormat indexType,
std::size_t count,
std::size_t offset) = 0;
std::size_t offset,
bool wireframe = false) = 0;
/**
* Do some resources release.

View File

@ -143,8 +143,10 @@ public:
* @param start For each instance, the first index to draw
* @param count For each instance, the number of indexes to draw
* @see `drawElements(PrimitiveType primitiveType, IndexFormat indexType, unsigned int count, unsigned int offset)`
*
* TODO: Implement a wireframe mode for METAL devices. Refer to: https://forums.ogre3d.org/viewtopic.php?t=95089
*/
virtual void drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count) override;
virtual void drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count, bool wireframe) override;
/**
* Draw primitives with an index list.
@ -154,11 +156,14 @@ public:
* @param offset Byte offset within indexBuffer to start reading indexes from.
* @see `setIndexBuffer(Buffer* buffer)`
* @see `drawArrays(PrimitiveType primitiveType, unsigned int start, unsigned int count)`
*
* TODO: Implement a wireframe mode for METAL devices. Refer to: https://forums.ogre3d.org/viewtopic.php?t=95089
*/
virtual void drawElements(PrimitiveType primitiveType,
IndexFormat indexType,
std::size_t count,
std::size_t offset) override;
std::size_t offset,
bool wireframe) override;
/**
* Do some resources release.

View File

@ -290,7 +290,7 @@ void CommandBufferMTL::setIndexBuffer(Buffer* buffer)
[_mtlIndexBuffer retain];
}
void CommandBufferMTL::drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count)
void CommandBufferMTL::drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count, bool wireframe /* unused */)
{
prepareDrawing();
[_mtlRenderEncoder drawPrimitives:toMTLPrimitive(primitiveType) vertexStart:start vertexCount:count];
@ -299,7 +299,8 @@ void CommandBufferMTL::drawArrays(PrimitiveType primitiveType, std::size_t start
void CommandBufferMTL::drawElements(PrimitiveType primitiveType,
IndexFormat indexType,
std::size_t count,
std::size_t offset)
std::size_t offset,
bool wireframe /* unused */)
{
prepareDrawing();
[_mtlRenderEncoder drawIndexedPrimitives:toMTLPrimitive(primitiveType)

View File

@ -211,24 +211,40 @@ void CommandBufferGL::setProgramState(ProgramState* programState)
_programState = programState;
}
void CommandBufferGL::drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count)
void CommandBufferGL::drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count, bool wireframe)
{
prepareDrawing();
#ifdef AX_USE_GL // glPolygonMode is only supported in Desktop OpenGL
if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#else
if (wireframe) primitiveType = PrimitiveType::LINE;
#endif
glDrawArrays(UtilsGL::toGLPrimitiveType(primitiveType), start, count);
#ifdef AX_USE_GL // glPolygonMode is only supported in Desktop OpenGL
if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
cleanResources();
}
void CommandBufferGL::drawElements(PrimitiveType primitiveType,
IndexFormat indexType,
std::size_t count,
std::size_t offset)
std::size_t offset,
bool wireframe)
{
prepareDrawing();
#ifdef AX_USE_GL // glPolygonMode is only supported in Desktop OpenGL
if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#else
if (wireframe) primitiveType = PrimitiveType::LINE;
#endif
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer->getHandler());
glDrawElements(UtilsGL::toGLPrimitiveType(primitiveType), count, UtilsGL::toGLIndexType(indexType),
(GLvoid*)offset);
CHECK_GL_ERROR_DEBUG();
#ifdef AX_USE_GL // glPolygonMode is only supported in Desktop OpenGL
if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
cleanResources();
}

View File

@ -139,7 +139,7 @@ public:
* @param count For each instance, the number of indexes to draw
* @see `drawElements(PrimitiveType primitiveType, IndexFormat indexType, unsigned int count, unsigned int offset)`
*/
virtual void drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count) override;
virtual void drawArrays(PrimitiveType primitiveType, std::size_t start, std::size_t count, bool wireframe = false) override;
/**
* Draw primitives with an index list.
@ -153,7 +153,8 @@ public:
virtual void drawElements(PrimitiveType primitiveType,
IndexFormat indexType,
std::size_t count,
std::size_t offset) override;
std::size_t offset,
bool wireframe = false) override;
/**
* Do some resources release.

View File

@ -2258,7 +2258,7 @@ int lua_axis_3d_Mesh_draw(lua_State* tolua_S)
#endif
argc = lua_gettop(tolua_S)-1;
if (argc == 7)
if (argc == 8)
{
axis::Renderer* arg0;
double arg1;
@ -2267,26 +2267,30 @@ int lua_axis_3d_Mesh_draw(lua_State* tolua_S)
unsigned int arg4;
axis::Vec4 arg5;
bool arg6;
bool arg7;
ok &= luaval_to_object<axis::Renderer>(tolua_S, 2, "ax.Renderer",&arg0, "ax.Mesh:draw");
ok &= luaval_to_number(tolua_S, 3,&arg1, "ax.Mesh:draw");
ok &= luaval_to_number(tolua_S, 3, &arg1, "ax.Mesh:draw");
ok &= luaval_to_mat4(tolua_S, 4, &arg2, "ax.Mesh:draw");
ok &= luaval_to_uint32(tolua_S, 5,&arg3, "ax.Mesh:draw");
ok &= luaval_to_uint32(tolua_S, 5, &arg3, "ax.Mesh:draw");
ok &= luaval_to_uint32(tolua_S, 6,&arg4, "ax.Mesh:draw");
ok &= luaval_to_uint32(tolua_S, 6, &arg4, "ax.Mesh:draw");
ok &= luaval_to_vec4(tolua_S, 7, &arg5, "ax.Mesh:draw");
ok &= luaval_to_boolean(tolua_S, 8,&arg6, "ax.Mesh:draw");
ok &= luaval_to_boolean(tolua_S, 8, &arg6, "ax.Mesh:draw");
ok &= luaval_to_boolean(tolua_S, 9, &arg7, "ax.Mesh:draw");
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function 'lua_axis_3d_Mesh_draw'", nullptr);
return 0;
}
cobj->draw(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
cobj->draw(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
lua_settop(tolua_S, 1);
return 1;
}
@ -2627,7 +2631,7 @@ int lua_axis_3d_Mesh_setForce2DQueue(lua_State* tolua_S)
tolua_error(tolua_S,"invalid arguments in function 'lua_axis_3d_Mesh_setForce2DQueue'", nullptr);
return 0;
}
cobj->setForce2DQueue(arg0);
cobj->getMaterial()->setForce2DQueue(arg0);
lua_settop(tolua_S, 1);
return 1;
}
@ -4480,7 +4484,7 @@ int lua_axis_3d_MeshRenderer_setForce2DQueue(lua_State* tolua_S)
tolua_error(tolua_S,"invalid arguments in function 'lua_axis_3d_MeshRenderer_setForce2DQueue'", nullptr);
return 0;
}
cobj->setForce2DQueue(arg0);
cobj->getMaterial()->setForce2DQueue(arg0);
lua_settop(tolua_S, 1);
return 1;
}

View File

@ -2214,7 +2214,7 @@ MeshRendererClippingTest::MeshRendererClippingTest()
auto animation = Animation3D::create("MeshRendererTest/orc.c3b");
auto animate = Animate3D::create(animation);
mesh3D->runAction(RepeatForever::create(animate));
mesh3D->setForce2DQueue(true);
mesh3D->getMaterial()->setForce2DQueue(true);
}
MeshRendererClippingTest::~MeshRendererClippingTest() {}