Bladeren bron

Instancing support

Panagiotis Christopoulos Charitos 13 jaren geleden
bovenliggende
commit
e9ec9678f8

+ 8 - 3
include/anki/resource/Material.h

@@ -298,6 +298,9 @@ class Material: public MaterialProperties, public NonCopyable
 public:
 public:
 	typedef PtrVector<MaterialVariable> VarsContainer;
 	typedef PtrVector<MaterialVariable> VarsContainer;
 
 
+	/// Type for garbage collection
+	typedef PtrVector<ShaderProgramResourcePointer> ShaderPrograms;
+
 	Material();
 	Material();
 	~Material();
 	~Material();
 
 
@@ -320,6 +323,11 @@ public:
 	{
 	{
 		return commonUniformBlock;
 		return commonUniformBlock;
 	}
 	}
+
+	const ShaderPrograms& getShaderPrograms() const
+	{
+		return progs;
+	}
 	/// @}
 	/// @}
 
 
 	const ShaderProgram& findShaderProgram(const PassLevelKey& key) const
 	const ShaderProgram& findShaderProgram(const PassLevelKey& key) const
@@ -344,9 +352,6 @@ public:
 	}
 	}
 
 
 private:
 private:
-	/// Type for garbage collection
-	typedef PtrVector<ShaderProgramResourcePointer> ShaderPrograms;
-
 	typedef ConstCharPtrHashMap<MaterialVariable*>::Type
 	typedef ConstCharPtrHashMap<MaterialVariable*>::Type
 		NameToVariableHashMap;
 		NameToVariableHashMap;
 
 

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

@@ -21,7 +21,8 @@ public:
 		std::string name;
 		std::string name;
 		std::string type;
 		std::string type;
 		StringList value;
 		StringList value;
-		Bool const_;
+		Bool constant;
+		U32 arraySize;
 	};
 	};
 
 
 	explicit MaterialShaderProgramCreator(const XmlElement& pt, 
 	explicit MaterialShaderProgramCreator(const XmlElement& pt, 

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

@@ -68,9 +68,13 @@ class ParticleEmitter: public SceneNode, public Spatial, public Movable,
 	public Renderable, private ParticleEmitterProperties
 	public Renderable, private ParticleEmitterProperties
 {
 {
 public:
 public:
-	ParticleEmitter(const char* filename,
-		const char* name, Scene* scene, // Scene
-		U32 movableFlags, Movable* movParent); // Movable
+	ParticleEmitter(
+		const char* filename,
+		// SceneNode
+		const char* name, Scene* scene,
+		// Movable
+		U32 movableFlags, Movable* movParent);
+
 	~ParticleEmitter();
 	~ParticleEmitter();
 
 
 	/// @name SceneNode virtuals
 	/// @name SceneNode virtuals
@@ -138,7 +142,7 @@ private:
 	// rotation is the identity
 	// rotation is the identity
 	Bool identityRotation = true;
 	Bool identityRotation = true;
 
 
-	U32 instancesCount; ///< AKA alive
+	U32 instancesCount; ///< AKA alive count
 
 
 	Vector<Vec3> instancintPositions;
 	Vector<Vec3> instancintPositions;
 
 

+ 5 - 0
include/anki/scene/Renderable.h

@@ -114,6 +114,11 @@ public:
 	{
 	{
 		return ubo;
 		return ubo;
 	}
 	}
+
+	Ubo& getInstancingUbo()
+	{
+		return instancingUbo;
+	}
 	/// @}
 	/// @}
 
 
 protected:
 protected:

+ 13 - 0
shaders/MaterialCommonFunctions.glsl

@@ -0,0 +1,13 @@
+/// Generic add
+#define add_DEFINED
+#define add(a, b) (a + b)
+
+/// Generic mul
+#define mul_DEFINED
+#define mul(a, b) (a * b)
+
+#define vec4ToVec3_DEFINED
+#define vec4ToVec3(a) ((a).xyz)
+
+#define vec3ToVec4_DEFINED
+#define vec3ToVec4(a, w) (vec4((a), (w)))

+ 1 - 8
shaders/MaterialFragmentFunctions.glsl

@@ -2,14 +2,7 @@
 /// The file contains common functions for fragment operations
 /// The file contains common functions for fragment operations
 
 
 #pragma anki include "shaders/Pack.glsl"
 #pragma anki include "shaders/Pack.glsl"
-
-/// Generic add
-#define add_DEFINED
-#define add(a, b) (a + b)
-
-/// Generic mul
-#define mul_DEFINED
-#define mul(a, b) (a * b)
+#pragma anki include "shaders/MaterialCommonFunctions.glsl"
 
 
 /// @param[in] normal The fragment's normal in view space
 /// @param[in] normal The fragment's normal in view space
 /// @param[in] tangent The tangent
 /// @param[in] tangent The tangent

+ 21 - 0
shaders/MaterialVertexInstancingTranslations.glsl

@@ -0,0 +1,21 @@
+/// @file 
+/// Contains variables and functions for instancing of translations
+
+layout(location = 1) uniform instancingBlock
+{
+	vec3 instancingTranslations[];
+};
+
+//==============================================================================
+#define setVaryings_particle_DEFINED
+void setVaryings_particle(in mat4 billboardModelViewProjectionMat)
+{
+#if defined(PASS_DEPTH) && LOD > 0
+	// No tex coords for you
+#else
+	vTexCoords = texCoords;
+#endif
+
+	gl_Position = billboardModelViewProjectionMat 
+		* vec4(position + instancingTranslations[gl_InstanceID], 1.0);
+}

+ 33 - 3
src/renderer/Drawer.cpp

@@ -139,6 +139,7 @@ void RenderableDrawer::setupShaderProg(
 	vis.renderable = &renderable;
 	vis.renderable = &renderable;
 	vis.r = r;
 	vis.r = r;
 
 
+	// Set the uniforms
 	for(auto it = renderable.getVariablesBegin();
 	for(auto it = renderable.getVariablesBegin();
 		it != renderable.getVariablesEnd(); ++it)
 		it != renderable.getVariablesEnd(); ++it)
 	{
 	{
@@ -147,6 +148,7 @@ void RenderableDrawer::setupShaderProg(
 		rvar->getMaterialVariable().acceptVisitor(vis);
 		rvar->getMaterialVariable().acceptVisitor(vis);
 	}
 	}
 
 
+	// Write the block
 	const ShaderProgramUniformBlock* block = mtl.getCommonUniformBlock();
 	const ShaderProgramUniformBlock* block = mtl.getCommonUniformBlock();
 	if(block)
 	if(block)
 	{
 	{
@@ -155,10 +157,26 @@ void RenderableDrawer::setupShaderProg(
 		renderable.getUbo().write(&vis.clientBlock[0]);
 		renderable.getUbo().write(&vis.clientBlock[0]);
 		renderable.getUbo().setBinding(0);
 		renderable.getUbo().setBinding(0);
 	}
 	}
+
+	// Write the instancing blocks
+#if 0
+	U32 instancesCount = renderable.getRenderableInstancesCount();
+	const Vec3* translations = renderable.getRenderableInstancingTranslations();
+	if(translations)
+	{
+		ShaderProgramUniformBlock& block = 
+			sprog.findUniformBlock("instancingTranslations");
+		ANKI_ASSERT(block.getBinding() == 1);
+
+		Ubo& ubo = renderable.getInstancingUbo();
+		ubo.write(translations, instancesCount * sizeof(Vec3), 0);
+		ubo.setBinding(1);
+	}
+#endif
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void RenderableDrawer::render(const Frustumable& fr, uint pass,
+void RenderableDrawer::render(const Frustumable& fr, U32 pass,
 	Renderable& renderable)
 	Renderable& renderable)
 {
 {
 	/*float dist = (node.getWorldTransform().getOrigin() -
 	/*float dist = (node.getWorldTransform().getOrigin() -
@@ -171,12 +189,24 @@ void RenderableDrawer::render(const Frustumable& fr, uint pass,
 	setupShaderProg(key, fr, renderable);
 	setupShaderProg(key, fr, renderable);
 
 
 	// Render
 	// Render
-	U32 indecesCount = renderable.getRenderableModelPatchBase().getIndecesCount(0);
+	U32 indicesCount = 
+		renderable.getRenderableModelPatchBase().getIndecesCount(0);
 
 
 	const Vao& vao = renderable.getRenderableModelPatchBase().getVao(key);
 	const Vao& vao = renderable.getRenderableModelPatchBase().getVao(key);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
 	ANKI_ASSERT(vao.getAttachmentsCount() > 1);
 	vao.bind();
 	vao.bind();
-	glDrawElements(GL_TRIANGLES, indecesCount, GL_UNSIGNED_SHORT, 0);
+
+	U32 instancesCount = renderable.getRenderableInstancesCount();
+
+	if(instancesCount == 0)
+	{
+		glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_SHORT, 0);
+	}
+	else
+	{
+		glDrawElementsInstanced(
+			GL_TRIANGLES, indicesCount, GL_UNSIGNED_SHORT, 0, instancesCount);
+	}
 }
 }
 
 
 }  // end namespace anki
 }  // end namespace anki

+ 43 - 6
src/resource/MaterialShaderProgramCreator.cpp

@@ -41,12 +41,20 @@ void MaterialShaderProgramCreator::parseShaderProgramTag(
 		
 		
 		for(Input* in : inputs)
 		for(Input* in : inputs)
 		{
 		{
-			if(in->type == "sampler2D" || in->const_)
+			if(in->type == "sampler2D" || in->constant)
 			{
 			{
 				continue;
 				continue;
 			}
 			}
 
 
-			block.push_back("\tuniform " + in->type + " " + in->name + ";");
+			std::string line = "\tuniform " + in->type + " " + in->name;
+
+			if(in->arraySize > 1)
+			{
+				line += "[" + std::to_string(in->arraySize) + "U]";
+			}
+
+			line += ";";
+			block.push_back(line);
 		}
 		}
 		block.sortAll();
 		block.sortAll();
 
 
@@ -139,35 +147,64 @@ void MaterialShaderProgramCreator::parseInputTag(
 	inpvar->type = inputEl.getChildElement("type").getText();
 	inpvar->type = inputEl.getChildElement("type").getText();
 	XmlElement constEl = inputEl.getChildElementOptional("const");
 	XmlElement constEl = inputEl.getChildElementOptional("const");
 	XmlElement valueEl = inputEl.getChildElement("value");
 	XmlElement valueEl = inputEl.getChildElement("value");
+	XmlElement arrSizeEl = inputEl.getChildElement("arraySize");
 
 
+	// Is const?
 	if(constEl)
 	if(constEl)
 	{
 	{
-		inpvar->const_ = constEl.getInt();
+		inpvar->constant = constEl.getInt();
+	}
+	else
+	{
+		inpvar->constant = false;
+	}
+
+	// Is array?
+	if(arrSizeEl)
+	{
+		inpvar->arraySize = arrSizeEl.getInt();
 	}
 	}
 	else
 	else
 	{
 	{
-		inpvar->const_ = false;
+		inpvar->arraySize = 0;
 	}
 	}
 
 
+	// Get value
 	if(valueEl.getText())
 	if(valueEl.getText())
 	{
 	{
 		inpvar->value = StringList::splitString(valueEl.getText(), ' ');
 		inpvar->value = StringList::splitString(valueEl.getText(), ' ');
 	}
 	}
 
 
-	if(inpvar->const_ == false)
+	if(inpvar->constant == false)
 	{
 	{
+		// Handle non-consts
+
 		if(!(enableUniformBlocks && inpvar->type != "sampler2D"))
 		if(!(enableUniformBlocks && inpvar->type != "sampler2D"))
 		{
 		{
-			line = "uniform " + inpvar->type + " " + inpvar->name + ";";
+			line = "uniform " + inpvar->type + " " + inpvar->name;
+			
+			if(inpvar->arraySize > 1)
+			{
+				line += "[" + std::to_string(inpvar->arraySize) + "U]";
+			}
+
+			line += ";";
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
+		// Handle consts
+
 		if(inpvar->value.size() == 0)
 		if(inpvar->value.size() == 0)
 		{
 		{
 			throw ANKI_EXCEPTION("Empty value and const is illogical");
 			throw ANKI_EXCEPTION("Empty value and const is illogical");
 		}
 		}
 
 
+		if(inpvar->arraySize > 0)
+		{
+			throw ANKI_EXCEPTION("Const arrays currently cannot be handled");
+		}
+
 		line = "const " + inpvar->type + " " + inpvar->name + " = "
 		line = "const " + inpvar->type + " " + inpvar->name + " = "
 			+ inpvar->type + "(" + inpvar->value.join(", ") +  ");";
 			+ inpvar->type + "(" + inpvar->value.join(", ") +  ");";
 	}
 	}

+ 3 - 1
src/scene/ParticleEmitter.cpp

@@ -42,8 +42,10 @@ ParticleEmitter::ParticleEmitter(
 	: SceneNode(name, scene), Spatial(this, &aabb),
 	: SceneNode(name, scene), Spatial(this, &aabb),
 		Movable(movableFlags, movParent, *this)
 		Movable(movableFlags, movParent, *this)
 {
 {
-	Renderable::init(*this);
 	init(filename, scene);
 	init(filename, scene);
+
+	instancesCount = particles.size();
+	Renderable::init(*this);
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 11 - 13
src/scene/Renderable.cpp

@@ -105,25 +105,23 @@ void Renderable::init(PropertyMap& pmap)
 	}
 	}
 
 
 	// Init the instancing UBO
 	// Init the instancing UBO
+#if 0
+	const ShaderProgram* aprog = mtl.getShaderPrograms()[0].get();
 	U32 instancesCount = getRenderableInstancesCount();
 	U32 instancesCount = getRenderableInstancesCount();
-	if(instancesCount > 0)
+	
+	const ShaderProrgamUniformBlock* block = 
+		aprog->tryFindUniformBlock("instancesTranslations");
+	if(block)
 	{
 	{
-		const Vec3* translations;
-		const Transform* transforms;
-		U32 size = 0;
-
-		if((translations = getRenderableInstancingTranslations()) != 0)
-		{
-			size = sizeof(Vec3) * instancesCount;
-		}
-		else if((transforms = getRenderableInstancingWorldTransforms()) != 0)
+		if(instancesCount < 1)
 		{
 		{
-			size = sizeof(Mat4) * instancesCount;
+			throw ANKI_EXCEPTION("The shader program implies multiple "
+				"instances but the object has zero");
 		}
 		}
 
 
-		ANKI_ASSERT(size != 0);
-		instancingUbo.create(size, nullptr);
+		instancingUbo.create(instancesCount * sizeof(Vec3), nullptr);
 	}
 	}
+#endif
 }
 }
 
 
 }  // end namespace anki
 }  // end namespace anki