Browse Source

Physics and particles

Panagiotis Christopoulos Charitos 13 years ago
parent
commit
28a155af68

+ 87 - 0
include/anki/resource/ParticleEmitterResource.h

@@ -0,0 +1,87 @@
+#ifndef ANKI_RESOURCE_PARTICLE_EMITTER_RSRC_H
+#define ANKI_RESOURCE_PARTICLE_EMITTER_RSRC_H
+
+#include "anki/math/Math.h"
+#include "anki/resource/Resource.h"
+
+namespace anki {
+
+/// XXX
+struct ParticleEmitterProperties
+{
+public:
+	ParticleEmitterProperties& operator=(const ParticleEmitterProperties& b);
+
+protected:
+	/// @name Particle specific properties
+	/// @{
+	F32 particleLife = 0.0; ///< Required and > 0.0. In seconds
+	F32 particleLifeDeviation = 0.0;
+
+	/// Not-required, any value, Default 0.0, If not set only the gravity
+	/// applies
+	Vec3 forceDirection = Vec3(0.0, 1.0, 0.0);
+	Vec3 forceDirectionDeviation = Vec3(0.0);
+	F32 forceMagnitude = 0; ///< Default 0.0
+	F32 forceMagnitudeDeviation = 0.0;
+
+	F32 particleMass = 1.0; ///< Required and > 0.0
+	F32 particleMassDeviation = 0.0;
+
+	/// Not-required, any value. If not set then it uses the world's default
+	Vec3 gravity = Vec3(0.0);
+	Vec3 gravityDeviation = Vec3(0.0);
+
+	Vec3 startingPos = Vec3(0.0); ///< If not set the default is zero
+	Vec3 startingPosDeviation = Vec3(0.0);
+
+	F32 size = 0.0; ///< The size of the collision shape. Required and > 0.0
+	/// @}
+
+	/// @name Emitter specific properties
+	/// @{
+
+	/// The size of the particles vector. Required
+	U32 maxNumOfParticles;
+	/// How often the emitter emits new particles. In secs. Required
+	F32 emissionPeriod;
+	/// How many particles are emitted every emission. Required
+	U32 particlesPerEmittion;
+	/// @}
+};
+
+/// This is the properties of the particle emitter resource
+class ParticleEmitterResource: public ParticleEmitterProperties
+{
+public:
+	ParticleEmitterResource();
+	~ParticleEmitterResource();
+
+	Bool hasForce() const
+	{
+		return forceEnabled;
+	}
+
+	///< @return True if gravity is derived
+	Bool usingWorldGravity() const
+	{
+		return wordGravityEnabled;
+	}
+
+	const Model& getModel() const
+	{
+		return *model;
+	}
+
+	/// Load it
+	void load(const char* filename);
+
+private:
+	ModelResourcePointer model;
+	Bool forceEnabled;
+	Bool wordGravityEnabled;
+};
+
+} // end namespace anki
+
+#endif

+ 0 - 67
include/anki/resource/ParticleEmitterRsrc.h

@@ -1,67 +0,0 @@
-#ifndef ANKI_RESOURCE_PARTICLE_EMITTER_RSRC_H
-#define ANKI_RESOURCE_PARTICLE_EMITTER_RSRC_H
-
-#include "anki/math/Math.h"
-
-
-namespace anki {
-
-
-/// This is the properties of the particle emitter resource
-class ParticleEmitterRsrc
-{
-	public:
-		ParticleEmitterRsrc();
-		ParticleEmitterRsrc(const ParticleEmitterRsrc& a);
-		virtual ~ParticleEmitterRsrc() {}
-
-		ParticleEmitterRsrc& operator=(const ParticleEmitterRsrc& a);
-
-		bool hasForce() const; ///< Don't call it often. Its slow
-		bool usingWorldGrav() const; ///< @return True if gravity is derived
-
-		/// Load it
-		void load(const char* filename);
-
-	protected:
-		/// @name Particle specific properties
-		/// @{
-		float particleLife; ///< Required and > 0.0. In seconds
-		float particleLifeDeviation;
-
-		/// Not-required, any value, Default 0.0, If not set only the gravity
-		/// applies
-		Vec3 forceDirection;
-		Vec3 forceDirectionDeviation;
-		float forceMagnitude; ///< Default 0.0
-		float forceMagnitudeDeviation;
-
-		float particleMass; ///< Required and > 0.0
-		float particleMassDeviation;
-
-		/// Not-required, any value. If not set then it uses the world's default
-		Vec3 gravity;
-		Vec3 gravityDeviation;
-
-		Vec3 startingPos; ///< If not set the default is zero
-		Vec3 startingPosDeviation;
-
-		float size; ///< The size of the collision shape. Required and > 0.0
-		/// @}
-
-		/// @name Emitter specific properties
-		/// @{
-		uint maxNumOfParticles; ///< The size of the particles vector. Required
-		/// How often the emitter emits new particles. In secs. Required
-		float emissionPeriod;
-		/// How many particles are emitted every emission. Required
-		uint particlesPerEmittion;
-		std::string modelName;
-		/// @}
-};
-
-
-} // end namespace
-
-
-#endif

+ 1 - 2
include/anki/resource/Resource.h

@@ -14,7 +14,6 @@ namespace anki {
 		rsrc ## ResourceManagerSingleton; \
 	typedef ResourcePointer<rsrc, rsrc ## ResourceManagerSingleton> name;
 
-
 ANKI_RESOURCE_TYPEDEFS(TextureResource, TextureResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(ShaderProgramResource, ShaderProgramResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(Material, MaterialResourcePointer)
@@ -22,7 +21,7 @@ ANKI_RESOURCE_TYPEDEFS(Mesh, MeshResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(Skeleton, SkeletonResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(SkelAnim, SkelAnimResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(LightRsrc, LightRsrcResourcePointer)
-ANKI_RESOURCE_TYPEDEFS(ParticleEmitterRsrc, ParticleEmitterRsrcResourcePointer)
+ANKI_RESOURCE_TYPEDEFS(ParticleEmitterResource, ParticleEmitterResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(Script, ScriptResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(Model, ModelResourcePointer)
 ANKI_RESOURCE_TYPEDEFS(Skin, SkinResourcePointer)

+ 4 - 4
include/anki/scene/ModelNode.h

@@ -20,7 +20,7 @@ public:
 	/// @{
 	ModelPatchNode(const ModelPatch* modelPatch_,
 		const char* name, Scene* scene, // Scene
-		uint movableFlags, Movable* movParent); // Movable
+		U32 movableFlags, Movable* movParent); // Movable
 	/// @}
 
 	/// @name SceneNode virtuals
@@ -45,7 +45,7 @@ public:
 	}
 
 	/// Override SceneNode::frameUpdate
-	void frameUpdate(float prevUpdateTime, float crntTime, int frame)
+	void frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 	{
 		SceneNode::frameUpdate(prevUpdateTime, crntTime, frame);
 	}
@@ -69,13 +69,13 @@ public:
 	/// @{
 
 	/// Implements Renderable::getModelPatchBase
-	const ModelPatchBase& getModelPatchBase() const
+	const ModelPatchBase& getRenderableModelPatchBase() const
 	{
 		return *modelPatch;
 	}
 
 	/// Implements  Renderable::getMaterial
-	const Material& getMaterial() const
+	const Material& getRenderableMaterial() const
 	{
 		return modelPatch->getMaterial();
 	}

+ 0 - 40
include/anki/scene/Particle.h

@@ -1,40 +0,0 @@
-#ifndef ANKI_SCENE_PARTICLE_H
-#define ANKI_SCENE_PARTICLE_H
-
-#include <boost/scoped_ptr.hpp>
-#include "anki/scene/ModelNode.h"
-
-
-namespace anki {
-
-
-class RigidBody;
-
-
-/// The scene node particle class
-/*class Particle: public ModelNode
-{
-	public:
-		Particle(float timeOfDeath, Scene& scene, ulong flags,
-			SceneNode* parent);
-		virtual ~Particle();
-
-		float getTimeOfDeath() const {return timeOfDeath;}
-		float& getTimeOfDeath() {return timeOfDeath;}
-		void setTimeOfDeath(float x) {timeOfDeath = x;}
-
-		bool isDead() const {return timeOfDeath < 0.0;}
-		void setNewRigidBody(RigidBody* body);
-		RigidBody& getRigidBody() {return *body;}
-		const RigidBody& getRigidBody() const {return *body;}
-
-	private:
-		float timeOfDeath; ///< Life of death. If < 0.0 then dead. In seconds
-		boost::scoped_ptr<RigidBody> body; ///< For garbage collection
-};*/
-
-
-} // end namespace
-
-
-#endif

+ 123 - 0
include/anki/scene/ParticleEmitter.h

@@ -0,0 +1,123 @@
+#ifndef ANKI_SCENE_PARTICLE_EMITTER_H
+#define ANKI_SCENE_PARTICLE_EMITTER_H
+
+#include "anki/scene/SceneNode.h"
+#include "anki/scene/Movable.h"
+#include "anki/scene/Spatial.h"
+#include "anki/scene/Renderable.h"
+#include "anki/physics/RigidBody.h"
+#include "anki/resource/ParticleEmitterResource.h"
+
+namespace anki {
+
+/// Particle scene node
+class Particle: public SceneNode, public Movable, public RigidBody
+{
+public:
+	Particle(F32 timeOfDeath,
+		const char* name, Scene* scene, // Scene
+		U32 movableFlags, Movable* movParent, // Movable
+		PhysWorld* masterContainer, const Initializer& init); // RigidBody
+
+	~Particle();
+
+	/// @name SceneNode virtuals
+	/// @{
+
+	/// Override SceneNode::getMovable()
+	Movable* getMovable()
+	{
+		return this;
+	}
+
+	/// Override SceneNode::getRigidBody()
+	RigidBody* getRigidBody()
+	{
+		return this;
+	}
+	/// @}
+
+	F32 getTimeOfDeath() const
+	{
+		return timeOfDeath;
+	}
+	F32& getTimeOfDeath()
+	{
+		return timeOfDeath;
+	}
+	void setTimeOfDeath(F32 x)
+	{
+		timeOfDeath = x;
+	}
+
+	Bool isDead() const
+	{
+		return timeOfDeath < 0.0;
+	}
+
+private:
+	F32 timeOfDeath; ///< Life of death. If < 0.0 then dead. In seconds
+};
+
+/// The particle emitter scene node. This scene node emitts
+class ParticleEmitter: public SceneNode, public Spatial, public Movable,
+	public Renderable, private ParticleEmitterProperties
+{
+public:
+	ParticleEmitter(const char* filename,
+		const char* name, Scene* scene, // Scene
+		U32 movableFlags, Movable* movParent); // Movable
+	~ParticleEmitter();
+
+	/// @name SceneNode virtuals
+	/// @{
+
+	/// Override SceneNode::getMovable()
+	Movable* getMovable()
+	{
+		return this;
+	}
+
+	/// Override SceneNode::getSpatial()
+	Spatial* getSpatial()
+	{
+		return this;
+	}
+
+	/// Override SceneNode::frameUpdate()
+	void frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame);
+	/// @}
+
+	/// @name Renderable virtuals
+	/// @{
+
+	/// Implements Renderable::getModelPatchBase
+	const ModelPatchBase& getRenderableModelPatchBase() const;
+
+	/// Implements  Renderable::getMaterial
+	const Material& getRenderableMaterial() const;
+
+	/// Overrides Renderable::getRenderableWorldTransform
+	const Transform* getRenderableWorldTransform() const
+	{
+		return nullptr;
+	}
+	/// @}
+
+private:
+	ParticleEmitterResourcePointer particleEmitterResource;
+	std::unique_ptr<btCollisionShape> collShape;
+	PtrVector<Particle> particles;
+	F32 timeLeftForNextEmission;
+	/// The resource
+	Aabb aabb;
+
+	void init(const char* filename);
+
+	static F32 getRandom(F32 initial, F32 deviation);
+	static Vec3 getRandom(const Vec3& initial, const Vec3& deviation);
+};
+
+} // end namespace anki
+
+#endif

+ 0 - 48
include/anki/scene/ParticleEmitterNode.h

@@ -1,48 +0,0 @@
-#ifndef ANKI_SCENE_PARTICLE_EMITTER_NODE_H
-#define ANKI_SCENE_PARTICLE_EMITTER_NODE_H
-
-#include <btBulletCollisionCommon.h>
-#include "anki/scene/SceneNode.h"
-#include "anki/resource/ParticleEmitterRsrc.h"
-#include "anki/resource/Resource.h"
-
-class btCollisionShape;
-
-namespace anki {
-
-/*class Particle;
-
-
-/// The particle emitter scene node. This scene node emitts
-/// @ref ParticleEmitter:Particle particle nodes in space.
-class ParticleEmitterNode: public SceneNode, public ParticleEmitterRsrc
-{
-	public:
-		ParticleEmitterNode(Scene& scene, ulong flags, SceneNode* parent);
-		virtual ~ParticleEmitterNode();
-
-		void init(const char* filename);
-
-		void frameUpdate(float prevUpdateTime, float crntTime);
-
-	private:
-		boost::scoped_ptr<btCollisionShape> collShape;
-		Vector<Particle*> particles;
-		float timeLeftForNextEmission;
-		/// The resource
-		ParticleEmitterRsrcResourcePointer particleEmitterProps;
-		static btTransform startingTrf;
-
-		static float getRandom(float initial, float deviation);
-		static Vec3 getRandom(const Vec3& initial, const Vec3& deviation);
-};
-
-
-inline ParticleEmitterNode::ParticleEmitterNode(Scene& scene, ulong flags,
-	SceneNode* parent)
-:	SceneNode(SNT_PARTICLE_EMITTER_NODE, scene, flags, parent)
-{}*/
-
-} // end namespace
-
-#endif

+ 26 - 3
include/anki/scene/Renderable.h

@@ -14,7 +14,7 @@ class Transform;
 /// @addtogroup Scene
 /// @{
 
-/// XXX
+/// The ID of a buildin material variable
 enum BuildinMaterialVariableId
 {
 	BMV_NO_BUILDIN = 0,
@@ -22,6 +22,8 @@ enum BuildinMaterialVariableId
 	BMV_MODEL_VIEW_MATRIX,
 	BMV_NORMAL_MATRIX,
 	BMV_BLURRING,
+	BMV_INSTANCING_TRANSLATIONS,
+	BMV_INSTANCING_MODEL_VIEW_PROJECTION_MATRICES,
 	BMV_COUNT
 };
 
@@ -67,10 +69,10 @@ public:
 	virtual ~Renderable();
 
 	/// Access to VAOs
-	virtual const ModelPatchBase& getModelPatchBase() const = 0;
+	virtual const ModelPatchBase& getRenderableModelPatchBase() const = 0;
 
 	/// Access the material
-	virtual const Material& getMaterial() const = 0;
+	virtual const Material& getRenderableMaterial() const = 0;
 
 	/// Information for movables
 	virtual const Transform* getRenderableWorldTransform() const
@@ -78,6 +80,25 @@ public:
 		return nullptr;
 	}
 
+	/// @name Instancing methods
+	/// @{
+
+	virtual Vec3* getRenderableInstancingTranslations() const
+	{
+		return nullptr;
+	}
+
+	virtual Transform* getRenderableInstancingWorldTransforms() const
+	{
+		return nullptr;
+	}
+
+	virtual U32 getRenderableInstancesCount() const
+	{
+		return 0;
+	}
+	/// @}
+
 	/// @name Accessors
 	/// @{
 	RenderableMaterialVariables::iterator getVariablesBegin()
@@ -96,11 +117,13 @@ public:
 	/// @}
 
 protected:
+	/// The derived class needs to call that
 	void init(PropertyMap& pmap);
 
 private:
 	RenderableMaterialVariables vars;
 	Ubo ubo;
+	Ubo instancingUbo;
 };
 /// @}
 

+ 2 - 2
include/anki/scene/SkinNode.h

@@ -181,13 +181,13 @@ public:
 	/// @{
 
 	/// Implements Renderable::getModelPatchBase
-	const ModelPatchBase& getModelPatchBase() const
+	const ModelPatchBase& getRenderableModelPatchBase() const
 	{
 		return *skinModelPatch;
 	}
 
 	/// Implements Renderable::getMaterial
-	const Material& getMaterial() const
+	const Material& getRenderableMaterial() const
 	{
 		return skinModelPatch->getMaterial();
 	}

+ 4 - 0
shaders/IsLpGeneric.glsl

@@ -302,6 +302,10 @@ void main()
 	fColor *= dot(normal, groundLightDir.xyz) + 1.0;
 #endif
 
+#if 0
+	fColor = fColor * 0.5 + normal * 0.5;
+#endif
+
 #if 0
 	if(tiles[vInstanceId].lightsCount[2] > 0)
 	{

+ 3 - 2
src/renderer/Dbg.cpp

@@ -57,7 +57,8 @@ void Dbg::run()
 	drawer->setModelMatrix(Mat4::getIdentity());
 	//drawer->drawGrid();
 
-	for(auto it = scene.getSceneNodesBegin(); it != scene.getSceneNodesEnd(); it++)
+	for(auto it = scene.getSceneNodesBegin();
+		it != scene.getSceneNodesEnd(); it++)
 	{
 		SceneNode* node = *it;
 		Spatial* sp = node->getSpatial();
@@ -72,7 +73,7 @@ void Dbg::run()
 		sceneDrawer->draw(sector->getOctree());
 	}
 
-	scene.getPhysics().debugDraw();
+	/*scene.getPhysics().debugDraw();*/
 
 	drawer->flush();
 }

+ 5 - 5
src/renderer/Drawer.cpp

@@ -62,7 +62,7 @@ struct SetupMaterialVariableVisitor
 		case BMV_MODEL_VIEW_MATRIX:
 			if(!mvMatCalculated)
 			{
-				mvMat = mMat * fr->getViewMatrix();
+				mvMat = fr->getViewMatrix() * mMat;
 				mvMatCalculated = true;
 			}
 			uniSet(*uni, mvMat);
@@ -70,7 +70,7 @@ struct SetupMaterialVariableVisitor
 		case BMV_NORMAL_MATRIX:
 			if(!mvMatCalculated)
 			{
-				mvMat = mMat * fr->getViewMatrix();
+				mvMat = fr->getViewMatrix() * mMat;
 				mvMatCalculated = true;
 			}
 			uniSet(*uni, mvMat.getRotationPart());
@@ -127,7 +127,7 @@ void RenderableDrawer::setupShaderProg(
 	const Frustumable& fr,
 	Renderable& renderable)
 {
-	const Material& mtl = renderable.getMaterial();
+	const Material& mtl = renderable.getRenderableMaterial();
 	const ShaderProgram& sprog = mtl.findShaderProgram(key);
 
 	sprog.bind();
@@ -171,9 +171,9 @@ void RenderableDrawer::render(const Frustumable& fr, uint pass,
 	setupShaderProg(key, fr, renderable);
 
 	// Render
-	U32 indecesCount = renderable.getModelPatchBase().getIndecesCount(0);
+	U32 indecesCount = renderable.getRenderableModelPatchBase().getIndecesCount(0);
 
-	const Vao& vao = renderable.getModelPatchBase().getVao(key);
+	const Vao& vao = renderable.getRenderableModelPatchBase().getVao(key);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
 	vao.bind();
 	glDrawElements(GL_TRIANGLES, indecesCount, GL_UNSIGNED_SHORT, 0);

+ 106 - 0
src/resource/ParticleEmitterResource.cpp

@@ -0,0 +1,106 @@
+#include "anki/resource/ParticleEmitterResource.h"
+#include "anki/resource/Model.h"
+#include "anki/util/Exception.h"
+#include <cstring>
+
+namespace anki {
+
+static const char* errMsg = "Incorrect or missing value ";
+
+#define PE_EXCEPTION(x) ANKI_EXCEPTION("Particle emmiter: " + x)
+
+//==============================================================================
+// ParticleEmitterProperties                                                   =
+//==============================================================================
+
+//==============================================================================
+ParticleEmitterProperties& ParticleEmitterProperties::operator=(
+	const ParticleEmitterProperties& b)
+{
+	memcpy(this, &b, sizeof(ParticleEmitterProperties));
+	return *this;
+}
+
+//==============================================================================
+// ParticleEmitterResource                                                     =
+//==============================================================================
+
+//==============================================================================
+ParticleEmitterResource::ParticleEmitterResource()
+{}
+
+//==============================================================================
+ParticleEmitterResource::~ParticleEmitterResource()
+{}
+
+//==============================================================================
+void ParticleEmitterResource::load(const char* /*filename*/)
+{
+	// dummy load
+	particleLife = 7.0;
+	particleLifeDeviation = 2.0;
+
+	forceDirection = Vec3(0.0, 0.1, 0.0);
+	forceDirectionDeviation = Vec3(0.0, 0.0, 0.0);
+	forceMagnitude = 900.0;
+	forceMagnitudeDeviation = 100.0;
+
+	particleMass = 1.0;
+	particleMassDeviation = 0.0;
+
+	/*gravity = Vec3(0.0, 10.0, 0.0);
+	gravityDeviation = Vec3(0.0, 0.0, 0.0);*/
+
+	startingPos = Vec3(0.0, 1.0, 0.0);
+	startingPosDeviation = Vec3(0.0, 0.0, 0.0);
+	size = 0.5;
+	maxNumOfParticles = 50;
+	emissionPeriod = 1.0;
+	particlesPerEmittion = 1;
+	model.load("data/models/horse/horse.mdl");
+
+	// sanity checks
+	//
+
+	if(particleLife <= 0.0)
+	{
+		throw PE_EXCEPTION(errMsg + "particleLife");
+	}
+
+	if(particleLife - particleLifeDeviation <= 0.0)
+	{
+		throw PE_EXCEPTION(errMsg + "particleLifeDeviation");
+	}
+
+	if(size <= 0.0)
+	{
+		throw PE_EXCEPTION(errMsg + "size");
+	}
+
+	if(maxNumOfParticles < 1)
+	{
+		throw PE_EXCEPTION(errMsg + "maxNumOfParticles");
+	}
+
+	if(emissionPeriod <= 0.0)
+	{
+		throw PE_EXCEPTION(errMsg + "emissionPeriod");
+	}
+
+	if(particlesPerEmittion < 1)
+	{
+		throw PE_EXCEPTION(errMsg + "particlesPerEmittion");
+	}
+
+	// Calc some stuff
+	//
+
+	forceEnabled =
+		(!isZero(forceDirection.getLengthSquared())
+		|| !isZero(forceDirectionDeviation.getLengthSquared()))
+		&& (forceMagnitude != 0.0 || forceMagnitudeDeviation != 0.0);
+
+	wordGravityEnabled = isZero(gravity.getLengthSquared());
+}
+
+} // end namespace anki

+ 0 - 145
src/resource/ParticleEmitterRsrc.cpp

@@ -1,145 +0,0 @@
-#include <cstring>
-#include "anki/resource/ParticleEmitterRsrc.h"
-#include "anki/util/Exception.h"
-
-
-namespace anki {
-
-
-static const char* errMsg = "Incorrect or missing value ";
-
-
-#define PE_EXCEPTION(x) ANKI_EXCEPTION("Particle emmiter: " + x)
-
-
-//==============================================================================
-// Constructor                                                                 =
-//==============================================================================
-ParticleEmitterRsrc::ParticleEmitterRsrc()
-	: particleLife(0.0), particleLifeDeviation(0.0), forceDirection(0.0),
-		forceDirectionDeviation(0.0), forceMagnitude(0.0),
-		forceMagnitudeDeviation(0.0), particleMass(0.0),
-		particleMassDeviation(0.0), gravity(0.0), gravityDeviation(0.0),
-		startingPos(0.0), startingPosDeviation(0.0), size(0.0)
-{}
-
-
-//==============================================================================
-// Constructor [copy]                                                          =
-//==============================================================================
-ParticleEmitterRsrc::ParticleEmitterRsrc(const ParticleEmitterRsrc& a)
-{
-	(*this) = a;
-}
-
-
-//==============================================================================
-// operator=                                                                   =
-//==============================================================================
-ParticleEmitterRsrc& ParticleEmitterRsrc::operator=(
-	const ParticleEmitterRsrc& b)
-{
-	particleLife = b.particleLife;
-	particleLifeDeviation = b.particleLifeDeviation;
-	forceDirection = b.forceDirection;
-	forceDirectionDeviation = b.forceDirectionDeviation;
-	forceMagnitude = b.forceMagnitude;
-	forceMagnitudeDeviation = b.forceMagnitudeDeviation;
-	particleMass = b.particleMass;
-	particleMassDeviation = b.particleMassDeviation;
-	gravity = b.gravity;
-	gravityDeviation = b.gravityDeviation;
-	startingPos = b.startingPos;
-	startingPosDeviation = b.startingPosDeviation;
-	size = b.size;
-	maxNumOfParticles = b.maxNumOfParticles;
-	emissionPeriod = b.emissionPeriod;
-	particlesPerEmittion = b.particlesPerEmittion;
-	modelName = b.modelName;
-
-	return *this;
-}
-
-
-//==============================================================================
-// hasForce                                                                    =
-//==============================================================================
-bool ParticleEmitterRsrc::hasForce() const
-{
-	return (!isZero(forceDirection.getLengthSquared()) ||
-		!isZero(forceDirectionDeviation.getLengthSquared())) &&
-			(forceMagnitude != 0.0 || forceMagnitudeDeviation != 0.0);
-}
-
-
-//==============================================================================
-// usingWorldGrav                                                              =
-//==============================================================================
-bool ParticleEmitterRsrc::usingWorldGrav() const
-{
-	return isZero(gravity.getLengthSquared());
-}
-
-
-//==============================================================================
-// load                                                                        =
-//==============================================================================
-void ParticleEmitterRsrc::load(const char* /*filename*/)
-{
-	// dummy load
-	particleLife = 7.0;
-	particleLifeDeviation = 2.0;
-
-	forceDirection = Vec3(0.0, 0.1, 0.0);
-	forceDirectionDeviation = Vec3(0.0, 0.0, 0.0);
-	forceMagnitude = 900.0;
-	forceMagnitudeDeviation = 100.0;
-
-	particleMass = 1.0;
-	particleMassDeviation = 0.0;
-
-	/*gravity = Vec3(0.0, 10.0, 0.0);
-	gravityDeviation = Vec3(0.0, 0.0, 0.0);*/
-
-	startingPos = Vec3(0.0, 1.0, 0.0);
-	startingPosDeviation = Vec3(0.0, 0.0, 0.0);
-	size = 0.5;
-	maxNumOfParticles = 50;
-	emissionPeriod = 1.0;
-	particlesPerEmittion = 1;
-	modelName = "meshes/horse/horse.mdl";
-
-	// sanity checks
-	if(particleLife <= 0.0)
-	{
-		throw PE_EXCEPTION(errMsg + "particleLife");
-	}
-
-	if(particleLife - particleLifeDeviation <= 0.0)
-	{
-		throw PE_EXCEPTION(errMsg + "particleLifeDeviation");
-	}
-
-	if(size <= 0.0)
-	{
-		throw PE_EXCEPTION(errMsg + "size");
-	}
-
-	if(maxNumOfParticles < 1)
-	{
-		throw PE_EXCEPTION(errMsg + "maxNumOfParticles");
-	}
-
-	if(emissionPeriod <= 0.0)
-	{
-		throw PE_EXCEPTION(errMsg + "emissionPeriod");
-	}
-
-	if(particlesPerEmittion < 1)
-	{
-		throw PE_EXCEPTION(errMsg + "particlesPerEmittion");
-	}
-}
-
-
-} // end namespace

+ 0 - 34
src/scene/Particle.cpp

@@ -1,34 +0,0 @@
-#include "anki/scene/Particle.h"
-#include "anki/physics/RigidBody.h"
-
-
-namespace anki {
-
-/*
-//==============================================================================
-// Constructor                                                                 =
-//==============================================================================
-Particle::Particle(float timeOfDeath_, Scene& scene, ulong flags,
-	SceneNode* parent):
-	ModelNode(scene, flags, parent),
-	timeOfDeath(timeOfDeath_)
-{}
-
-
-//==============================================================================
-// Destructor                                                                  =
-//==============================================================================
-Particle::~Particle()
-{}
-
-
-//==============================================================================
-// setNewRigidBody                                                             =
-//==============================================================================
-void Particle::setNewRigidBody(RigidBody* body_)
-{
-	body.reset(body_);
-}*/
-
-
-} // end namespace

+ 64 - 48
src/scene/ParticleEmitterNode.cpp → src/scene/ParticleEmitter.cpp

@@ -1,41 +1,53 @@
-#include <btBulletCollisionCommon.h>
-#include <btBulletDynamicsCommon.h>
-#include "anki/scene/ParticleEmitterNode.h"
-#include "anki/scene/Particle.h"
-#include "anki/physics/RigidBody.h"
-#include "anki/core/App.h"
-#include "anki/scene/Scene.h"
+#include "anki/scene/ParticleEmitter.h"
+#include "anki/resource/Model.h"
 #include "anki/util/Functions.h"
 
-
 namespace anki {
 
-
-/*btTransform ParticleEmitterNode::startingTrf(toBt(Mat3::getIdentity()),
-	btVector3(10000000.0, 10000000.0, 10000000.0));
-
-
 //==============================================================================
-// Destructor                                                                  =
+// Particle                                                                    =
 //==============================================================================
-ParticleEmitterNode::~ParticleEmitterNode()
+
+//==============================================================================
+Particle::Particle(F32 timeOfDeath_,
+	const char* name, Scene* scene, // Scene
+	U32 movableFlags, Movable* movParent, // Movable
+	PhysWorld* masterContainer, const Initializer& init)
+	: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
+		 RigidBody(masterContainer, init), timeOfDeath(timeOfDeath_)
 {}
 
+//==============================================================================
+Particle::~Particle()
+{}
 
 //==============================================================================
-// getRandom                                                                   =
+// ParticleEmitter                                                             =
+//==============================================================================
+
 //==============================================================================
-float ParticleEmitterNode::getRandom(float initial, float deviation)
+ParticleEmitter::ParticleEmitter(const char* filename,
+	const char* name, Scene* scene, // Scene
+	U32 movableFlags, Movable* movParent) // Movable
+	: SceneNode(name, scene), Spatial(this, &aabb),
+		Movable(movableFlags, movParent, *this)
 {
-	return (deviation == 0.0) ?  initial :
-		initial + Util::randFloat(deviation) * 2.0 - deviation;
+	init(filename);
 }
 
+//==============================================================================
+ParticleEmitter::~ParticleEmitter()
+{}
 
 //==============================================================================
-// getRandom                                                                   =
+F32 ParticleEmitter::getRandom(F32 initial, F32 deviation)
+{
+	return (deviation == 0.0) ? initial
+		: initial + randFloat(deviation) * 2.0 - deviation;
+}
+
 //==============================================================================
-Vec3 ParticleEmitterNode::getRandom(const Vec3& initial, const Vec3& deviation)
+Vec3 ParticleEmitter::getRandom(const Vec3& initial, const Vec3& deviation)
 {
 	if(deviation == Vec3(0.0))
 	{
@@ -44,7 +56,7 @@ Vec3 ParticleEmitterNode::getRandom(const Vec3& initial, const Vec3& deviation)
 	else
 	{
 		Vec3 out;
-		for(int i = 0; i < 3; i++)
+		for(U i = 0; i < 3; i++)
 		{
 			out[i] = getRandom(initial[i], deviation[i]);
 		}
@@ -52,23 +64,33 @@ Vec3 ParticleEmitterNode::getRandom(const Vec3& initial, const Vec3& deviation)
 	}
 }
 
+//==============================================================================
+const ModelPatchBase& ParticleEmitter::getRenderableModelPatchBase() const
+{
+	return *particleEmitterResource->getModel().getModelPatches()[0];
+}
 
 //==============================================================================
-// init                                                                        =
+const Material& ParticleEmitter::getRenderableMaterial() const
+{
+	return
+		particleEmitterResource->getModel().getModelPatches()[0]->getMaterial();
+}
+
 //==============================================================================
-void ParticleEmitterNode::init(const char* filename)
+void ParticleEmitter::init(const char* filename)
 {
-	particleEmitterProps.load(filename);
+	particleEmitterResource.load(filename);
 
 	// copy the resource to me
-	ParticleEmitterRsrc& me = *this;
-	ParticleEmitterRsrc& other = *particleEmitterProps.get();
+	ParticleEmitterProperties& me = *this;
+	const ParticleEmitterProperties& other = *particleEmitterResource;
 	me = other;
 
 	// create the particles
 	collShape.reset(new btSphereShape(size));
 
-	for(uint i = 0; i < maxNumOfParticles; i++)
+	for(U i = 0; i < maxNumOfParticles; i++)
 	{
 		Particle* particle = new Particle(-1.0, getScene(), SNF_NONE, NULL);
 		particle->init(modelName.c_str());
@@ -102,18 +124,17 @@ void ParticleEmitterNode::init(const char* filename)
 	timeLeftForNextEmission = 0.0;
 }
 
-
-//==============================================================================
-// frameUpdate                                                                 =
 //==============================================================================
-void ParticleEmitterNode::frameUpdate(float prevUpdateTime, float crntTime)
+void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 {
+	SceneNode::frameUpdate(prevUpdateTime, crntTime, frame);
+
 	// Opt: We dont have to make extra calculations if the ParticleEmitterNode's
 	// rotation is the identity
-	bool identRot = getWorldTransform().getRotation() == Mat3::getIdentity();
+	Bool identRot = getWorldTransform().getRotation() == Mat3::getIdentity();
 
 	// deactivate the dead particles
-	BOOST_FOREACH(Particle* p, particles)
+	for(Particle* p : particles)
 	{
 		if(p->isDead()) // its already dead so dont deactivate it again
 		{
@@ -123,21 +144,19 @@ void ParticleEmitterNode::frameUpdate(float prevUpdateTime, float crntTime)
 		if(p->getTimeOfDeath() < crntTime)
 		{
 			//cout << "Killing " << i << " " << p.timeOfDeath << endl;
-			p->getRigidBody().setActivationState(DISABLE_SIMULATION);
-			p->getRigidBody().setWorldTransform(startingTrf);
-			p->disableFlag(SceneNode::SNF_ACTIVE);
+			p->setActivationState(DISABLE_SIMULATION);
 			p->setTimeOfDeath(-1.0);
 		}
 	}
 
 	// pre calculate
-	bool forceFlag = hasForce();
-	bool worldGravFlag = usingWorldGrav();
+	Bool forceFlag = particleEmitterResource->hasForce();
+	Bool worldGravFlag = particleEmitterResource->usingWorldGravity();
 
 	if(timeLeftForNextEmission <= 0.0)
 	{
-		uint partNum = 0;
-		BOOST_FOREACH(Particle* pp, particles)
+		U partNum = 0;
+		for(Particle* pp : particles)
 		{
 			Particle& p = *pp;
 			if(!p.isDead())
@@ -148,8 +167,6 @@ void ParticleEmitterNode::frameUpdate(float prevUpdateTime, float crntTime)
 
 			RigidBody& body = p.getRigidBody();
 
-			p.enableFlag(SceneNode::SNF_ACTIVE);
-
 			// life
 			p.setTimeOfDeath(getRandom(crntTime + particleLife,
 				particleLifeDeviation));
@@ -169,8 +186,8 @@ void ParticleEmitterNode::frameUpdate(float prevUpdateTime, float crntTime)
 			// force
 			if(forceFlag)
 			{
-				Vec3 forceDir = getRandom(forceDirection,
-					forceDirectionDeviation);
+				Vec3 forceDir = getRandom(
+					forceDirection, forceDirectionDeviation);
 				forceDir.normalize();
 
 				if(!identRot)
@@ -221,7 +238,6 @@ void ParticleEmitterNode::frameUpdate(float prevUpdateTime, float crntTime)
 	{
 		timeLeftForNextEmission -= crntTime - prevUpdateTime;
 	}
-}*/
-
+}
 
-} // end namespace
+} // end namespace anki

+ 27 - 5
src/scene/Renderable.cpp

@@ -20,8 +20,8 @@ struct CreateNewPropertyVisitor
 	template<typename T>
 	void visit(const T&) const
 	{
-		RenderableMaterialVariable* rvar = new RenderableMaterialVariable(
-			mvar);
+		RenderableMaterialVariable* rvar =
+			new RenderableMaterialVariable(mvar);
 
 		//pmap->addNewProperty(prop);
 		vars->push_back(rvar);
@@ -38,7 +38,9 @@ static Array<const char*, BMV_COUNT - 1> buildinNames = {{
 	"modelViewProjectionMat",
 	"modelViewMat",
 	"normalMat",
-	"blurring"
+	"blurring",
+	"instancingTranslations",
+	"instancingModelViewProjectionMatrices"
 }};
 
 //==============================================================================
@@ -78,7 +80,7 @@ Renderable::~Renderable()
 //==============================================================================
 void Renderable::init(PropertyMap& pmap)
 {
-	const Material& mtl = getMaterial();
+	const Material& mtl = getRenderableMaterial();
 
 	CreateNewPropertyVisitor vis;
 	vis.pmap = &pmap;
@@ -100,7 +102,27 @@ void Renderable::init(PropertyMap& pmap)
 	if(block)
 	{
 		ubo.create(block->getSize(), nullptr);
-		//ubo.setBinding(20);
+	}
+
+	// Init the instancing UBO
+	U32 instancesCount = getRenderableInstancesCount();
+	if(instancesCount > 0)
+	{
+		Vec3* translations;
+		Transform* transforms;
+		U32 size = 0;
+
+		if((translations = getRenderableInstancingTranslations()) != 0)
+		{
+			size = sizeof(Vec3) * instancesCount;
+		}
+		else if((transforms = getRenderableInstancingWorldTransforms()) != 0)
+		{
+			size = sizeof(Mat4) * instancesCount;
+		}
+
+		ANKI_ASSERT(size != 0);
+		instancingUbo.create(size, nullptr);
 	}
 }
 

+ 1 - 0
src/scene/Scene.cpp

@@ -71,6 +71,7 @@ void Scene::update(float prevUpdateTime, float crntTime, Renderer& r)
 	for(SceneNode* n : nodes)
 	{
 		Movable* m = n->getMovable();
+
 		if(m)
 		{
 			m->update();

+ 2 - 2
src/scene/VisibilityTester.cpp

@@ -38,8 +38,8 @@ struct MaterialSortFunctor
 		ANKI_ASSERT(a->getRenderable() != nullptr 
 			&& b->getRenderable() != nullptr);
 
-		return a->getRenderable()->getMaterial() 
-			< b->getRenderable()->getMaterial();
+		return a->getRenderable()->getRenderableMaterial()
+			< b->getRenderable()->getRenderableMaterial();
 	}
 };
 

+ 17 - 15
testapp/Main.cpp

@@ -12,7 +12,6 @@
 #include "anki/resource/Material.h"
 #include "anki/scene/Scene.h"
 #include "anki/resource/SkelAnim.h"
-#include "anki/scene/ParticleEmitterNode.h"
 #include "anki/physics/Character.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/renderer/MainRenderer.h"
@@ -75,34 +74,34 @@ void initPhysics()
 	init.mass = 1;
 	init.shape = colShape;
 	init.group = PhysWorld::CG_PARTICLE;
-	init.mask = PhysWorld::CG_MAP;
+	init.mask = PhysWorld::CG_MAP | PhysWorld::CG_PARTICLE;
 
-	const U ARRAY_SIZE_X = 5;
-	const U ARRAY_SIZE_Y = 5;
-	const U ARRAY_SIZE_Z = 5;
-	const U START_POS_X = -5;
-	const U START_POS_Y = 15;
-	const U START_POS_Z = -3;
+	const I ARRAY_SIZE_X = 5;
+	const I ARRAY_SIZE_Y = 5;
+	const I ARRAY_SIZE_Z = 5;
+	const I START_POS_X = -5;
+	const I START_POS_Y = 35;
+	const I START_POS_Z = -3;
 
 	float start_x = START_POS_X - ARRAY_SIZE_X / 2;
 	float start_y = START_POS_Y;
 	float start_z = START_POS_Z - ARRAY_SIZE_Z / 2;
 
-	for(U k = 0; k < ARRAY_SIZE_Y; k++)
+	for(I k = 0; k < ARRAY_SIZE_Y; k++)
 	{
-		for(U i = 0; i < ARRAY_SIZE_X; i++)
+		for(I i = 0; i < ARRAY_SIZE_X; i++)
 		{
-			for(U j = 0; j < ARRAY_SIZE_Z; j++)
+			for(I j = 0; j < ARRAY_SIZE_Z; j++)
 			{
 				std::string name = std::string("crate0") + std::to_string(i)
 					+ std::to_string(j) + std::to_string(k);
 
-				new ModelNode(
+				ModelNode* mnode = new ModelNode(
 					"data/models/crate0/crate0.mdl",
 					name.c_str(),
 					&SceneSingleton::get(), Movable::MF_NONE, nullptr);
 
-				init.movable = scene.findSceneNode((name + "0").c_str()).getMovable();
+				init.movable = mnode;
 				ANKI_ASSERT(init.movable);
 
 				Transform trf(
@@ -236,13 +235,15 @@ void init()
 	scene.sectors.push_back(new Sector(sectorAabb));
 #endif
 
+#if 1
 	ModelNode* sponzaModel = new ModelNode(
 		"data/maps/sponza/sponza.mdl",
 		"sponza", &scene, Movable::MF_NONE, nullptr);
 
 	(void)sponzaModel;
+#endif
 
-	/*initPhysics();*/
+	initPhysics();
 }
 
 //==============================================================================
@@ -449,8 +450,9 @@ void initSubsystems(int argc, char* argv[])
 	// Main renderer
 	RendererInitializer initializer;
 	initializer.ms.ez.enabled = true;
-	initializer.dbg.enabled = false;
+	initializer.dbg.enabled = true;
 	initializer.is.sm.bilinearEnabled = true;
+	initializer.is.groundLightEnabled = false;
 	initializer.is.sm.enabled = true;
 	initializer.is.sm.pcfEnabled = false;
 	initializer.is.sm.resolution = 512;

+ 8 - 4
tools/dae2anki/dae2anki.py

@@ -90,12 +90,15 @@ def parse_commandline():
 	parser.add_option("-f", "--flip-yz", dest="flip",
 		type="string", default=False, 
 		help="flip Y with Z (from blender to AnKi)")
+	parser.add_option("-m", "--model", dest="export_model",
+		type="string", default=False, 
+		help="create a model file as well")
 	(options, args) = parser.parse_args()
 
 	if not options.inp or not options.out:
 		parser.error("argument is missing")
 
-	return (options.inp, options.out, options.flip)
+	return (options.inp, options.out, options.flip, options.export_model)
 
 def parse_library_geometries(el):
 	geometries = []
@@ -451,7 +454,7 @@ def write_model(meshes, directory, mdl_name):
 	f.close()
 
 def main():
-	(infile, outdir, flip) = parse_commandline()
+	(infile, outdir, flip, export_model) = parse_commandline()
 
 	print("-- Begin...")
 	xml.register_namespace("", "http://www.collada.org/2005/11/COLLADASchema")
@@ -478,8 +481,9 @@ def main():
 		write_mesh(mesh, outdir, flip)
 
 	# Write the model
-	mdl_name = os.path.splitext(os.path.basename(infile))[0]
-	write_model(meshes, outdir, mdl_name)
+	if export_model:
+		mdl_name = os.path.splitext(os.path.basename(infile))[0]
+		write_model(meshes, outdir, mdl_name)
 
 	print("-- Bye!")