Pārlūkot izejas kodu

Particle system rework. Needs more things

Panagiotis Christopoulos Charitos 12 gadi atpakaļ
vecāks
revīzija
205a1f540f

+ 3 - 3
include/anki/resource/ParticleEmitterResource.h

@@ -84,16 +84,16 @@ public:
 		return *this;
 	}
 
-	const Model& getModel() const
+	const Material& getMaterial() const
 	{
-		return *model;
+		return *material;
 	}
 
 	/// Load it
 	void load(const char* filename);
 
 private:
-	ModelResourcePointer model;
+	MaterialResourcePointer material;
 
 	void loadInternal(const XmlElement& el);
 };

+ 26 - 31
include/anki/scene/ParticleEmitter.h

@@ -10,12 +10,9 @@
 
 namespace anki {
 
-#if 0
-
 class ParticleEmitter;
 
 /// Particle base
-/// XXX Remove SceneNode
 class ParticleBase
 {
 	friend class ParticleEmitter;
@@ -85,6 +82,8 @@ public:
 		(void)crntTime;
 	}
 
+	virtual const Vec3& getPosition() const = 0;
+
 protected:
 	F32 timeOfBirth; ///< Keep the time of birth for nice effects
 	F32 timeOfDeath = -1.0; ///< Time of death. If < 0.0 then dead. In seconds
@@ -99,13 +98,18 @@ private:
 class ParticleSimple: public ParticleBase
 {
 public:
-	ParticleSimple(
-		const char* name, SceneGraph* scene); // SceneNode
+	ParticleSimple();
 
 	void revive(const ParticleEmitter& pe,
-		F32 prevUpdateTime, F32 crntTime);
+		F32 prevUpdateTime, F32 crntTime) override;
 
-	void simulate(const ParticleEmitter& pe, F32 prevUpdateTime, F32 crntTime);
+	void simulate(const ParticleEmitter& pe, F32 prevUpdateTime, 
+		F32 crntTime) override;
+
+	const Vec3& getPosition() const
+	{
+		return position;
+	}
 
 private:
 	/// The velocity
@@ -159,8 +163,11 @@ public:
 	/// @name SceneNode virtuals
 	/// @{
 
-	/// Override SceneNode::frameUpdate()
-	void frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame);
+	void frameUpdate(F32 prevUpdateTime, F32 crntTime, 
+		SceneNode::UpdateType uptype) override;
+
+	void componentUpdated(SceneComponent& comp, 
+		SceneComponent::UpdateType) override;
 	/// @}
 
 	/// @name RenderComponent virtuals
@@ -169,33 +176,26 @@ public:
 	/// Implements RenderComponent::getRenderingData
 	void getRenderingData(
 		const PassLodKey& key, 
+		const U8* subMeshIndicesArray, U subMeshIndicesCount,
 		const Vao*& vao, const ShaderProgram*& prog,
-		const U32* subMeshIndicesArray, U subMeshIndicesCount,
 		Drawcall& drawcall);
 
 	/// Implements  RenderComponent::getMaterial
 	const Material& getMaterial();
 
-	/// Overrides RenderComponent::getRenderWorldTransforms
-	const Transform* getRenderWorldTransforms() override
+	/// Overrides RenderComponent::getRenderWorldTransform
+	void getRenderWorldTransform(U index, Transform& trf) override
 	{
-		return &(*instancingTransformations)[0];
+		ANKI_ASSERT(index < 1);
+		trf = getWorldTransform();
 	}
 
-	/// Overrides RenderComponent::getRenderInstancesCount
-	U32 getRenderInstancesCount()
+	Bool getHasWorldTransforms() override
 	{
-		return instancesCount;
+		return true;
 	}
 	/// @}
 
-	/// @name MoveComponent virtuals
-	/// @{
-
-	/// Overrides MoveComponent::moveUpdate. Calculates an optimization
-	void moveUpdate();
-	/// @}
-
 private:
 	ParticleEmitterResourcePointer particleEmitterResource;
 	btCollisionShape* collShape = nullptr;
@@ -207,20 +207,15 @@ private:
 	// rotation is the identity
 	Bool identityRotation = true;
 
-	U32 instancesCount; ///< AKA alive count
+	U32 aliveParticlesCount;
 
-	/// The transformations. Calculated on frameUpdate() and consumed on
-	/// rendering.
-	SceneFrameVector<Transform>* instancingTransformations;
-
-	RenderComponentVariable* alphaRenderComponentVar = nullptr;
+	Vao vao; ///< Hold the VBO
+	Vbo vbo; ///< Hold the vertex data
 
 	void createParticlesSimulation(SceneGraph* scene);
 	void createParticlesSimpleSimulation(SceneGraph* scene);
 };
 
-#endif
-
 } // end namespace anki
 
 #endif

+ 4 - 2
shaders/BsCommonVert.glsl

@@ -3,8 +3,10 @@
 #define DEFAULT_FLOAT_PRECISION mediump
 #pragma anki include "shaders/MsBsCommon.glsl"
 
-layout(location = 0) in vec3 position;
-layout(location = 3) in vec2 texCoord;
+layout(location = POSITION_LOCATION) in vec3 position;
+layout(location = TEXTURE_COORDINATE_LOCATION) in vec2 texCoord;
+layout(location = SCALE_LOCATION) in float scale;
+layout(location = ALPHA_LOCATION) in float alpha;
 
 /// @name Varyings
 /// @{

+ 9 - 0
shaders/Common.glsl

@@ -19,4 +19,13 @@ precision DEFAULT_FLOAT_PRECISION int;
 #define textureFai(tex_, texc_) texture(tex_, texc_)
 //#define textureFai(tex_, texc_) textureLod(tex_, texc_, 0.0)
 
+#define POSITION_LOCATION 0
+#define NORMAL_LOCATION 1
+#define TANGENT_LOCATION 2
+#define TEXTURE_COORDINATE_LOCATION 3
+#define TEXTURE_COORDINATE_LOCATION_1 4
+#define TEXTURE_COORDINATE_LOCATION_2 5
+#define SCALE_LOCATION 6
+#define ALPHA_LOCATION 7
+
 #endif

+ 4 - 4
shaders/MsCommonVert.glsl

@@ -2,15 +2,15 @@
 
 /// @name Attributes
 /// @{
-layout(location = 0) in highp vec3 position;
-layout(location = 3) in mediump vec2 texCoord;
+layout(location = POSITION_LOCATION) in highp vec3 position;
+layout(location = TEXTURE_COORDINATE_LOCATION) in mediump vec2 texCoord;
 
 #if PASS_COLOR || TESSELLATION
-layout(location = 1) in mediump vec3 normal;
+layout(location = NORMAL_LOCATION) in mediump vec3 normal;
 #endif
 
 #if PASS_COLOR
-layout(location = 2) in mediump vec4 tangent;
+layout(location = TANGENT_LOCATION) in mediump vec4 tangent;
 #endif
 /// @}
 

+ 2 - 2
src/resource/ParticleEmitterResource.cpp

@@ -157,8 +157,8 @@ void ParticleEmitterResource::loadInternal(const XmlElement& rootel)
 	xmlReadU(rootel, "usePhysicsEngine", u);
 	usePhysicsEngine = u;
 
-	XmlElement el = rootel.getChildElement("model");
-	model.load(el.getText());
+	XmlElement el = rootel.getChildElement("material");
+	material.load(el.getText());
 
 	// sanity checks
 	//

+ 75 - 68
src/scene/ParticleEmitter.cpp

@@ -3,12 +3,11 @@
 #include "anki/resource/Model.h"
 #include "anki/util/Functions.h"
 #include "anki/physics/PhysicsWorld.h"
+#include "anki/gl/Drawcall.h"
 #include <limits>
 
 namespace anki {
 
-#if 0
-
 //==============================================================================
 // Misc                                                                        =
 //==============================================================================
@@ -45,9 +44,7 @@ Vec3 getRandom(const Vec3& initial, const Vec3& deviation)
 //==============================================================================
 ParticleBase::ParticleBase(ParticleType type_)
 	: type(type_)
-{
-	sceneNodeProtected.moveC = this;
-}
+{}
 
 //==============================================================================
 ParticleBase::~ParticleBase()
@@ -211,14 +208,14 @@ ParticleEmitter::ParticleEmitter(
 	const char* name, SceneGraph* scene,
 	const char* filename)
 	:	SceneNode(name, scene),
-		SpatialComponent(this, &aabb),
+		SpatialComponent(this),
 		MoveComponent(this),
 		RenderComponent(this),
 		particles(getSceneAllocator())
 {
-	addComponent(static_cast<MoveComponent>(this));
-	addComponent(static_cast<SpatialComponent>(this));
-	addComponent(static_cast<RenderComponent>(this));
+	addComponent(static_cast<MoveComponent*>(this));
+	addComponent(static_cast<SpatialComponent*>(this));
+	addComponent(static_cast<RenderComponent*>(this));
 
 	// Load resource
 	particleEmitterResource.load(filename);
@@ -239,58 +236,76 @@ ParticleEmitter::ParticleEmitter(
 	}
 
 	timeLeftForNextEmission = 0.0;
-	instancesCount = particles.size();
 	RenderComponent::init();
 
-	// Find the "alpha" material variable
-	for(auto it = RenderComponent::getVariablesBegin();
-		it != RenderComponent::getVariablesEnd(); ++it)
-	{
-		if((*it)->getName() == "alpha")
-		{
-			alphaRenderComponentVar = *it;
-		}
-	}
+	// Create the vertex buffer and object
+	//
+	const U components = 3 + 1 + 1;
+	PtrSize vertSize = components * sizeof(F32);
+
+	vbo.create(GL_ARRAY_BUFFER, maxNumOfParticles * vertSize,
+		nullptr, GL_DYNAMIC_DRAW);
+
+	vao.create();
+	// Position
+	vao.attachArrayBufferVbo(&vbo, 0, 3, GL_FLOAT, GL_FALSE, vertSize, 0);
+
+	// Scale
+	vao.attachArrayBufferVbo(&vbo, 6, 1, GL_FLOAT, GL_FALSE, vertSize, 
+		sizeof(F32) * 3);
+
+	// Alpha
+	vao.attachArrayBufferVbo(&vbo, 7, 1, GL_FLOAT, GL_FALSE, vertSize, 
+		sizeof(F32) * 4);
 }
 
 //==============================================================================
 ParticleEmitter::~ParticleEmitter()
 {
-	for(ParticleBase* part : particles)
+	// XXX delete particles
+	/*for(ParticleBase* part : particles)
 	{
 		getSceneGraph().deleteSceneNode(part);
 	}
 
-	getSceneAllocator().deleteInstance(collShape);
+	getSceneAllocator().deleteInstance(collShape);*/
 }
 
 //==============================================================================
 void ParticleEmitter::getRenderingData(
 	const PassLodKey& key, 
-	const Vao*& vao, const ShaderProgram*& prog,
-	const U32* subMeshIndicesArray, U subMeshIndicesCount,
-	Array<U32, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesCountArray,
-	Array<const void*, ANKI_MAX_MULTIDRAW_PRIMITIVES>& indicesOffsetArray, 
-	U32& drawcallCount) const
+	const U8* subMeshIndicesArray, U subMeshIndicesCount,
+	const Vao*& vao_, const ShaderProgram*& prog,
+	Drawcall& dc)
 {
-	particleEmitterResource->getModel().getModelPatches()[0]->
-		getRenderingDataSub(key, vao, prog, 
-		subMeshIndicesArray, subMeshIndicesCount, 
-		indicesCountArray, indicesOffsetArray, drawcallCount);
+	vao_ = &vao;
+	prog = &getMaterial().findShaderProgram(key);
+
+	dc.primitiveType = GL_POINTS;
+	dc.indicesType = 0;
+
+	dc.instancesCount = 1;
+	dc.drawCount = 1;
+
+	dc.count = aliveParticlesCount;
+	dc.offset = 0;
 }
 
 //==============================================================================
 const Material& ParticleEmitter::getMaterial()
 {
-	return
-		particleEmitterResource->getModel().getModelPatches()[0]->getMaterial();
+	return particleEmitterResource->getMaterial();
 }
 
 //==============================================================================
-void ParticleEmitter::moveUpdate()
+void ParticleEmitter::componentUpdated(SceneComponent& comp, 
+	SceneComponent::UpdateType)
 {
-	identityRotation =
-		getWorldTransform().getRotation() == Mat3::getIdentity();
+	if(comp.getType() == MoveComponent::getGlobType())
+	{
+		identityRotation =
+			getWorldTransform().getRotation() == Mat3::getIdentity();
+	}
 }
 
 //==============================================================================
@@ -328,9 +343,8 @@ void ParticleEmitter::createParticlesSimpleSimulation(SceneGraph* scene)
 {
 	for(U i = 0; i < maxNumOfParticles; i++)
 	{
-		ParticleSimple* part;
-		
-		getSceneGraph().newSceneNode(part, nullptr);
+		ParticleSimple* part = 
+			getSceneAllocator().newInstance<ParticleSimple>();
 
 		part->size = getRandom(particle.size, particle.sizeDeviation);
 		part->alpha = getRandom(particle.alpha, particle.alphaDeviation);
@@ -340,25 +354,28 @@ void ParticleEmitter::createParticlesSimpleSimulation(SceneGraph* scene)
 }
 
 //==============================================================================
-void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
+void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, 
+	SceneNode::UpdateType uptype)
 {
+	if(uptype != SceneNode::ASYNC_UPDATE)
+	{
+		return;
+	}
+
 	// - Deactivate the dead particles
 	// - Calc the AABB
 	// - Calc the instancing stuff
 	//
 	Vec3 aabbmin(std::numeric_limits<F32>::max());
 	Vec3 aabbmax(-std::numeric_limits<F32>::max());
-
-	// Create the transformations vector
-	instancingTransformations = getSceneFrameAllocator().
-		newInstance<SceneFrameVector<Transform>>(getSceneFrameAllocator());
-
-	instancingTransformations->reserve(particles.size());
+	aliveParticlesCount = 0;
 
 	// Create the alpha vectors
 	SceneFrameVector<F32> alpha(getSceneFrameAllocator());
 	alpha.reserve(particles.size());
 
+	F32* verts = (F32*)vbo.map(GL_MAP_WRITE_BIT);
+
 	for(ParticleBase* p : particles)
 	{
 		if(p->isDead())
@@ -378,8 +395,7 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 			p->simulate(*this, prevUpdateTime, crntTime);
 
 			// An alive
-			const Vec3& origin = 
-				p->MoveComponent::getWorldTransform().getOrigin();
+			const Vec3& origin = p->getPosition();
 
 			for(U i = 0; i < 3; i++)
 			{
@@ -390,25 +406,24 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 			F32 lifePercent = (crntTime - p->getTimeOfBirth())
 				/ (p->getTimeOfDeath() - p->getTimeOfBirth());
 
-			Transform trf = p->MoveComponent::getWorldTransform();
-			// XXX set a flag for scale
-			trf.setScale(
-				p->size + (lifePercent * particle.sizeAnimation));
+			verts[0] = origin.x();
+			verts[1] = origin.y();
+			verts[2] = origin.z();
 
-			instancingTransformations->push_back(trf);
+			// XXX set a flag for scale
+			verts[3] = p->size + (lifePercent * particle.sizeAnimation);
 
 			// Set alpha
-			if(alphaRenderComponentVar)
-			{
-				alpha.push_back(
-					sin((lifePercent) * getPi<F32>())
-					* p->alpha);
-			}
+			verts[4] = sin((lifePercent) * getPi<F32>()) * p->alpha;
+
+			++aliveParticlesCount;
+			verts += 4;
 		}
 	}
 
-	instancesCount = instancingTransformations->size();
-	if(instancesCount != 0)
+	vbo.unmap();
+
+	if(aliveParticlesCount != 0)
 	{
 		aabb = Aabb(aabbmin - particle.size, aabbmax + particle.size);
 	}
@@ -418,12 +433,6 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 	}
 	SpatialComponent::markForUpdate();
 
-	if(alphaRenderComponentVar)
-	{
-		alphaRenderComponentVar->setValues(
-			&alpha[0], alpha.size(), getSceneAllocator());
-	}
-
 	//
 	// Emit new particles
 	//
@@ -457,6 +466,4 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 	}
 }
 
-#endif
-
 } // end namespace anki