Browse Source

Mesh LOD. WIP

Panagiotis Christopoulos Charitos 13 years ago
parent
commit
d17ce21581

+ 10 - 18
include/anki/resource/Mesh.h

@@ -34,19 +34,17 @@ public:
 
 	/// Get info on how to attach a VBO to a VAO
 	virtual void getVboInfo(
-		const VertexAttribute attrib, const U32 lod, const Vbo*& vbo, 
+		const VertexAttribute attrib, const Vbo*& vbo,
 		U32& size, GLenum& type, U32& stride, U32& offset) const = 0;
 
 	virtual U32 getVerticesCount() const = 0;
 
-	virtual U32 getIndicesCount(U32 lod) const = 0;
+	virtual U32 getIndicesCount() const = 0;
 
 	virtual U32 getTextureChannelsCount() const = 0;
 
 	virtual Bool hasWeights() const = 0;
 
-	virtual U32 getLodsCount() const = 0;
-
 	virtual const Obb& getBoundingShape() const = 0;
 };
 
@@ -79,9 +77,9 @@ public:
 		return vertsCount;
 	}
 
-	U32 getIndicesCount(U32 lod) const
+	U32 getIndicesCount() const
 	{
-		return indicesCount[lod];
+		return indicesCount;
 	}
 
 	U32 getTextureChannelsCount() const
@@ -94,34 +92,28 @@ public:
 		return weights;
 	}
 
-	U32 getLodsCount() const
-	{
-		return indicesCount.size();
-	}
-
 	const Obb& getBoundingShape() const
 	{
 		return visibilityShape;
 	}
+
+	void getVboInfo(
+		const VertexAttribute attrib, const Vbo*& vbo,
+		U32& size, GLenum& type, U32& stride, U32& offset) const;
 	/// @}
 
 	/// Load from a file
 	void load(const char* filename);
 
-	/// Implements MeshBase::getVboInfo
-	void getVboInfo(
-		const VertexAttribute attrib, const U32 lod, const Vbo*& vbo, 
-		U32& size, GLenum& type, U32& stride, U32& offset) const;
-
 private:
 	U32 vertsCount;
-	Vector<U32> indicesCount; ///< Indices count per level
+	U32 indicesCount; ///< Indices count per level
 	U32 texChannelsCount;
 	Bool weights;
 	Obb visibilityShape;
 
 	Vbo vbo;
-	Vector<Vbo> indicesVbos;
+	Vbo indicesVbo;
 
 	/// Create the VBOs using the mesh data
 	void createVbos(const MeshLoader& loader);

+ 1 - 6
include/anki/resource/MeshLoader.h

@@ -72,11 +72,6 @@ public:
 
 	/// @name Accessors
 	/// @{
-	U getLodsCount() const
-	{
-		return 1;
-	}
-
 	const Vector<Vec3>& getPositions() const
 	{
 		return vertCoords;
@@ -106,7 +101,7 @@ public:
 		return vertWeights;
 	}
 
-	const Vector<ushort>& getIndices(const U lod) const
+	const Vector<ushort>& getIndices() const
 	{
 		return vertIndeces;
 	}

+ 18 - 16
include/anki/resource/Model.h

@@ -23,7 +23,8 @@ public:
 	virtual ~ModelPatchBase()
 	{}
 
-	virtual const MeshBase& getMeshBase() const = 0;
+	virtual const MeshBase& getMeshBase(const PassLevelKey& key) const = 0;
+	virtual U32 getMeshesCount() const = 0;
 	virtual const Material& getMaterial() const = 0;
 
 	const Vao& getVao(const PassLevelKey& key) const
@@ -34,26 +35,18 @@ public:
 	}
 
 	/// Allias to MeshBase::getIndicesCount()
-	U32 getIndecesCount(const U32 lod) const
+	U32 getIndicesCount(const PassLevelKey& key) const
 	{
-		return getMeshBase().getIndicesCount(lod);
+		return getMeshBase(key).getIndicesCount();
 	}
 
 protected:
 	VaosContainer vaos;
 	PassLevelToVaoMap vaosMap;
 
-	void create()
-	{
-		createVaos(getMaterial(), getMeshBase(), vaos, vaosMap);
-	}
-
 	/// Create VAOs using a material and a mesh. It writes a VaosContainer and
 	/// a hash map
-	static void createVaos(const Material& mtl,
-		const MeshBase& mesh,
-		VaosContainer& vaos,
-		PassLevelToVaoMap& vaosMap);
+	void create();
 
 private:
 	/// Called by @a createVaos multiple times to create and populate a single
@@ -72,16 +65,23 @@ public:
 	/// Map to get the VAO given a PassLod key
 	typedef PassLevelHashMap<Vao> PassLevelToVaoMap;
 
-	ModelPatch(const char* meshFName, const char* mtlFName);
+	ModelPatch(const char* meshFNames[], U32 meshesCount, const char* mtlFName);
 	~ModelPatch();
 
 	/// @name Accessors
 	/// @{
 
 	/// Implements ModelPatchBase::getMeshBase
-	const MeshBase& getMeshBase() const
+	const MeshBase& getMeshBase(const PassLevelKey& key) const
+	{
+		U i = std::min((U32)key.level, (U32)meshes.size());
+		return *meshes[i];
+	}
+
+	/// Implements ModelPatchBase::getMeshesCount
+	U32 getMeshesCount() const
 	{
-		return *mesh;
+		return meshes.size();
 	}
 
 	/// Implements ModelPatchBase::getMaterial
@@ -92,7 +92,7 @@ public:
 	/// @}
 
 private:
-	MeshResourcePointer mesh; ///< The geometry
+	Vector<MeshResourcePointer> meshes; ///< The geometries
 	MaterialResourcePointer mtl; ///< Material
 };
 
@@ -105,6 +105,8 @@ private:
 /// 	<modelPatches>
 /// 		<modelPatch>
 /// 			<mesh>path/to/mesh.mesh</mesh>
+///				[<mesh1>path/to/mesh_lod_1.mesh</mesh1>]
+///				[<mesh2>path/to/mesh_lod_2.mesh</mesh2>]
 /// 			<material>path/to/material.mtl</material>
 /// 		</modelPatch>
 /// 		...

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

@@ -28,11 +28,13 @@ struct ParticleEmitterProperties
 
 		/// Particle size. It is the size of the collision shape
 		F32 size = 1.0;
+		F32 sizeDeviation = 0.0;
 		F32 sizeAnimation = 1.0;
 
 		/// Alpha factor. If the material supports alpha then multiply with 
 		/// this
 		F32 alpha = 1.0;
+		F32 alphaDeviation = 0.0;
 
 		/// Initial force. If not set only the gravity applies
 		Vec3 forceDirection = Vec3(0.0, 1.0, 0.0);

+ 15 - 1
include/anki/resource/ResourcePointer.h

@@ -27,6 +27,12 @@ public:
 		copy(b);
 	}
 
+	/// Move contructor
+	ResourcePointer(Self&& b)
+	{
+		*this = std::move(b);
+	}
+
 	/// Construct and load
 	ResourcePointer(const char* filename)
 	{
@@ -84,6 +90,14 @@ public:
 		return *this;
 	}
 
+	/// Move
+	Self& operator=(Self&& b)
+	{
+		hook = b.hook;
+		b.hook = nullptr;
+		return *this;
+	}
+
 	/// Load the resource using the resource manager
 	void load(const char* filename)
 	{
@@ -124,6 +138,6 @@ private:
 	}
 };
 
-} // end namespace
+} // end namespace anki
 
 #endif

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

@@ -16,6 +16,8 @@ class ParticleEmitter;
 /// XXX Remove SceneNode
 class ParticleBase: public SceneNode, public Movable
 {
+	friend class ParticleEmitter;
+
 public:
 	enum ParticleType
 	{
@@ -99,6 +101,8 @@ public:
 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
+	F32 size = 1.0;
+	F32 alpha = 1.0;
 
 private:
 	ParticleType type;

+ 5 - 11
include/anki/scene/SkinNode.h

@@ -35,9 +35,9 @@ public:
 		return mesh->getVerticesCount();
 	}
 
-	U32 getIndicesCount(U32 lod) const
+	U32 getIndicesCount() const
 	{
-		return mesh->getIndicesCount(lod);
+		return mesh->getIndicesCount();
 	}
 
 	U32 getTextureChannelsCount() const
@@ -50,18 +50,13 @@ public:
 		return false;
 	}
 
-	U32 getLodsCount() const
-	{
-		return mesh->getLodsCount();
-	}
-
 	const Obb& getBoundingShape() const
 	{
 		return mesh->getBoundingShape();
 	}
 
 	void getVboInfo(
-		const VertexAttribute attrib, const U32 lod, const Vbo*& vbo, 
+		const VertexAttribute attrib, const Vbo*& vbo,
 		U32& size, GLenum& type, U32& stride, U32& offset) const;
 	/// @}
 
@@ -129,7 +124,6 @@ private:
 	Vao xfbVao; ///< Used as a source VAO in XFB
 };
 
-
 /// A fragment of the SkinNode
 class SkinPatchNode: public SceneNode, public Movable, public Renderable,
 	public Spatial
@@ -312,8 +306,8 @@ private:
 
 	/// @name Animation stuff
 	/// @{
-	float step;
-	float frame;
+	F32 step;
+	F32 frame;
 	const SkelAnim* anim; ///< The active skeleton animation
 	/// @}
 

+ 1 - 1
src/renderer/Drawer.cpp

@@ -255,7 +255,7 @@ void RenderableDrawer::render(const Frustumable& fr, RenderingStage stage,
 
 	// Render
 	U32 indicesCount = 
-		renderable.getRenderableModelPatchBase().getIndecesCount(0);
+		renderable.getRenderableModelPatchBase().getIndecesCount();
 
 	const Vao& vao = renderable.getRenderableModelPatchBase().getVao(key);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);

+ 11 - 26
src/resource/Mesh.cpp

@@ -15,13 +15,9 @@ void Mesh::load(const char* filename)
 	vertsCount = loader.getPositions().size();
 	ANKI_ASSERT(vertsCount > 0);
 
-	indicesCount.push_back(loader.getLodsCount());
-	for(U lod = 0; lod < indicesCount.size(); lod++)
-	{
-		indicesCount[lod] = loader.getIndices(lod).size();
-		ANKI_ASSERT(indicesCount[lod] > 0);
-		ANKI_ASSERT(indicesCount[lod] % 3 == 0 && "Expecting triangles");
-	}
+	indicesCount = loader.getIndices().size();
+	ANKI_ASSERT(indicesCount > 0);
+	ANKI_ASSERT(indicesCount % 3 == 0 && "Expecting triangles");
 
 	weights = loader.getWeights().size() > 1;
 	texChannelsCount = loader.getTextureChannelsCount();
@@ -95,24 +91,16 @@ void Mesh::createVbos(const MeshLoader& loader)
 		&buff[0],
 		GL_STATIC_DRAW);
 
-	/// Create the indices VBOs
-	indicesVbos.resize(loader.getLodsCount());
-	U lod = 0;
-	for(Vbo& v : indicesVbos)
-	{
-		v.create(
-			GL_ELEMENT_ARRAY_BUFFER,
-			getVectorSizeInBytes(loader.getIndices(lod)),
-			&loader.getIndices(lod)[0],
-			GL_STATIC_DRAW);
-
-		++lod;
-	}
+	/// Create the indices VBO
+	indicesVbo.create(
+		GL_ELEMENT_ARRAY_BUFFER,
+		getVectorSizeInBytes(loader.getIndices()),
+		&loader.getIndices()[0],
+		GL_STATIC_DRAW);
 }
 
 //==============================================================================
-void Mesh::getVboInfo(
-	const VertexAttribute attrib, const U32 lod, const Vbo*& v, U32& size, 
+void Mesh::getVboInfo(const VertexAttribute attrib, const Vbo*& v, U32& size,
 	GLenum& type, U32& stride, U32& offset) const
 {
 	stride = calcVertexSize();
@@ -192,10 +180,7 @@ void Mesh::getVboInfo(
 				+ sizeof(U32) * 4;
 		}
 	case VA_INDICES:
-		if(lod < indicesVbos.size())
-		{
-			v = &indicesVbos[lod];
-		}
+		v = &indicesVbo;
 		break;
 	default:
 		ANKI_ASSERT(0);

+ 53 - 27
src/resource/Model.cpp

@@ -54,7 +54,7 @@ void ModelPatchBase::createVao(const Material& mtl,const MeshBase& meshb,
 			continue;
 		}
 
-		meshb.getVboInfo(attrib.id, (U32)key.level, vbo, size, type,
+		meshb.getVboInfo(attrib.id, vbo, size, type,
 			stride, offset);
 
 		if(vbo == nullptr)
@@ -68,40 +68,38 @@ void ModelPatchBase::createVao(const Material& mtl,const MeshBase& meshb,
 	}
 
 	// The indices VBO
-	meshb.getVboInfo(MeshBase::VA_INDICES, key.level, vbo, size, type,
+	meshb.getVboInfo(MeshBase::VA_INDICES, vbo, size, type,
 			stride, offset);
 
-	if(vbo == nullptr)
-	{
-		// The desired LOD was not found. Use the 0
-		meshb.getVboInfo(MeshBase::VA_INDICES, 0, vbo, size, type,
-			stride, offset);
-	}
-
 	ANKI_ASSERT(vbo != nullptr);
 	vao.attachElementArrayBufferVbo(vbo);
 }
 
 //==============================================================================
-void ModelPatchBase::createVaos(const Material& mtl,
-	const MeshBase& meshb,
-	VaosContainer& vaos,
-	PassLevelToVaoMap& vaosMap)
+void ModelPatchBase::create()
 {
-	vaos.resize(mtl.getLevelsOfDetail() * mtl.getPasses().size());
+	const Material& mtl = getMaterial();
+	U32 meshMaxLod = getMeshesCount() - 1;
+	U32 mtlMaxLod = mtl.getLevelsOfDetail() - 1;
+	U32 maxLod = std::max(meshLods, mtlLods);
+	U i = 0;
+	U passesCount = mtl.getPasses().size();
+
+	vaos.resize(maxLod * passesCount);
 
-	for(U32 level = 0; level < mtl.getLevelsOfDetail(); ++level)
+	for(U32 level = 0; level < maxLod + 1; ++level)
 	{
-		for(U32 pass = 0; pass < mtl.getPasses().size(); ++pass)
+		for(U32 pass = 0; pass < passesCount; ++pass)
 		{
-			PassLevelKey key(pass, level);
+			PassLevelKey meshKey(pass, std::min(level, meshMaxLod));
+			PassLevelKey mtlKey(pass, std::min(level, mtlMaxLod));
 
 			Vao vao;
-			createVao(mtl, meshb, key, vao);
+			createVao(mtl, getMeshBase(meshKey), mtlKey, vao);
 
-			U index = level * mtl.getPasses().size() + pass;
-			vaos[index] = std::move(vao);
-			vaosMap[key] = &vaos[index];
+			vaos[i] = std::move(vao);
+			vaosMap[key] = &vaos[i];
+			++i;
 		}
 	}
 }
@@ -111,10 +109,16 @@ void ModelPatchBase::createVaos(const Material& mtl,
 //==============================================================================
 
 //==============================================================================
-ModelPatch::ModelPatch(const char* meshFName, const char* mtlFName)
+ModelPatch::ModelPatch(const char *meshFNames[], U32 meshesCount,
+	const char* mtlFName)
 {
 	// Load
-	mesh.load(meshFName);
+	ANKI_ASSERT(meshesCount > 0);
+	meshes.resize(meshesCount);
+	for(U32 i = 0; i < meshesCount; i++)
+	{
+		meshes[i].load(meshFNames[i]);
+	}
 	mtl.load(mtlFName);
 
 	/// Create VAOs
@@ -149,30 +153,52 @@ void Model::load(const char* filename)
 		do
 		{
 			XmlElement meshEl = modelPatchEl.getChildElement("mesh");
+			XmlElement meshEl1 = modelPatchEl.getChildElementOptional("mesh1");
+			XmlElement meshEl2 = modelPatchEl.getChildElementOptional("mesh2");
+			Array<const char*, 3> meshesFnames;
+			U meshesCount = 1;
+
+			meshesFnames[0] = meshEl.getText();
+
+			if(meshEl1)
+			{
+				++meshesCount;
+				meshesFnames[1] = meshEl1.getText();
+			}
+
+			if(meshEl2)
+			{
+				++meshesCount;
+				meshesFnames[2] = meshEl2.getText();
+			}
+
 			XmlElement materialEl =
 				modelPatchEl.getChildElement("material");
 
-			ModelPatch* patch = new ModelPatch(meshEl.getText(),
-				materialEl.getText());
+			ModelPatch* patch = new ModelPatch(
+				&meshesFnames[0], meshesCount, materialEl.getText());
 			modelPatches.push_back(patch);
 
 			modelPatchEl = modelPatchEl.getNextSiblingElement("modelPatch");
 		} while(modelPatchEl);
 
+		// Check number of model patches
 		if(modelPatches.size() < 1)
 		{
 			throw ANKI_EXCEPTION("Zero number of model patches");
 		}
 
 		// Calculate compound bounding volume
-		visibilityShape = modelPatches[0]->getMeshBase().getBoundingShape();
+		PassLevelKey key;
+		key.level = 0;
+		visibilityShape = modelPatches[0]->getMeshBase(key).getBoundingShape();
 
 		for(ModelPatchesContainer::const_iterator it = modelPatches.begin() + 1;
 			it != modelPatches.end();
 			++it)
 		{
 			visibilityShape = visibilityShape.getCompoundShape(
-				(*it)->getMeshBase().getBoundingShape());
+				(*it)->getMeshBase(key).getBoundingShape());
 		}
 	}
 	catch(std::exception& e)

+ 2 - 0
src/resource/ParticleEmitterResource.cpp

@@ -130,9 +130,11 @@ void ParticleEmitterResource::loadInternal(const XmlElement& rootel)
 	xmlReadFloat(rootel, "massDeviation", particle.massDeviation);
 
 	xmlReadFloat(rootel, "size", particle.size);
+	xmlReadFloat(rootel, "sizeDeviation", particle.sizeDeviation);
 	xmlReadFloat(rootel, "sizeAnimation", particle.sizeAnimation);
 
 	xmlReadFloat(rootel, "alpha", particle.alpha);
+	xmlReadFloat(rootel, "alphaDeviation", particle.alphaDeviation);
 
 	xmlReadVec3(rootel, "forceDirection", particle.forceDirection);
 	xmlReadVec3(rootel, "forceDirectionDeviation", 

+ 8 - 2
src/resource/Skin.cpp

@@ -71,9 +71,15 @@ void Skin::load(const char* filename)
 		// All meshes should have vert weights
 		for(const ModelPatch* patch : model->getModelPatches())
 		{
-			if(!patch->getMeshBase().hasWeights())
+			for(U i = 0; i < patch->getMeshesCount(); i++)
 			{
-				throw ANKI_EXCEPTION("Mesh does not support HW skinning");
+				PassLevelKey key;
+				key.level = i;
+				const MeshBase& meshBase = patch->getMeshBase(key);
+				if(!meshBase.hasWeights())
+				{
+					throw ANKI_EXCEPTION("Mesh does not support HW skinning");
+				}
 			}
 		}
 	}

+ 11 - 6
src/scene/ParticleEmitter.cpp

@@ -300,9 +300,11 @@ void ParticleEmitter::createParticlesSimulation(Scene* scene)
 			Movable::MF_NONE, nullptr,
 			&scene->getPhysics(), binit);
 
-		particles.push_back(part);
-
+		part->size = getRandom(particle.size, particle.sizeDeviation);
+		part->alpha = getRandom(particle.alpha, particle.alphaDeviation);
 		part->forceActivationState(DISABLE_SIMULATION);
+
+		particles.push_back(part);
 	}
 }
 
@@ -311,11 +313,14 @@ void ParticleEmitter::createParticlesSimpleSimulation(Scene* scene)
 {
 	for(U i = 0; i < maxNumOfParticles; i++)
 	{
-		ParticleSimple* p = new ParticleSimple(
+		ParticleSimple* part = new ParticleSimple(
 			(getName() + std::to_string(i)).c_str(),
 			scene, Movable::MF_NONE, nullptr);
 
-		particles.push_back(p);
+		part->size = getRandom(particle.size, particle.sizeDeviation);
+		part->alpha = getRandom(particle.alpha, particle.alphaDeviation);
+
+		particles.push_back(part);
 	}
 }
 
@@ -365,7 +370,7 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 			Transform trf = p->Movable::getWorldTransform();
 			// XXX set a flag for scale
 			trf.setScale(
-				particle.size + (lifePercent * particle.sizeAnimation));
+				p->size + (lifePercent * particle.sizeAnimation));
 
 			instancingTransformations.push_back(trf);
 
@@ -374,7 +379,7 @@ void ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime, I frame)
 			{
 				alpha.push_back(
 					sin((lifePercent) * getPi<F32>())
-					* particle.alpha);
+					* p->alpha);
 			}
 		}
 	}

+ 4 - 5
src/scene/SkinNode.cpp

@@ -25,11 +25,10 @@ SkinMesh::SkinMesh(const MeshBase* mesh_)
 }
 
 //==============================================================================
-void SkinMesh::getVboInfo(
-	const VertexAttribute attrib, const U32 lod, const Vbo*& v, 
+void SkinMesh::getVboInfo(const VertexAttribute attrib, const Vbo*& v,
 	U32& size, GLenum& type, U32& stride, U32& offset) const
 {
-	mesh->getVboInfo(attrib, lod, v, size, type, stride, offset);
+	mesh->getVboInfo(attrib, v, size, type, stride, offset);
 
 	switch(attrib)
 	{
@@ -73,7 +72,7 @@ SkinModelPatch::SkinModelPatch(const ModelPatch* mpatch_)
 	for(auto a : attribs)
 	{
 		mpatch->getMeshBase().getVboInfo(
-			a, 0, vbo, size, type, stride, offset);
+			a, vbo, size, type, stride, offset);
 
 		ANKI_ASSERT(vbo != nullptr);
 
@@ -83,7 +82,7 @@ SkinModelPatch::SkinModelPatch(const ModelPatch* mpatch_)
 	}
 
 	// The indices VBO
-	mpatch->getMeshBase().getVboInfo(MeshBase::VA_INDICES, 0, vbo, size, type,
+	mpatch->getMeshBase().getVboInfo(MeshBase::VA_INDICES, vbo, size, type,
 			stride, offset);
 	ANKI_ASSERT(vbo != nullptr);
 	xfbVao.attachElementArrayBufferVbo(vbo);