Commit 64e4fe57 authored by hybrid's avatar hybrid

Add shadow interface to static meshes

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4333 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 10139e71
......@@ -12,6 +12,7 @@ namespace irr
namespace scene
{
class IShadowVolumeSceneNode;
class IMesh;
......@@ -37,6 +38,25 @@ public:
/** \return Pointer to mesh which is displayed by this node. */
virtual IMesh* getMesh(void) = 0;
//! Creates shadow volume scene node as child of this node.
/** The shadow can be rendered using the ZPass or the zfail
method. ZPass is a little bit faster because the shadow volume
creation is easier, but with this method there occur ugly
looking artifacs when the camera is inside the shadow volume.
These error do not occur with the ZFail method.
\param shadowMesh: Optional custom mesh for shadow volume.
\param id: Id of the shadow scene node. This id can be used to
identify the node later.
\param zfailmethod: If set to true, the shadow will use the
zfail method, if not, zpass is used.
\param infinity: Value used by the shadow volume algorithm to
scale the shadow volume.
\return Pointer to the created shadow scene node. This pointer
should not be dropped. See IReferenceCounted::drop() for more
information. */
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0,
s32 id=-1, bool zfailmethod=true, f32 infinity=10000.0f) = 0;
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/** In this way it is possible to change the materials of a mesh
causing all mesh scene nodes referencing this mesh to change, too.
......
......@@ -290,7 +290,6 @@ void CAnimatedMeshSceneNode::render()
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
if (Shadow && PassCount==1)
Shadow->updateShadowVolumes();
......@@ -1116,6 +1115,7 @@ ISceneNode* CAnimatedMeshSceneNode::clone(ISceneNode* newParent, ISceneManager*
newNode->LoopCallBack = LoopCallBack;
newNode->PassCount = PassCount;
newNode->Shadow = Shadow;
newNode->Shadow->grab();
newNode->JointChildSceneNodes = JointChildSceneNodes;
newNode->PretransitingSave = PretransitingSave;
newNode->RenderFromIdentity = RenderFromIdentity;
......
......@@ -8,6 +8,7 @@
#include "S3DVertex.h"
#include "SMeshBuffer.h"
#include "os.h"
#include "CShadowVolumeSceneNode.h"
namespace irr
{
......@@ -32,7 +33,7 @@ CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr,
s32 id, const core::vector3df& position,
const core::vector3df& rotation, const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale),
Mesh(0), Size(size)
Mesh(0), Shadow(0), Size(size)
{
#ifdef _DEBUG
setDebugName("CCubeSceneNode");
......@@ -44,6 +45,8 @@ CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr,
CCubeSceneNode::~CCubeSceneNode()
{
if (Shadow)
Shadow->drop();
if (Mesh)
Mesh->drop();
}
......@@ -63,6 +66,9 @@ void CCubeSceneNode::render()
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
if (Shadow)
Shadow->updateShadowVolumes();
// for debug purposes only:
video::SMaterial mat = Mesh->getMeshBuffer(0)->getMaterial();
......@@ -121,6 +127,40 @@ const core::aabbox3d<f32>& CCubeSceneNode::getBoundingBox() const
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CCubeSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
return ISceneNode::removeChild(child);
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
IShadowVolumeSceneNode* CCubeSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh; // if null is given, use the mesh of node
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
}
void CCubeSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
......@@ -180,6 +220,8 @@ ISceneNode* CCubeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManag
nb->cloneMembers(this, newManager);
nb->getMaterial(0) = getMaterial(0);
nb->Shadow = Shadow;
nb->Shadow->grab();
if ( newParent )
nb->drop();
......
......@@ -45,6 +45,11 @@ namespace scene
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const { return ESNT_CUBE; }
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
......@@ -68,10 +73,16 @@ namespace scene
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const { return false; }
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
private:
void setSize();
IMesh* Mesh;
IShadowVolumeSceneNode* Shadow;
f32 Size;
};
......
......@@ -11,6 +11,7 @@
#include "IAnimatedMesh.h"
#include "IMaterialRenderer.h"
#include "IFileSystem.h"
#include "CShadowVolumeSceneNode.h"
namespace irr
{
......@@ -23,8 +24,8 @@ namespace scene
CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::vector3df& rotation,
const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), PassCount(0),
ReadOnlyMaterials(false)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), Shadow(0),
PassCount(0), ReadOnlyMaterials(false)
{
#ifdef _DEBUG
setDebugName("CMeshSceneNode");
......@@ -37,6 +38,8 @@ CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* m
//! destructor
CMeshSceneNode::~CMeshSceneNode()
{
if (Shadow)
Shadow->drop();
if (Mesh)
Mesh->drop();
}
......@@ -125,6 +128,9 @@ void CMeshSceneNode::render()
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
Box = Mesh->getBoundingBox();
if (Shadow && PassCount==1)
Shadow->updateShadowVolumes();
// for debug purposes only:
bool renderMeshes = true;
......@@ -221,6 +227,21 @@ void CMeshSceneNode::render()
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CMeshSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
return ISceneNode::removeChild(child);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CMeshSceneNode::getBoundingBox() const
{
......@@ -273,6 +294,25 @@ void CMeshSceneNode::setMesh(IMesh* mesh)
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
IShadowVolumeSceneNode* CMeshSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh; // if null is given, use the mesh of node
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
}
void CMeshSceneNode::copyMaterials()
{
Materials.clear();
......@@ -392,6 +432,8 @@ ISceneNode* CMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManag
nb->cloneMembers(this, newManager);
nb->ReadOnlyMaterials = ReadOnlyMaterials;
nb->Materials = Materials;
nb->Shadow = Shadow;
nb->Shadow->grab();
if (newParent)
nb->drop();
......
......@@ -60,6 +60,11 @@ namespace scene
//! Returns the current mesh
virtual IMesh* getMesh(void) { return Mesh; }
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
......@@ -71,6 +76,11 @@ namespace scene
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
protected:
void copyMaterials();
......@@ -80,6 +90,7 @@ namespace scene
video::SMaterial ReadOnlyMaterial;
IMesh* Mesh;
IShadowVolumeSceneNode* Shadow;
s32 PassCount;
bool ReadOnlyMaterials;
......
......@@ -10,8 +10,8 @@
#include "IMeshCache.h"
#include "IAnimatedMesh.h"
#include "IMaterialRenderer.h"
#include "os.h"
#include "CShadowVolumeSceneNode.h"
namespace irr
{
......@@ -24,7 +24,7 @@ COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr,
s32 id, s32 minimalPolysPerNode)
: IMeshSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0),
TangentsOctree(0), VertexType((video::E_VERTEX_TYPE)-1),
MinimalPolysPerNode(minimalPolysPerNode), Mesh(0),
MinimalPolysPerNode(minimalPolysPerNode), Mesh(0), Shadow(0),
UseVBOs(OCTREE_USE_HARDWARE), UseVisibilityAndVBOs(OCTREE_USE_VISIBILITY),
BoxBased(OCTREE_BOX_BASED)
{
......@@ -37,6 +37,8 @@ COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr,
//! destructor
COctreeSceneNode::~COctreeSceneNode()
{
if (Shadow)
Shadow->drop();
deleteTree();
}
......@@ -102,6 +104,9 @@ void COctreeSceneNode::render()
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
if (Shadow)
Shadow->updateShadowVolumes();
SViewFrustum frust = *camera->getViewFrustum();
//transform the frustum to the current absolute transformation
......@@ -281,6 +286,40 @@ void COctreeSceneNode::render()
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool COctreeSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
return ISceneNode::removeChild(child);
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
IShadowVolumeSceneNode* COctreeSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh; // if null is given, use the mesh of node
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& COctreeSceneNode::getBoundingBox() const
{
......
......@@ -66,6 +66,16 @@ namespace scene
//! Check if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const;
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
private:
void deleteTree();
......@@ -89,6 +99,7 @@ namespace scene
s32 PassCount;
IMesh * Mesh;
IShadowVolumeSceneNode* Shadow;
//! use VBOs for rendering where possible
bool UseVBOs;
//! use visibility information together with VBOs
......
......@@ -14,6 +14,7 @@
#include "IMeshManipulator.h"
#include "SMesh.h"
#include "IMaterialRenderer.h"
#include "CShadowVolumeSceneNode.h"
namespace irr
{
......@@ -33,7 +34,7 @@ CQuake3ShaderSceneNode::CQuake3ShaderSceneNode(
core::vector3df(0.f, 0.f, 0.f),
core::vector3df(0.f, 0.f, 0.f),
core::vector3df(1.f, 1.f, 1.f)),
Shader(shader), Mesh(0), Original(0), MeshBuffer(0), TimeAbs(0.f)
Shader(shader), Mesh(0), Shadow(0), Original(0), MeshBuffer(0), TimeAbs(0.f)
{
#ifdef _DEBUG
core::stringc dName = "CQuake3ShaderSceneNode ";
......@@ -71,6 +72,9 @@ CQuake3ShaderSceneNode::CQuake3ShaderSceneNode(
*/
CQuake3ShaderSceneNode::~CQuake3ShaderSceneNode()
{
if (Shadow)
Shadow->drop();
if (Mesh)
Mesh->drop();
......@@ -336,6 +340,8 @@ void CQuake3ShaderSceneNode::render()
}
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation );
if (Shadow)
Shadow->updateShadowVolumes();
//! render all stages
u32 drawCount = (pass == ESNRP_TRANSPARENT_EFFECT) ? 1 : 0;
......@@ -490,6 +496,40 @@ void CQuake3ShaderSceneNode::render()
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CQuake3ShaderSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
return ISceneNode::removeChild(child);
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
IShadowVolumeSceneNode* CQuake3ShaderSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh; // if null is given, use the mesh of node
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
}
/*!
3.3.1 deformVertexes wave <div> <func> <base> <amplitude> <phase> <freq>
Designed for water surfaces, modifying the values differently at each point.
......
......@@ -47,9 +47,20 @@ public:
virtual void setReadOnlyMaterials(bool readonly) {}
virtual bool isReadOnlyMaterials() const { return true; }
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
private:
const quake3::IShader* Shader;
SMesh *Mesh;
IShadowVolumeSceneNode* Shadow;
const SMeshBufferLightMap* Original;
SMeshBuffer* MeshBuffer;
core::vector3df MeshOffset;
......
......@@ -203,7 +203,7 @@ u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light,
void CShadowVolumeSceneNode::setShadowMesh(const IMesh* mesh)
{
if (ShadowMesh == mesh)
if (ShadowMesh == mesh)
return;
if (ShadowMesh)
ShadowMesh->drop();
......@@ -227,8 +227,8 @@ void CShadowVolumeSceneNode::updateShadowVolumes()
// create as much shadow volumes as there are lights but
// do not ignore the max light settings.
const u32 lights = SceneManager->getVideoDriver()->getDynamicLightCount();
if (!lights)
const u32 lightCount = SceneManager->getVideoDriver()->getDynamicLightCount();
if (!lightCount)
return;
// calculate total amount of vertices and indices
......@@ -279,7 +279,7 @@ void CShadowVolumeSceneNode::updateShadowVolumes()
const core::vector3df parentpos = Parent->getAbsolutePosition();
// TODO: Only correct for point lights.
for (i=0; i<lights; ++i)
for (i=0; i<lightCount; ++i)
{
const video::SLight& dl = SceneManager->getVideoDriver()->getDynamicLight(i);
core::vector3df lpos = dl.Position;
......
......@@ -7,6 +7,7 @@
#include "ISceneManager.h"
#include "S3DVertex.h"
#include "os.h"
#include "CShadowVolumeSceneNode.h"
namespace irr
{
......@@ -16,7 +17,7 @@ namespace scene
//! constructor
CSphereSceneNode::CSphereSceneNode(f32 radius, u32 polyCountX, u32 polyCountY, ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), Shadow(0),
Radius(radius), PolyCountX(polyCountX), PolyCountY(polyCountY)
{
#ifdef _DEBUG
......@@ -31,6 +32,8 @@ CSphereSceneNode::CSphereSceneNode(f32 radius, u32 polyCountX, u32 polyCountY, I
//! destructor
CSphereSceneNode::~CSphereSceneNode()
{
if (Shadow)
Shadow->drop();
if (Mesh)
Mesh->drop();
}
......@@ -45,6 +48,9 @@ void CSphereSceneNode::render()
{
driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial());
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
if (Shadow)
Shadow->updateShadowVolumes();
driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
if ( DebugDataVisible & scene::EDS_BBOX )
{
......@@ -57,6 +63,39 @@ void CSphereSceneNode::render()
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CSphereSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
return ISceneNode::removeChild(child);
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
IShadowVolumeSceneNode* CSphereSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh; // if null is given, use the mesh of node
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CSphereSceneNode::getBoundingBox() const
......@@ -146,6 +185,8 @@ ISceneNode* CSphereSceneNode::clone(ISceneNode* newParent, ISceneManager* newMan
nb->cloneMembers(this, newManager);
nb->getMaterial(0) = Mesh->getMeshBuffer(0)->getMaterial();
nb->Shadow = Shadow;
nb->Shadow->grab();
if ( newParent )
nb->drop();
......
......@@ -69,9 +69,20 @@ namespace scene
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const { return false; }
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
virtual bool removeChild(ISceneNode* child);
private:
IMesh* Mesh;
IShadowVolumeSceneNode* Shadow;
core::aabbox3d<f32> Box;
f32 Radius;
u32 PolyCountX;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment