Jelajahi Sumber

Implementation of LOD is feature complete

Panagiotis Christopoulos Charitos 13 tahun lalu
induk
melakukan
1c98fa0297

+ 3 - 1
include/anki/renderer/Drawer.h

@@ -9,6 +9,7 @@ class PassLevelKey;
 class Renderer;
 class Frustumable;
 class Renderable;
+class ShaderProgram;
 
 /// It includes all the functions to render a Renderable
 class RenderableDrawer
@@ -30,7 +31,7 @@ public:
 	void prepareDraw()
 	{}
 
-	void render(const Frustumable& fr,
+	void render(Frustumable& fr,
 		RenderingStage stage, U32 pass, Renderable& renderable);
 
 private:
@@ -39,6 +40,7 @@ private:
 	void setupShaderProg(
 		const PassLevelKey& key,
 		const Frustumable& fr,
+		const ShaderProgram& prog,
 		Renderable& renderable);
 };
 

+ 1 - 1
include/anki/renderer/Renderer.h

@@ -90,7 +90,7 @@ struct RendererInitializer
 	U32 width;
 	U32 height;
 	F32 renderingQuality = 1.0; ///< Applies only to MainRenderer
-	F32 lodDistance; ///< Distance that used to calculate the LOD
+	F32 lodDistance = 10.0; ///< Distance that used to calculate the LOD
 
 	// funcs
 	RendererInitializer()

+ 1 - 0
include/anki/resource/Material.h

@@ -354,6 +354,7 @@ public:
 
 	const ShaderProgram& findShaderProgram(const PassLevelKey& key) const
 	{
+		ANKI_ASSERT(eSProgs.find(key) != eSProgs.end());
 		return *eSProgs.at(key);
 	}
 

+ 13 - 14
include/anki/resource/Model.h

@@ -10,6 +10,9 @@
 
 namespace anki {
 
+// Forward
+class ShaderProgram;
+
 /// Model patch interface class. Its very important class and it binds the
 /// material with the mesh
 class ModelPatchBase
@@ -27,22 +30,19 @@ public:
 	virtual U32 getMeshesCount() const = 0;
 	virtual const Material& getMaterial() const = 0;
 
-	const Vao& getVao(const PassLevelKey& key) const
+	const Obb& getBoundingShape() const
 	{
-		PassLevelToVaoMap::const_iterator it = vaosMap.find(key);
-		ANKI_ASSERT(it != vaosMap.end());
-		return *(it->second);
+		PassLevelKey key(0, 0);
+		return getMeshBase(key).getBoundingShape();
 	}
 
-	/// Allias to MeshBase::getIndicesCount()
-	U32 getIndicesCount(const PassLevelKey& key) const
-	{
-		return getMeshBase(key).getIndicesCount();
-	}
+	/// Given a pass lod key retrieve variables useful for rendering
+	void getRenderingData(const PassLevelKey& key, const Vao*& vao,
+		const ShaderProgram*& prog, U32& indicesCount) const;
 
 protected:
+	/// Array [lod][pass]
 	VaosContainer vaos;
-	PassLevelToVaoMap vaosMap;
 
 	/// Create VAOs using a material and a mesh. It writes a VaosContainer and
 	/// a hash map
@@ -51,9 +51,9 @@ protected:
 private:
 	/// Called by @a createVaos multiple times to create and populate a single
 	/// VAO
-	static void createVao(const Material& mtl,
+	static void createVao(
+		const ShaderProgram &prog,
 		const MeshBase& mesh,
-		const PassLevelKey& key,
 		Vao& vao);
 };
 
@@ -74,8 +74,7 @@ public:
 	/// Implements ModelPatchBase::getMeshBase
 	const MeshBase& getMeshBase(const PassLevelKey& key) const
 	{
-		U i = std::min((U32)key.level, (U32)meshes.size());
-		return *meshes[i];
+		return *meshes[key.level];
 	}
 
 	/// Implements ModelPatchBase::getMeshesCount

+ 8 - 2
include/anki/scene/ModelNode.h

@@ -59,7 +59,7 @@ public:
 	void movableUpdate()
 	{
 		Movable::movableUpdate();
-		obb = modelPatch->getMeshBase().getBoundingShape().getTransformed(
+		obb = modelPatch->getBoundingShape().getTransformed(
 			getWorldTransform());
 		spatialMarkUpdated();
 	}
@@ -85,6 +85,12 @@ public:
 	{
 		return &getWorldTransform();
 	}
+
+	/// Overrides Renderable::getRenderableOrigin
+	Vec3 getRenderableOrigin() const
+	{
+		return getWorldTransform().getOrigin();
+	}
 	/// @}
 
 private:
@@ -147,6 +153,6 @@ private:
 	ModelPatchNodes patches;
 };
 
-} // end namespace
+} // end namespace anki
 
 #endif

+ 8 - 2
include/anki/scene/ParticleEmitter.h

@@ -216,16 +216,22 @@ public:
 	const Material& getRenderableMaterial() const;
 
 	/// Overrides Renderable::getRenderableWorldTransforms
-	virtual const Transform* getRenderableWorldTransforms() const
+	const Transform* getRenderableWorldTransforms() const
 	{
 		return &instancingTransformations[0];
 	}
 
 	/// Overrides Renderable::getRenderableInstancesCount
-	virtual U32 getRenderableInstancesCount() const
+	U32 getRenderableInstancesCount() const
 	{
 		return instancesCount;
 	}
+
+	/// Overrides Renderable::getRenderableOrigin
+	Vec3 getRenderableOrigin() const
+	{
+		return getWorldTransform().getOrigin();
+	}
 	/// @}
 
 	/// @name Movable virtuals

+ 4 - 1
include/anki/scene/Renderable.h

@@ -165,12 +165,15 @@ public:
 		return nullptr;
 	}
 
-	/// Used for instancing
+	/// Number of instances. If greater than 1 then it's instanced
 	virtual U32 getRenderableInstancesCount() const
 	{
 		return 1;
 	}
 
+	/// XXX
+	virtual Vec3 getRenderableOrigin() const = 0;
+
 	/// @name Accessors
 	/// @{
 	RenderableVariables::iterator getVariablesBegin()

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

@@ -89,27 +89,31 @@ public:
 
 	/// @name Accessors
 	/// @{
-	SkinMesh& getSkinMesh()
+	SkinMesh& getSkinMesh(const PassLevelKey& key)
 	{
-		return *skinMesh;
+		return *skinMeshes[key.level];
 	}
-
-	const SkinMesh& getSkinMesh() const
+	const SkinMesh& getSkinMesh(const PassLevelKey& key) const
 	{
-		return *skinMesh;
+		return *skinMeshes[key.level];
 	}
 
-	const Vao& getTransformFeedbackVao() const
+	const Vao& getTransformFeedbackVao(const PassLevelKey& key) const
 	{
-		return xfbVao;
+		return xfbVaos[key.level];
 	}
 	/// @}
 
 	/// @name Implementations of ModelPatchBase virtuals
 	/// @{
-	const MeshBase& getMeshBase() const
+	const MeshBase& getMeshBase(const PassLevelKey& key) const
+	{
+		return *skinMeshes[key.level];
+	}
+
+	U32 getMeshesCount() const
 	{
-		return *skinMesh;
+		return skinMeshes.size();
 	}
 
 	const Material& getMaterial() const
@@ -119,9 +123,9 @@ public:
 	/// @}
 
 private:
-	std::unique_ptr<SkinMesh> skinMesh;
+	PtrVector<SkinMesh> skinMeshes;
 	const ModelPatch* mpatch;
-	Vao xfbVao; ///< Used as a source VAO in XFB
+	Vector<Vao> xfbVaos; ///< Used as a source VAO in XFB
 };
 
 /// A fragment of the SkinNode
@@ -191,6 +195,12 @@ public:
 	{
 		return &getWorldTransform();
 	}
+
+	/// Overrides Renderable::getRenderableOrigin
+	Vec3 getRenderableOrigin() const
+	{
+		return getWorldTransform().getOrigin();
+	}
 	/// @}
 
 private:

+ 1 - 1
src/gl/ShaderProgram.cpp

@@ -740,7 +740,7 @@ void ShaderProgram::initUniformBlocks()
 		block.name.shrink_to_fit();
 
 		// Index
-		ANKI_ASSERT(glGetUniformBlockIndex(glId, name) == i);
+		ANKI_ASSERT(glGetUniformBlockIndex(glId, &name[0]) == i);
 		block.index = i;
 
 		// Size

+ 47 - 37
src/renderer/Drawer.cpp

@@ -14,12 +14,12 @@ namespace anki {
 /// Visitor that sets a uniform
 struct SetupRenderableVariableVisitor
 {
-	PassLevelKey key;
 	const Frustumable* fr = nullptr;
 	Renderer* r = nullptr;
 	Renderable* renderable = nullptr;
 	Array<U8, RenderableDrawer::UNIFORM_BLOCK_MAX_SIZE> clientBlock;
 	RenderableVariable* rvar = nullptr;
+	const ShaderProgramUniformVariable* uni;
 
 	/// Set a uniform in a client block
 	template<typename T>
@@ -32,13 +32,6 @@ struct SetupRenderableVariableVisitor
 	template<typename TRenderableVariableTemplate>
 	void visit(TRenderableVariableTemplate& x)
 	{
-		const ShaderProgramUniformVariable* uni =
-			x.tryFindShaderProgramUniformVariable(key);
-		if(!uni)
-		{
-			return;
-		}
-
 		const U32 instancesCount = renderable->getRenderableInstancesCount();
 		const U32 uniArrSize = uni->getSize();
 		const U32 size = std::min(instancesCount, uniArrSize);
@@ -49,7 +42,7 @@ struct SetupRenderableVariableVisitor
 		const Mat4& vp = fr->getViewProjectionMatrix();
 		const Mat4& v = fr->getViewMatrix();
 
-		const U maxInstances = 32; // XXX Use a proper vector with allocator
+		const U32 maxInstances = 32;
 
 		switch(x.getBuildinId())
 		{
@@ -172,34 +165,42 @@ void SetupRenderableVariableVisitor::uniSet<TextureResourcePointer>(
 }
 
 //==============================================================================
-void RenderableDrawer::setupShaderProg(
-	const PassLevelKey& key,
-	const Frustumable& fr,
+void RenderableDrawer::setupShaderProg(const PassLevelKey& key_,
+	const Frustumable& fr, const ShaderProgram &prog,
 	Renderable& renderable)
 {
-	const Material& mtl = renderable.getRenderableMaterial();
-	const ShaderProgram& sprog = mtl.findShaderProgram(key);
-
-	sprog.bind();
+	prog.bind();
 	
 	SetupRenderableVariableVisitor vis;
 
 	vis.fr = &fr;
-	vis.key = key;
 	vis.renderable = &renderable;
 	vis.r = r;
 
+	PassLevelKey key(key_.pass,
+		std::min(key_.level,
+		U8(renderable.getRenderableMaterial().getLevelsOfDetail() - 1)));
+
 	// Set the uniforms
 	for(auto it = renderable.getVariablesBegin();
 		it != renderable.getVariablesEnd(); ++it)
 	{
 		RenderableVariable* rvar = *it;
-		vis.rvar = rvar;
-		rvar->acceptVisitor(vis);
+
+		const ShaderProgramUniformVariable* uni =
+			rvar->tryFindShaderProgramUniformVariable(key);
+
+		if(uni)
+		{
+			vis.rvar = rvar;
+			vis.uni = uni;
+			rvar->acceptVisitor(vis);
+		}
 	}
 
 	// Write the block
-	const ShaderProgramUniformBlock* block = mtl.getCommonUniformBlock();
+	const ShaderProgramUniformBlock* block =
+		renderable.getRenderableMaterial().getCommonUniformBlock();
 	if(block)
 	{
 		ANKI_ASSERT(block->getSize() <= UNIFORM_BLOCK_MAX_SIZE);
@@ -210,9 +211,18 @@ void RenderableDrawer::setupShaderProg(
 }
 
 //==============================================================================
-void RenderableDrawer::render(const Frustumable& fr, RenderingStage stage,
+void RenderableDrawer::render(Frustumable& fr, RenderingStage stage,
 	U32 pass, Renderable& renderable)
 {
+	/* Instancing */
+	U32 instancesCount = renderable.getRenderableInstancesCount();
+
+	if(instancesCount < 1)
+	{
+		return;
+	}
+
+	/* Blending */
 	const Material& mtl = renderable.getRenderableMaterial();
 
 	Bool blending = mtl.isBlendingEnabled();
@@ -237,29 +247,29 @@ void RenderableDrawer::render(const Frustumable& fr, RenderingStage stage,
 
 	GlStateSingleton::get().enable(GL_BLEND, blending);
 
-	/*float dist = (node.getWorldTransform().getOrigin() -
-		cam.getWorldTransform().getOrigin()).getLength();
-	uint lod = std::min(r.calculateLod(dist), mtl.getLevelsOfDetail() - 1);*/
+	// Calculate the LOD
+	Vec3 camPos =
+		fr.getSceneNode().getMovable()->getWorldTransform().getOrigin();
 
-	U32 instancesCount = renderable.getRenderableInstancesCount();
+	F32 dist = (renderable.getRenderableOrigin() - camPos).getLength();
+	U8 lod = r->calculateLod(dist);
 
-	if(instancesCount < 1)
-	{
-		return;
-	}
+	PassLevelKey key(pass, lod);
+
+	// Get rendering useful stuff
+	const ShaderProgram* prog;
+	const Vao* vao;
+	U32 indicesCount;
 
-	PassLevelKey key(pass, 0);
+	renderable.getRenderableModelPatchBase().getRenderingData(
+		key, vao, prog, indicesCount);
 
 	// Setup shader
-	setupShaderProg(key, fr, renderable);
+	setupShaderProg(key, fr, *prog, renderable);
 
 	// Render
-	U32 indicesCount = 
-		renderable.getRenderableModelPatchBase().getIndecesCount();
-
-	const Vao& vao = renderable.getRenderableModelPatchBase().getVao(key);
-	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
-	vao.bind();
+	ANKI_ASSERT(vao->getAttachmentsCount() > 1);
+	vao->bind();
 
 	if(instancesCount == 1)
 	{

+ 57 - 15
src/resource/Model.cpp

@@ -31,13 +31,11 @@ static const Array<Attrib, MeshBase::VA_COUNT - 1> attribs = {{
 }};
 
 //==============================================================================
-void ModelPatchBase::createVao(const Material& mtl,const MeshBase& meshb,
-	const PassLevelKey& key, Vao& vao)
+void ModelPatchBase::createVao(const ShaderProgram& prog,
+	const MeshBase& meshb, Vao& vao)
 {
 	vao.create();
 
-	const ShaderProgram& prog = mtl.findShaderProgram(key);
-
 	const Vbo* vbo;
 	U32 size;
 	GLenum type;
@@ -75,30 +73,74 @@ void ModelPatchBase::createVao(const Material& mtl,const MeshBase& meshb,
 	vao.attachElementArrayBufferVbo(vbo);
 }
 
+//==============================================================================
+void ModelPatchBase::getRenderingData(const PassLevelKey& key, const Vao*& vao,
+	const ShaderProgram*& prog, U32& indicesCount) const
+{
+	const U meshLods = getMeshesCount();
+	ANKI_ASSERT(meshLods > 0);
+	const U mtlLods = getMaterial().getLevelsOfDetail();
+	ANKI_ASSERT(mtlLods > 0);
+
+	// VAO
+	U lodsCount = std::max(meshLods, mtlLods);
+
+	U index = key.pass + std::min((U)key.level, lodsCount - 1) * lodsCount;
+
+	ANKI_ASSERT(index < vaos.size());
+	vao = &vaos[index];
+
+	// Mesh and indices
+	PassLevelKey meshKey;
+	meshKey.pass = key.pass;
+	meshKey.level = std::min(key.level, (U8)(meshLods - 1));
+
+	const MeshBase& meshBase = getMeshBase(meshKey);
+	indicesCount = meshBase.getIndicesCount();
+
+	// Prog
+	PassLevelKey mtlKey;
+	mtlKey.pass = key.pass;
+	mtlKey.level = std::min(key.level, (U8)(mtlLods - 1));
+
+	prog = &getMaterial().findShaderProgram(mtlKey);
+}
+
 //==============================================================================
 void ModelPatchBase::create()
 {
-	const Material& mtl = getMaterial();
-	U32 meshMaxLod = getMeshesCount() - 1;
-	U32 mtlMaxLod = mtl.getLevelsOfDetail() - 1;
-	U32 maxLod = std::max(meshLods, mtlLods);
 	U i = 0;
+	const Material& mtl = getMaterial();
+	U lodsCount = std::max(getMeshesCount(), mtl.getLevelsOfDetail());
 	U passesCount = mtl.getPasses().size();
 
-	vaos.resize(maxLod * passesCount);
+	vaos.resize(lodsCount * passesCount);
 
-	for(U32 level = 0; level < maxLod + 1; ++level)
+	for(U lod = 0; lod < lodsCount; ++lod)
 	{
-		for(U32 pass = 0; pass < passesCount; ++pass)
+		for(U pass = 0; pass < passesCount; ++pass)
 		{
-			PassLevelKey meshKey(pass, std::min(level, meshMaxLod));
-			PassLevelKey mtlKey(pass, std::min(level, mtlMaxLod));
+			PassLevelKey key(pass, lod);
+			const ShaderProgram* prog;
+			const MeshBase* mesh;
+
+			// Get mesh
+			ANKI_ASSERT(getMeshesCount() > 0);
+			PassLevelKey meshKey = key;
+			meshKey.level = std::min(key.level, (U8)(getMeshesCount() - 1));
+			mesh = &getMeshBase(meshKey);
+
+			// Get shader prog
+			ANKI_ASSERT(getMaterial().getLevelsOfDetail() > 0);
+			PassLevelKey shaderKey = key;
+			shaderKey.level = std::min(key.level,
+				(U8)(getMaterial().getLevelsOfDetail() - 1));
+			prog = &getMaterial().findShaderProgram(shaderKey);
 
 			Vao vao;
-			createVao(mtl, getMeshBase(meshKey), mtlKey, vao);
+			createVao(*prog, *mesh, vao);
 
 			vaos[i] = std::move(vao);
-			vaosMap[key] = &vaos[i];
 			++i;
 		}
 	}

+ 1 - 1
src/scene/ParticleEmitter.cpp

@@ -86,7 +86,7 @@ void ParticleSimple::simulate(const ParticleEmitter& pe,
 	F32 prevUpdateTime, F32 crntTime)
 {
 	F32 dt = crntTime - prevUpdateTime;
-	
+
 	ANKI_ASSERT(props.particle.gravity.getLength() > 0.0);
 
 	Transform trf = getWorldTransform();

+ 39 - 20
src/scene/SkinNode.cpp

@@ -51,7 +51,15 @@ void SkinMesh::getVboInfo(const VertexAttribute attrib, const Vbo*& v,
 SkinModelPatch::SkinModelPatch(const ModelPatch* mpatch_)
 	: mpatch(mpatch_)
 {
-	skinMesh.reset(new SkinMesh(&mpatch->getMeshBase()));
+#if 0
+	// Create the model patch
+	skinMeshes.resize(mpatch->getMeshesCount());
+	for(U i = 0; i < mpatch->getMeshesCount(); i++)
+	{
+		PassLevelKey key;
+		key.level = i;
+		skinMeshes[i].reset(new SkinMesh(&mpatch->getMeshBase(key)));
+	}
 	create();
 
 	const Vbo* vbo;
@@ -62,30 +70,41 @@ SkinModelPatch::SkinModelPatch(const ModelPatch* mpatch_)
 
 	// Create the VAO
 	//
-	xfbVao.create();
-
-	static const Array<MeshBase::VertexAttribute, 6> attribs = {{
-		MeshBase::VA_POSITION, MeshBase::VA_NORMAL, MeshBase::VA_TANGENT,
-		MeshBase::VA_BONE_COUNT, MeshBase::VA_BONE_IDS, 
-		MeshBase::VA_BONE_WEIGHTS}};
-	U i = 0;
-	for(auto a : attribs)
+	xfbVaos.resize(mpatch->getMeshesCount());
+
+	for(Vao& xfbVao : xfbVaos)
 	{
-		mpatch->getMeshBase().getVboInfo(
-			a, vbo, size, type, stride, offset);
+		static const Array<MeshBase::VertexAttribute, 6> attribs = {{
+			MeshBase::VA_POSITION, MeshBase::VA_NORMAL, MeshBase::VA_TANGENT,
+			MeshBase::VA_BONE_COUNT, MeshBase::VA_BONE_IDS,
+			MeshBase::VA_BONE_WEIGHTS}};
 
-		ANKI_ASSERT(vbo != nullptr);
+		xfbVao.create();
 
-		xfbVao.attachArrayBufferVbo(vbo, i, size, type, false, stride, offset);
+		U i = 0;
+		for(auto a : attribs)
+		{
+			PassLevelKey key;
+			key.level = i;
 
-		++i;
-	}
+			mpatch->getMeshBase(key).getVboInfo(
+				a, vbo, size, type, stride, offset);
 
-	// The indices VBO
-	mpatch->getMeshBase().getVboInfo(MeshBase::VA_INDICES, vbo, size, type,
-			stride, offset);
-	ANKI_ASSERT(vbo != nullptr);
-	xfbVao.attachElementArrayBufferVbo(vbo);
+			ANKI_ASSERT(vbo != nullptr);
+
+			xfbVao.attachArrayBufferVbo(
+				vbo, i, size, type, false, stride, offset);
+
+			++i;
+		}
+
+		// The indices VBO
+		mpatch->getMeshBase(key).getVboInfo(MeshBase::VA_INDICES, vbo, size,
+			type, stride, offset);
+		ANKI_ASSERT(vbo != nullptr);
+		xfbVao.attachElementArrayBufferVbo(vbo);
+	}
+#endif
 }
 
 //==============================================================================

+ 1 - 0
testapp/Main.cpp

@@ -503,6 +503,7 @@ void initSubsystems(int argc, char* argv[])
 	initializer.renderingQuality = 1.0;
 	initializer.width = nwinit.width;
 	initializer.height = nwinit.height;
+	initializer.lodDistance = 20.0;
 
 	MainRendererSingleton::get().init(initializer);