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)
- 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.
- 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.

View File

@ -120,14 +120,16 @@ namespace scene
/** should be called if the mesh changed. */
virtual void recalculateBoundingBox()
{
if (Vertices.empty())
BoundingBox.reset(0,0,0);
else
if (!Vertices.empty())
{
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);
}
else
BoundingBox.reset(0,0,0);
}

View File

@ -11,6 +11,7 @@ namespace irr
{
namespace scene
{
class ICameraSceneNode;
//! A billboard scene node.
/** 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 */
virtual void getColor(video::SColor& topColor,
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

View File

@ -18,6 +18,7 @@ CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr,
const core::vector3df& position, const core::dimension2d<f32>& size,
video::SColor colorTop, video::SColor colorBottom)
: IBillboardSceneNode(parent, mgr, id, position)
, Buffer(new SMeshBuffer())
{
#ifdef _DEBUG
setDebugName("CBillboardSceneNode");
@ -25,26 +26,33 @@ CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr,
setSize(size);
indices[0] = 0;
indices[1] = 2;
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
Buffer->Vertices.set_used(4);
Buffer->Indices.set_used(6);
vertices[0].TCoords.set(1.0f, 1.0f);
vertices[0].Color = colorBottom;
Buffer->Indices[0] = 0;
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);
vertices[1].Color = colorTop;
Buffer->Vertices[0].TCoords.set(1.0f, 1.0f);
Buffer->Vertices[0].Color = colorBottom;
vertices[2].TCoords.set(0.0f, 0.0f);
vertices[2].Color = colorTop;
Buffer->Vertices[1].TCoords.set(1.0f, 0.0f);
Buffer->Vertices[1].Color = colorTop;
vertices[3].TCoords.set(0.0f, 1.0f);
vertices[3].Color = colorBottom;
Buffer->Vertices[2].TCoords.set(0.0f, 0.0f);
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
void CBillboardSceneNode::OnRegisterSceneNode()
@ -66,7 +74,25 @@ void CBillboardSceneNode::render()
return;
// 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 campos = camera->getAbsolutePosition();
@ -91,6 +117,8 @@ void CBillboardSceneNode::render()
view *= -1.0f;
core::array<video::S3DVertex>& vertices = Buffer->Vertices;
for (s32 i=0; i<4; ++i)
vertices[i].Normal = view;
@ -105,33 +133,23 @@ void CBillboardSceneNode::render()
vertices[2].Pos = pos - topHorizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical;
// draw
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);
Buffer->recalculateBoundingBox();
}
//! returns the axis aligned bounding box of this node
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)
{
Size = size;
@ -144,8 +162,8 @@ void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
Size.Height = 1.0f;
const f32 avg = (Size.Width + Size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg);
BBoxSafe.MinEdge.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;
BBox.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg);
BBoxSafe.MinEdge.set(-avg,-avg,-avg);
BBoxSafe.MaxEdge.set(avg,avg,avg);
}
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("TopEdgeWidth", TopEdgeWidth);
out->addFloat("Height", Size.Height);
out->addColor("Shade_Top", vertices[1].Color);
out->addColor("Shade_Down", vertices[0].Color);
out->addColor("Shade_Top", Buffer->Vertices[1].Color);
out->addColor("Shade_Down", Buffer->Vertices[0].Color);
}
@ -228,10 +246,10 @@ void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttrib
}
else
setSize(Size);
vertices[1].Color = in->getAttributeAsColor("Shade_Top");
vertices[0].Color = in->getAttributeAsColor("Shade_Down");
vertices[2].Color = vertices[1].Color;
vertices[3].Color = vertices[0].Color;
Buffer->Vertices[1].Color = in->getAttributeAsColor("Shade_Top");
Buffer->Vertices[0].Color = in->getAttributeAsColor("Shade_Down");
Buffer->Vertices[2].Color = Buffer->Vertices[1].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)
{
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,
const video::SColor& bottomColor)
{
vertices[0].Color = bottomColor;
vertices[1].Color = topColor;
vertices[2].Color = topColor;
vertices[3].Color = bottomColor;
Buffer->Vertices[0].Color = bottomColor;
Buffer->Vertices[1].Color = topColor;
Buffer->Vertices[2].Color = topColor;
Buffer->Vertices[3].Color = bottomColor;
}
@ -263,8 +281,8 @@ void CBillboardSceneNode::setColor(const video::SColor& topColor,
void CBillboardSceneNode::getColor(video::SColor& topColor,
video::SColor& bottomColor) const
{
bottomColor = vertices[0].Color;
topColor = vertices[1].Color;
bottomColor = Buffer->Vertices[0].Color;
topColor = Buffer->Vertices[1].Color;
}
@ -280,7 +298,7 @@ ISceneNode* CBillboardSceneNode::clone(ISceneNode* newParent, ISceneManager* new
newManager, ID, RelativeTranslation, Size);
nb->cloneMembers(this, newManager);
nb->Material = Material;
nb->Buffer->Material = Buffer->Material;
nb->Size = Size;
nb->TopEdgeWidth = this->TopEdgeWidth;

View File

@ -6,7 +6,7 @@
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#include "IBillboardSceneNode.h"
#include "S3DVertex.h"
#include "SMeshBuffer.h"
namespace irr
{
@ -25,6 +25,8 @@ public:
video::SColor colorTop=video::SColor(0xFFFFFFFF),
video::SColor colorBottom=video::SColor(0xFFFFFFFF));
virtual ~CBillboardSceneNode();
//! pre render event
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
@ -67,6 +69,9 @@ public:
virtual void getColor(video::SColor& topColor,
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.
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.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
protected:
void updateMesh(const irr::scene::ICameraSceneNode* camera);
private:
//! Size.Width is the bottom edge width
core::dimension2d<f32> Size;
f32 TopEdgeWidth;
core::aabbox3d<f32> BBox;
video::SMaterial Material;
video::S3DVertex vertices[4];
u16 indices[6];
//! BoundingBox which is large enough to contain the billboard independent of the camera
// 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)
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
f32 textLength = 0.f;
u32 i;
@ -347,14 +366,9 @@ void CBillboardTextSceneNode::OnAnimate(u32 timeMs)
}
// make bounding box
for (i=0; i< Mesh->getMeshBufferCount() ; ++i)
Mesh->getMeshBuffer(i)->recalculateBoundingBox();
Mesh->recalculateBoundingBox();
BBox = Mesh->getBoundingBox();
core::matrix4 mat( getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE );
mat.transformBoxEx(BBox);
}
void CBillboardTextSceneNode::OnRegisterSceneNode()

View File

@ -17,6 +17,8 @@ namespace irr
namespace scene
{
class ICameraSceneNode;
class CTextSceneNode : public ITextSceneNode
{
public:
@ -141,6 +143,11 @@ namespace scene
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:
core::stringw Text;