Add IOctreeSceneNode interface to control parameters like VBO usage and polygon clipping checks for octree scene nodes.

This was already possible, but needed users to set some defines and recompile Irrlicht.
As before it's only implemented for the EVT_2TCOORDS vertex format (others will follow soon).


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5434 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2017-04-19 16:28:24 +00:00
parent 5b6a6adf1f
commit 6355bc18b7
10 changed files with 188 additions and 65 deletions

View File

@ -1,6 +1,7 @@
--------------------------
Changes in 1.9 (not yet released)
- Add IOctreeSceneNode interface to control parameters like VBO usage and polygon clipping checks for octree scene nodes.
- Add support for different geometric primitivs to meshbuffers. Thanks @gerdb for patch proposal (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=45999)
- change SEvent::SUserEvent.UserData1 and SEvent::SUserEvent.UserData1 from s32 to size_t to avoid cutting numbers on some 64-bit platforms (SDL and Windows)
- Improve speed of draw3DBox (OpenGL and D3D9). Thanks @zerochen for patch (https://sourceforge.net/p/irrlicht/patches/256)

View File

@ -0,0 +1,86 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __I_OCTREE_SCENE_NODE_H_INCLUDED__
#define __I_OCTREE_SCENE_NODE_H_INCLUDED__
#include "IMeshSceneNode.h"
namespace irr
{
namespace scene
{
//! Settings if/how octree scene nodes are using hardware mesh-buffers
/** VBO = Vertex buffer object = meshbuffers bound on the graphic-card instead of uploaded each frame.
It can not be generally said which mode is optimal for drawing as this depends
on the scene. So you have to try and experiment for your meshes which one works best.
*/
enum EOCTREENODE_VBO
{
//! No VBO's used. Vertices+indices send to graphic-card on each render.
EOV_NO_VBO,
//! VBO's used. Draw the complete meshbuffers if any polygon in it is visible.
//! This allows VBO's for the meshbuffers to be completely static, but basically means
//! the octree is not used as an octree (not it still does do all the octree calculations)
//! Might work in very specific cases, but if this is gives you the best fastest results
//! you should probably compare as well to simply using a static mesh with no octree at all.
//! In most cases the other 2 options should work better with an octree.
EOV_USE_VBO,
//! VBO's used. The index-buffer information is updated each frame
//! with only the visible parts of a tree-node.
//! So the vertex-buffer is static and the index-buffer is dynamic.
//! This is the default
EOV_USE_VBO_WITH_VISIBITLY
};
//! Kind of checks polygons of the octree scene nodes use against camera
enum EOCTREE_POLYGON_CHECKS
{
//! Check against box of the camera frustum
//! This is the default
EOPC_BOX,
//! against the camera frustum
EOPC_FRUSTUM
};
//! A scene node displaying a static mesh
class IOctreeSceneNode : public irr::scene::IMeshSceneNode
{
public:
//! Constructor
/** Use setMesh() to set the mesh to display.
*/
IOctreeSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& rotation = core::vector3df(0,0,0),
const core::vector3df& scale = core::vector3df(1,1,1))
: IMeshSceneNode(parent, mgr, id, position, rotation, scale) {}
//! Set if/how vertex buffer object are used for the meshbuffers
/** NOTE: When there is already a mesh in the node this will rebuild
the octree. */
virtual void setUseVBO(EOCTREENODE_VBO useVBO) = 0;
//! Get if/how vertex buffer object are used for the meshbuffers
virtual EOCTREENODE_VBO getUseVBO() const = 0;
//! Set the kind of tests polygons do for visibility against the camera
virtual void setPolygonChecks(EOCTREE_POLYGON_CHECKS checks) = 0;
//! Get the kind of tests polygons do for visibility against the camera
virtual EOCTREE_POLYGON_CHECKS getPolygonChecks() const = 0;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -110,6 +110,7 @@ namespace scene
class IMeshSceneNode;
class IMeshWriter;
class IMetaTriangleSelector;
class IOctreeSceneNode;
class IParticleSystemSceneNode;
class ISceneCollisionManager;
class ISceneLoader;
@ -543,17 +544,9 @@ namespace scene
\param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed.
\return Pointer to the octree if successful, otherwise 0.
This pointer should not be dropped. See IReferenceCounted::drop() for more information. */
virtual IMeshSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0,
virtual IOctreeSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0,
s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) = 0;
//! Adds a scene node for rendering using a octree to the scene graph.
/** \deprecated Use addOctreeSceneNode instead. This method may be removed by Irrlicht 1.9. */
_IRR_DEPRECATED_ IMeshSceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0,
s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false)
{
return addOctreeSceneNode(mesh, parent, id, minimalPolysPerNode, alsoAddIfMeshPointerZero);
}
//! Adds a scene node for rendering using a octree to the scene graph.
/** This a good method for rendering scenes with lots of
geometry. The octree is built on the fly from the mesh, much
@ -567,17 +560,9 @@ namespace scene
\param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed.
\return Pointer to the octree if successful, otherwise 0.
This pointer should not be dropped. See IReferenceCounted::drop() for more information. */
virtual IMeshSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0,
virtual IOctreeSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0,
s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0;
//! Adds a scene node for rendering using a octree to the scene graph.
/** \deprecated Use addOctreeSceneNode instead. This method may be removed by Irrlicht 1.9. */
_IRR_DEPRECATED_ IMeshSceneNode* addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent=0,
s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false)
{
return addOctreeSceneNode(mesh, parent, id, minimalPolysPerNode, alsoAddIfMeshPointerZero);
}
//! Adds a camera scene node to the scene graph and sets it as active camera.
/** This camera does not react on user input like for example the one created with
addCameraSceneNodeFPS(). If you want to move or animate it, use animators or the
@ -1272,7 +1257,7 @@ namespace scene
\endcode
\param mesh: Mesh of which the triangles are taken.
\param node: Scene node of which transformation is used.
\param separateMeshbuffers: When true it's possible to get information which meshbuffer
\param separateMeshbuffers: When true it's possible to get information which meshbuffer
got hit in collision tests. But has a slight speed cost.
\return The selector, or null if not successful.
If you no longer need the selector, you should call ITriangleSelector::drop().
@ -1291,7 +1276,7 @@ namespace scene
//! Creates a simple ITriangleSelector, based on an animated mesh scene node.
/** Details of the mesh associated with the node will be extracted internally.
\param node The animated mesh scene node from which to build the selector
\param separateMeshbuffers: When true it's possible to get information which meshbuffer
\param separateMeshbuffers: When true it's possible to get information which meshbuffer
got hit in collision tests. But has a slight speed cost.
*/
virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers=false) = 0;

View File

@ -115,6 +115,7 @@
#include "IMeshManipulator.h"
#include "IMeshSceneNode.h"
#include "IMeshWriter.h"
#include "IOctreeSceneNode.h"
#include "IColladaMeshWriter.h"
#include "IMetaTriangleSelector.h"
#include "IOSOperator.h"

View File

@ -14,6 +14,7 @@
#include "IParticleSystemSceneNode.h"
#include "ILightSceneNode.h"
#include "IMeshSceneNode.h"
#include "IOctreeSceneNode.h"
namespace irr
{

View File

@ -24,11 +24,10 @@ namespace scene
//! constructor
COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr,
s32 id, s32 minimalPolysPerNode)
: IMeshSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0),
: IOctreeSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0),
TangentsOctree(0), VertexType((video::E_VERTEX_TYPE)-1),
MinimalPolysPerNode(minimalPolysPerNode), Mesh(0), Shadow(0),
UseVBOs(OCTREE_USE_HARDWARE), UseVisibilityAndVBOs(OCTREE_USE_VISIBILITY),
BoxBased(OCTREE_BOX_BASED)
UseVBOs(EOV_USE_VBO_WITH_VISIBITLY), PolygonChecks(EOPC_BOX)
{
#ifdef _DEBUG
setDebugName("COctreeSceneNode");
@ -136,10 +135,15 @@ void COctreeSceneNode::render()
case video::EVT_STANDARD:
{
IRR_PROFILE(getProfiler().start(EPID_OC_CALCPOLYS));
if (BoxBased)
StdOctree->calculatePolys(box);
else
StdOctree->calculatePolys(frust);
switch ( PolygonChecks )
{
case EOPC_BOX:
StdOctree->calculatePolys(box);
break;
case EOPC_FRUSTUM:
StdOctree->calculatePolys(frust);
break;
}
IRR_PROFILE(getProfiler().stop(EPID_OC_CALCPOLYS));
const Octree<video::S3DVertex>::SIndexData* d = StdOctree->getIndexData();
@ -186,10 +190,15 @@ void COctreeSceneNode::render()
case video::EVT_2TCOORDS:
{
IRR_PROFILE(getProfiler().start(EPID_OC_CALCPOLYS));
if (BoxBased)
LightMapOctree->calculatePolys(box);
else
LightMapOctree->calculatePolys(frust);
switch ( PolygonChecks )
{
case EOPC_BOX:
LightMapOctree->calculatePolys(box);
break;
case EOPC_FRUSTUM:
LightMapOctree->calculatePolys(frust);
break;
}
IRR_PROFILE(getProfiler().stop(EPID_OC_CALCPOLYS));
const Octree<video::S3DVertex2TCoords>::SIndexData* d = LightMapOctree->getIndexData();
@ -207,9 +216,18 @@ void COctreeSceneNode::render()
if (transparent == isTransparentPass)
{
driver->setMaterial(Materials[i]);
if (UseVBOs)
switch ( UseVBOs )
{
if (UseVisibilityAndVBOs)
case EOV_NO_VBO:
driver->drawIndexedTriangleList(
&LightMapMeshes[i].Vertices[0],
LightMapMeshes[i].Vertices.size(),
d[i].Indices, d[i].CurrentSize / 3);
break;
case EOV_USE_VBO:
driver->drawMeshBuffer ( &LightMapMeshes[i] );
break;
case EOV_USE_VBO_WITH_VISIBITLY:
{
u16* oldPointer = LightMapMeshes[i].Indices.pointer();
const u32 oldSize = LightMapMeshes[i].Indices.size();
@ -219,15 +237,9 @@ void COctreeSceneNode::render()
driver->drawMeshBuffer ( &LightMapMeshes[i] );
LightMapMeshes[i].Indices.set_pointer(oldPointer, oldSize);
LightMapMeshes[i].setDirty(scene::EBT_INDEX);
break;
}
else
driver->drawMeshBuffer ( &LightMapMeshes[i] );
}
else
driver->drawIndexedTriangleList(
&LightMapMeshes[i].Vertices[0],
LightMapMeshes[i].Vertices.size(),
d[i].Indices, d[i].CurrentSize / 3);
}
}
@ -254,10 +266,15 @@ void COctreeSceneNode::render()
case video::EVT_TANGENTS:
{
IRR_PROFILE(getProfiler().start(EPID_OC_CALCPOLYS));
if (BoxBased)
TangentsOctree->calculatePolys(box);
else
TangentsOctree->calculatePolys(frust);
switch ( PolygonChecks )
{
case EOPC_BOX:
TangentsOctree->calculatePolys(box);
break;
case EOPC_FRUSTUM:
TangentsOctree->calculatePolys(frust);
break;
}
IRR_PROFILE(getProfiler().stop(EPID_OC_CALCPOLYS));
const Octree<video::S3DVertexTangents>::SIndexData* d = TangentsOctree->getIndexData();
@ -319,6 +336,27 @@ bool COctreeSceneNode::removeChild(ISceneNode* child)
return ISceneNode::removeChild(child);
}
void COctreeSceneNode::setUseVBO(EOCTREENODE_VBO useVBO)
{
UseVBOs = useVBO;
if ( Mesh )
createTree(Mesh);
}
EOCTREENODE_VBO COctreeSceneNode::getUseVBO() const
{
return UseVBOs;
}
void COctreeSceneNode::setPolygonChecks(EOCTREE_POLYGON_CHECKS checks)
{
PolygonChecks = checks;
}
EOCTREE_POLYGON_CHECKS COctreeSceneNode::getPolygonChecks() const
{
return PolygonChecks;
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
@ -371,7 +409,11 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
if (mesh->getMeshBufferCount())
{
// check for "larger" buffer types
// check for "largest" buffer types
// Also dropping buffers/materials for empty buffer
// (which looks like a horrible idea. If a user wanted that material without mesh he should still get it...
// but not going to change that now. Only documenting it after figuring out what happens here.
// It works at least as Materials are reset in deleteTree).
VertexType = video::EVT_STANDARD;
u32 meshReserve = 0;
for (i=0; i<mesh->getMeshBufferCount(); ++i)
@ -450,7 +492,7 @@ bool COctreeSceneNode::createTree(IMesh* mesh)
Octree<video::S3DVertex2TCoords>::SMeshChunk& nchunk = LightMapMeshes.getLast();
nchunk.MaterialId = Materials.size() - 1;
if (UseVisibilityAndVBOs)
if (UseVBOs == EOV_USE_VBO_WITH_VISIBITLY)
{
nchunk.setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX);
nchunk.setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX);

View File

@ -5,15 +5,17 @@
#ifndef __C_OCTREE_SCENE_NODE_H_INCLUDED__
#define __C_OCTREE_SCENE_NODE_H_INCLUDED__
#include "IMeshSceneNode.h"
#include "IOctreeSceneNode.h"
#include "Octree.h"
namespace irr
{
namespace scene
{
//! implementation of the IBspTreeSceneNode
class COctreeSceneNode : public IMeshSceneNode
class COctreeSceneNode;
//! implementation of the IOctreeSceneNode
class COctreeSceneNode : public IOctreeSceneNode
{
public:
@ -76,6 +78,20 @@ namespace scene
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_;
//! Set if/how vertex buffer object are used for the meshbuffers
/** NOTE: When there is already a mesh in the node this will rebuild
the octree. */
virtual void setUseVBO(EOCTREENODE_VBO useVBO) _IRR_OVERRIDE_;
//! Get if/how vertex buffer object are used for the meshbuffers
virtual EOCTREENODE_VBO getUseVBO() const _IRR_OVERRIDE_;
//! Set the kind of tests polygons do for visibility against the camera
virtual void setPolygonChecks(EOCTREE_POLYGON_CHECKS checks) _IRR_OVERRIDE_;
//! Get the kind of tests polygons do for visibility against the camera
virtual EOCTREE_POLYGON_CHECKS getPolygonChecks() const _IRR_OVERRIDE_;
private:
void deleteTree();
@ -100,12 +116,9 @@ namespace scene
IMesh * Mesh;
IShadowVolumeSceneNode* Shadow;
//! use VBOs for rendering where possible
bool UseVBOs;
//! use visibility information together with VBOs
bool UseVisibilityAndVBOs;
//! use bounding box or frustum for calculate polys
bool BoxBased;
EOCTREENODE_VBO UseVBOs;
EOCTREE_POLYGON_CHECKS PolygonChecks;
};
} // end namespace scene

View File

@ -678,7 +678,7 @@ IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* m
//! Adds a scene node for rendering using a octree to the scene graph. This a good method for rendering
//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much
//! faster then a bsp tree.
IMeshSceneNode* CSceneManager::addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent,
IOctreeSceneNode* CSceneManager::addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent,
s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero)
{
if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount()))
@ -693,7 +693,7 @@ IMeshSceneNode* CSceneManager::addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNod
//! Adds a scene node for rendering using a octree. This a good method for rendering
//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much
//! faster then a bsp tree.
IMeshSceneNode* CSceneManager::addOctreeSceneNode(IMesh* mesh, ISceneNode* parent,
IOctreeSceneNode* CSceneManager::addOctreeSceneNode(IMesh* mesh, ISceneNode* parent,
s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero)
{
if (!alsoAddIfMeshPointerZero && !mesh)

View File

@ -118,13 +118,13 @@ namespace scene
//! Adds a scene node for rendering using a octree to the scene graph. This a good method for rendering
//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much
//! faster then a bsp tree.
virtual IMeshSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0,
virtual IOctreeSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0,
s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) _IRR_OVERRIDE_;
//! Adss a scene node for rendering using a octree. This a good method for rendering
//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much
//! faster then a bsp tree.
virtual IMeshSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0,
virtual IOctreeSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0,
s32 id=-1, s32 minimalPolysPerNode=128, bool alsoAddIfMeshPointerZero=false) _IRR_OVERRIDE_;
//! Adds a camera scene node to the tree and sets it as active camera.

View File

@ -14,12 +14,6 @@
/**
Flags for Octree
*/
//! use meshbuffer for drawing, enables VBO usage
#define OCTREE_USE_HARDWARE false
//! use visibility information together with VBOs
#define OCTREE_USE_VISIBILITY true
//! use bounding box or frustum for calculate polys
#define OCTREE_BOX_BASED true
//! bypass full invisible/visible test
#define OCTREE_PARENTTEST