Add alternavive BoundingBox calculation for BillboardSceneNode which can take in a camera node. Thx @Seven and @JacKDuRdEn for bugreports.

There are still some problems (and even bugs) with all this, but fixing those will take more time. I documented some of the problems in code.
Also switched to using a MeshBuffer in the billboard (mainly because it's nicer for the emscripten port).


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5452 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2017-04-22 17:29:16 +00:00
parent 8990dbcf28
commit 966712c571
7 changed files with 129 additions and 65 deletions

View File

@ -1,6 +1,7 @@
-------------------------- --------------------------
Changes in 1.9 (not yet released) Changes in 1.9 (not yet released)
- Add alternavive BoundingBox calculation for BillboardSceneNode which can take in a camera node. Thx @Seven and @JacKDuRdEn for bugreports.
- FPS camera now supports keyboard rotation. - FPS camera now supports keyboard rotation.
- Base FPS-camera movement on last position of mouse instead of always center (works better on platforms where cursor-placement is not allowed) - Base FPS-camera movement on last position of mouse instead of always center (works better on platforms where cursor-placement is not allowed)
- Octrees with other vertex types than EVT_2TCOORDS can now also use VBO's. - Octrees with other vertex types than EVT_2TCOORDS can now also use VBO's.

View File

@ -120,14 +120,16 @@ namespace scene
/** should be called if the mesh changed. */ /** should be called if the mesh changed. */
virtual void recalculateBoundingBox() virtual void recalculateBoundingBox()
{ {
if (Vertices.empty()) if (!Vertices.empty())
BoundingBox.reset(0,0,0);
else
{ {
BoundingBox.reset(Vertices[0].Pos); BoundingBox.reset(Vertices[0].Pos);
for (u32 i=1; i<Vertices.size(); ++i) const irr::u32 vsize = Vertices.size();
for (u32 i=1; i<vsize; ++i)
BoundingBox.addInternalPoint(Vertices[i].Pos); BoundingBox.addInternalPoint(Vertices[i].Pos);
} }
else
BoundingBox.reset(0,0,0);
} }

View File

@ -11,6 +11,7 @@ namespace irr
{ {
namespace scene namespace scene
{ {
class ICameraSceneNode;
//! A billboard scene node. //! A billboard scene node.
/** A billboard is like a 3d sprite: A 2d element, /** A billboard is like a 3d sprite: A 2d element,
@ -65,6 +66,14 @@ public:
\param[out] bottomColor Stores the color of the bottom vertices */ \param[out] bottomColor Stores the color of the bottom vertices */
virtual void getColor(video::SColor& topColor, virtual void getColor(video::SColor& topColor,
video::SColor& bottomColor) const = 0; video::SColor& bottomColor) const = 0;
//! Get the real boundingbox used by the billboard, which can depend on the active camera.
/** The boundingbox returned will use absolute coordinates.
The billboard orients itself toward the camera and some only update in render().
So we don't know the real boundingboxes before that. Which would be too late for culling.
That is why the usual getBoundingBox will return a "safe" boundingbox which is guaranteed
to contain the billboard. While this function can return the real one. */
virtual const core::aabbox3d<f32>& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) = 0;
}; };
} // end namespace scene } // end namespace scene

View File

@ -18,6 +18,7 @@ CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr,
const core::vector3df& position, const core::dimension2d<f32>& size, const core::vector3df& position, const core::dimension2d<f32>& size,
video::SColor colorTop, video::SColor colorBottom) video::SColor colorTop, video::SColor colorBottom)
: IBillboardSceneNode(parent, mgr, id, position) : IBillboardSceneNode(parent, mgr, id, position)
, Buffer(new SMeshBuffer())
{ {
#ifdef _DEBUG #ifdef _DEBUG
setDebugName("CBillboardSceneNode"); setDebugName("CBillboardSceneNode");
@ -25,26 +26,33 @@ CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr,
setSize(size); setSize(size);
indices[0] = 0; Buffer->Vertices.set_used(4);
indices[1] = 2; Buffer->Indices.set_used(6);
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
vertices[0].TCoords.set(1.0f, 1.0f); Buffer->Indices[0] = 0;
vertices[0].Color = colorBottom; Buffer->Indices[1] = 2;
Buffer->Indices[2] = 1;
Buffer->Indices[3] = 0;
Buffer->Indices[4] = 3;
Buffer->Indices[5] = 2;
vertices[1].TCoords.set(1.0f, 0.0f); Buffer->Vertices[0].TCoords.set(1.0f, 1.0f);
vertices[1].Color = colorTop; Buffer->Vertices[0].Color = colorBottom;
vertices[2].TCoords.set(0.0f, 0.0f); Buffer->Vertices[1].TCoords.set(1.0f, 0.0f);
vertices[2].Color = colorTop; Buffer->Vertices[1].Color = colorTop;
vertices[3].TCoords.set(0.0f, 1.0f); Buffer->Vertices[2].TCoords.set(0.0f, 0.0f);
vertices[3].Color = colorBottom; Buffer->Vertices[2].Color = colorTop;
Buffer->Vertices[3].TCoords.set(0.0f, 1.0f);
Buffer->Vertices[3].Color = colorBottom;
} }
CBillboardSceneNode::~CBillboardSceneNode()
{
Buffer->drop();
}
//! pre render event //! pre render event
void CBillboardSceneNode::OnRegisterSceneNode() void CBillboardSceneNode::OnRegisterSceneNode()
@ -66,7 +74,25 @@ void CBillboardSceneNode::render()
return; return;
// make billboard look to camera // make billboard look to camera
updateMesh(camera);
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(Buffer->Material);
driver->drawMeshBuffer(Buffer);
if (DebugDataVisible & scene::EDS_BBOX)
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(BBoxSafe, video::SColor(0,208,195,152));
}
}
void CBillboardSceneNode::updateMesh(const irr::scene::ICameraSceneNode* camera)
{
// billboard looks toward camera
core::vector3df pos = getAbsolutePosition(); core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition(); core::vector3df campos = camera->getAbsolutePosition();
@ -91,6 +117,8 @@ void CBillboardSceneNode::render()
view *= -1.0f; view *= -1.0f;
core::array<video::S3DVertex>& vertices = Buffer->Vertices;
for (s32 i=0; i<4; ++i) for (s32 i=0; i<4; ++i)
vertices[i].Normal = view; vertices[i].Normal = view;
@ -105,33 +133,23 @@ void CBillboardSceneNode::render()
vertices[2].Pos = pos - topHorizontal - vertical; vertices[2].Pos = pos - topHorizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical; vertices[3].Pos = pos - horizontal + vertical;
// draw Buffer->recalculateBoundingBox();
if (DebugDataVisible & scene::EDS_BBOX)
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(BBox, video::SColor(0,208,195,152));
}
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(vertices, 4, indices, 2);
} }
//! returns the axis aligned bounding box of this node //! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CBillboardSceneNode::getBoundingBox() const const core::aabbox3d<f32>& CBillboardSceneNode::getBoundingBox() const
{ {
return BBox; // Really wrong when scaled.
return BBoxSafe;
} }
const core::aabbox3d<f32>& CBillboardSceneNode::getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) _IRR_OVERRIDE_
{
updateMesh(camera);
return Buffer->BoundingBox;
}
//! sets the size of the billboard
void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size) void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{ {
Size = size; Size = size;
@ -144,8 +162,8 @@ void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
Size.Height = 1.0f; Size.Height = 1.0f;
const f32 avg = (Size.Width + Size.Height)/6; const f32 avg = (Size.Width + Size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg); BBoxSafe.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg); BBoxSafe.MaxEdge.set(avg,avg,avg);
} }
@ -164,14 +182,14 @@ void CBillboardSceneNode::setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWi
} }
const f32 avg = (core::max_(Size.Width,TopEdgeWidth) + Size.Height)/6; const f32 avg = (core::max_(Size.Width,TopEdgeWidth) + Size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg); BBoxSafe.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg); BBoxSafe.MaxEdge.set(avg,avg,avg);
} }
video::SMaterial& CBillboardSceneNode::getMaterial(u32 i) video::SMaterial& CBillboardSceneNode::getMaterial(u32 i)
{ {
return Material; return Buffer->Material;
} }
@ -207,8 +225,8 @@ void CBillboardSceneNode::serializeAttributes(io::IAttributes* out, io::SAttribu
out->addFloat("Width", Size.Width); out->addFloat("Width", Size.Width);
out->addFloat("TopEdgeWidth", TopEdgeWidth); out->addFloat("TopEdgeWidth", TopEdgeWidth);
out->addFloat("Height", Size.Height); out->addFloat("Height", Size.Height);
out->addColor("Shade_Top", vertices[1].Color); out->addColor("Shade_Top", Buffer->Vertices[1].Color);
out->addColor("Shade_Down", vertices[0].Color); out->addColor("Shade_Down", Buffer->Vertices[0].Color);
} }
@ -228,10 +246,10 @@ void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttrib
} }
else else
setSize(Size); setSize(Size);
vertices[1].Color = in->getAttributeAsColor("Shade_Top"); Buffer->Vertices[1].Color = in->getAttributeAsColor("Shade_Top");
vertices[0].Color = in->getAttributeAsColor("Shade_Down"); Buffer->Vertices[0].Color = in->getAttributeAsColor("Shade_Down");
vertices[2].Color = vertices[1].Color; Buffer->Vertices[2].Color = Buffer->Vertices[1].Color;
vertices[3].Color = vertices[0].Color; Buffer->Vertices[3].Color = Buffer->Vertices[0].Color;
} }
@ -240,7 +258,7 @@ void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttrib
void CBillboardSceneNode::setColor(const video::SColor& overallColor) void CBillboardSceneNode::setColor(const video::SColor& overallColor)
{ {
for(u32 vertex = 0; vertex < 4; ++vertex) for(u32 vertex = 0; vertex < 4; ++vertex)
vertices[vertex].Color = overallColor; Buffer->Vertices[vertex].Color = overallColor;
} }
@ -250,10 +268,10 @@ void CBillboardSceneNode::setColor(const video::SColor& overallColor)
void CBillboardSceneNode::setColor(const video::SColor& topColor, void CBillboardSceneNode::setColor(const video::SColor& topColor,
const video::SColor& bottomColor) const video::SColor& bottomColor)
{ {
vertices[0].Color = bottomColor; Buffer->Vertices[0].Color = bottomColor;
vertices[1].Color = topColor; Buffer->Vertices[1].Color = topColor;
vertices[2].Color = topColor; Buffer->Vertices[2].Color = topColor;
vertices[3].Color = bottomColor; Buffer->Vertices[3].Color = bottomColor;
} }
@ -263,8 +281,8 @@ void CBillboardSceneNode::setColor(const video::SColor& topColor,
void CBillboardSceneNode::getColor(video::SColor& topColor, void CBillboardSceneNode::getColor(video::SColor& topColor,
video::SColor& bottomColor) const video::SColor& bottomColor) const
{ {
bottomColor = vertices[0].Color; bottomColor = Buffer->Vertices[0].Color;
topColor = vertices[1].Color; topColor = Buffer->Vertices[1].Color;
} }
@ -280,7 +298,7 @@ ISceneNode* CBillboardSceneNode::clone(ISceneNode* newParent, ISceneManager* new
newManager, ID, RelativeTranslation, Size); newManager, ID, RelativeTranslation, Size);
nb->cloneMembers(this, newManager); nb->cloneMembers(this, newManager);
nb->Material = Material; nb->Buffer->Material = Buffer->Material;
nb->Size = Size; nb->Size = Size;
nb->TopEdgeWidth = this->TopEdgeWidth; nb->TopEdgeWidth = this->TopEdgeWidth;

View File

@ -6,7 +6,7 @@
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__ #define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#include "IBillboardSceneNode.h" #include "IBillboardSceneNode.h"
#include "S3DVertex.h" #include "SMeshBuffer.h"
namespace irr namespace irr
{ {
@ -25,6 +25,8 @@ public:
video::SColor colorTop=video::SColor(0xFFFFFFFF), video::SColor colorTop=video::SColor(0xFFFFFFFF),
video::SColor colorBottom=video::SColor(0xFFFFFFFF)); video::SColor colorBottom=video::SColor(0xFFFFFFFF));
virtual ~CBillboardSceneNode();
//! pre render event //! pre render event
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
@ -67,6 +69,9 @@ public:
virtual void getColor(video::SColor& topColor, virtual void getColor(video::SColor& topColor,
video::SColor& bottomColor) const _IRR_OVERRIDE_; video::SColor& bottomColor) const _IRR_OVERRIDE_;
//! Get the real boundingbox used by the billboard (which depends on the active camera)
virtual const core::aabbox3d<f32>& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) _IRR_OVERRIDE_;
//! Writes attributes of the scene node. //! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
@ -79,16 +84,24 @@ public:
//! Creates a clone of this scene node and its children. //! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
protected:
void updateMesh(const irr::scene::ICameraSceneNode* camera);
private: private:
//! Size.Width is the bottom edge width //! Size.Width is the bottom edge width
core::dimension2d<f32> Size; core::dimension2d<f32> Size;
f32 TopEdgeWidth; f32 TopEdgeWidth;
core::aabbox3d<f32> BBox;
video::SMaterial Material;
video::S3DVertex vertices[4]; //! BoundingBox which is large enough to contain the billboard independent of the camera
u16 indices[6]; // TODO: BUG - still can be wrong with scaling < 1. Billboards should calculate relative coordinates for their mesh
// and then use the node-scaling. But needs some work...
/** Note that we can't use the real boundingbox for culling because at that point
the camera which is used to calculate the billboard is not yet updated. So we only
know the real boundingbox after rendering - which is too late for culling. */
core::aabbox3d<f32> BBoxSafe;
scene::SMeshBuffer* Buffer;
}; };

View File

@ -281,6 +281,25 @@ void CBillboardTextSceneNode::OnAnimate(u32 timeMs)
if (!camera) if (!camera)
return; return;
// TODO: Risky - if camera is later in the scene-graph then it's not yet updated here
// CBillBoardSceneNode does it different, but maybe real solution would be to enforce cameras to update earlier?
// Maybe we can also unify the code by using a common base-class or having updateMesh functionality in an animator instead.
updateMesh(camera);
// mesh uses vertices with absolute coordinates so to get a bbox for culling we have to get back to local ones.
BBox = Mesh->getBoundingBox();
core::matrix4 mat( getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE );
mat.transformBoxEx(BBox);
}
const core::aabbox3d<f32>& CBillboardTextSceneNode::getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera)
{
updateMesh(camera);
return Mesh->getBoundingBox();
}
void CBillboardTextSceneNode::updateMesh(const irr::scene::ICameraSceneNode* camera)
{
// get text width // get text width
f32 textLength = 0.f; f32 textLength = 0.f;
u32 i; u32 i;
@ -347,14 +366,9 @@ void CBillboardTextSceneNode::OnAnimate(u32 timeMs)
} }
// make bounding box // make bounding box
for (i=0; i< Mesh->getMeshBufferCount() ; ++i) for (i=0; i< Mesh->getMeshBufferCount() ; ++i)
Mesh->getMeshBuffer(i)->recalculateBoundingBox(); Mesh->getMeshBuffer(i)->recalculateBoundingBox();
Mesh->recalculateBoundingBox(); Mesh->recalculateBoundingBox();
BBox = Mesh->getBoundingBox();
core::matrix4 mat( getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE );
mat.transformBoxEx(BBox);
} }
void CBillboardTextSceneNode::OnRegisterSceneNode() void CBillboardTextSceneNode::OnRegisterSceneNode()

View File

@ -17,6 +17,8 @@ namespace irr
namespace scene namespace scene
{ {
class ICameraSceneNode;
class CTextSceneNode : public ITextSceneNode class CTextSceneNode : public ITextSceneNode
{ {
public: public:
@ -141,6 +143,11 @@ namespace scene
topEdgeWidth = Size.Width; topEdgeWidth = Size.Width;
} }
virtual const core::aabbox3d<f32>& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) _IRR_OVERRIDE_;
protected:
void updateMesh(const irr::scene::ICameraSceneNode* camera);
private: private:
core::stringw Text; core::stringw Text;