Browse Source

Caching reflection entries

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
8dec76a6cc

+ 3 - 1
include/anki/core/Timestamp.h

@@ -11,7 +11,9 @@
 namespace anki {
 
 /// Timestamp type
-typedef U32 Timestamp;
+using Timestamp = U32;
+
+const U MAX_TIMESTAMP = MAX_U32;
 
 } // end namespace anki
 

+ 11 - 0
include/anki/renderer/Ir.h

@@ -46,15 +46,26 @@ anki_internal:
 	}
 
 private:
+	class CacheEntry
+	{
+	public:
+		const SceneNode* m_node = nullptr;
+		Timestamp m_timestamp = 0; ///< When last rendered.
+	};
+
 	Renderer m_nestedR;
 	TexturePtr m_cubemapArr;
 	U16 m_cubemapArrSize = 0;
 	U16 m_fbSize = 0;
 	DynamicBufferToken m_probesToken;
 	DynamicBufferToken m_proxiesToken;
+	DArray<CacheEntry> m_cacheEntries;
 
 	ANKI_USE_RESULT Error renderReflection(SceneNode& node,
 		ShaderReflectionProbe& shaderProb);
+
+	/// Find a cache entry to store the reflection.
+	void findCacheEntry(SceneNode& node, U& entry, Bool& render);
 };
 /// @}
 

+ 14 - 1
include/anki/scene/SpatialComponent.h

@@ -70,6 +70,18 @@ public:
 		}
 	}
 
+	/// Check if it's confined in a single sector.
+	Bool getSingleSector() const
+	{
+		return m_bits.bitsEnabled(Flag::SINGLE_SECTOR);
+	}
+
+	/// Confine it or not in a single sector.
+	void setSingleSector(Bool yes)
+	{
+		m_bits.enableBits(Flag::SINGLE_SECTOR, yes);
+	}
+
 	/// Used for sorting spatials. In most object the origin is the center of
 	/// mess but for cameras the origin is the eye point
 	const Vec4& getSpatialOrigin() const
@@ -115,7 +127,8 @@ private:
 		VISIBLE_CAMERA = 1 << 1,
 		VISIBLE_LIGHT = 1 << 2,
 		VISIBLE_ANY = VISIBLE_CAMERA | VISIBLE_LIGHT,
-		MARKED_FOR_UPDATE = 1 << 3
+		MARKED_FOR_UPDATE = 1 << 3,
+		SINGLE_SECTOR = 1 << 4
 	};
 	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Flag, friend)
 

+ 0 - 1
shaders/ImageReflections.glsl

@@ -128,7 +128,6 @@ void readFromProbes(in vec3 c, out vec3 color)
 	{
 		float R2 = u_reflectionProbes[i].positionRadiusSq.w;
 		vec3 center = u_reflectionProbes[i].positionRadiusSq.xyz;
-		color = vec3(1.0);
 
 		// Check if posVSpace is inside the sphere
 		vec3 f = c - center;

+ 4 - 3
shaders/IsLp.frag.glsl

@@ -62,7 +62,7 @@ vec3 getFragPosVSpace()
 	vec3 l = normalize(frag2Light); \
 	float nol = max(0.0, dot(normal, l)); \
 	vec3 specC = computeSpecularColorBrdf(viewDir, l, normal, specCol, \
-		light.specularColorTexId.rgb, a2, nol); \
+		light.specularColorTexId.rgb, a2, nol, refl); \
 	vec3 diffC = computeDiffuseColor( \
 		diffCol, light.diffuseColorShadowmapId.rgb); \
 	float att = computeAttenuationFactor(light.posRadius.w, frag2Light); \
@@ -100,7 +100,9 @@ void main()
 	float a2 = pow(max(EPSILON, roughness), 2.0);
 
 #if IR == 1
-	specCol *= readReflection(fragPos, normal);
+	vec3 refl = readReflection(fragPos, normal);
+#else
+	const vec3 refl = vec3(1.0);
 #endif
 
 	// Ambient and emissive color
@@ -192,5 +194,4 @@ void main()
 
 	out_color = out_color * 0.5 + readReflection(fragPos, normal) *0.5;
 #endif
-	//out_color = vec3(roughness);
 }

+ 7 - 7
shaders/LightFunctions.glsl

@@ -30,13 +30,11 @@ uint calcClusterSplit(float zVspace)
 //==============================================================================
 float computeAttenuationFactor(float lightRadius, vec3 frag2Light)
 {
-	float fragLightDist = length(frag2Light);
+	float fragLightDist = dot(frag2Light, frag2Light);
+	fragLightDist = min(fragLightDist, lightRadius);
 
-	float att = (fragLightDist * lightRadius) + (1.0 + ATTENUATION_BOOST);
-	att = max(0.0, att);
-	att *= att;
-
-	return att;
+	float att = 1.0 - fragLightDist / lightRadius;
+	return att * att;
 }
 
 //==============================================================================
@@ -48,13 +46,15 @@ vec3 computeSpecularColorBrdf(
 	vec3 specCol,
 	vec3 lightSpecCol,
 	float a2, // rougness^2
-	float nol) // N dot L
+	float nol, // N dot L
+	vec3 reflection) // For fresnel
 {
 	vec3 h = normalize(l + v);
 
 	// Fresnel (Schlick)
 	float loh = max(EPSILON, dot(l, h));
 	vec3 f = specCol + (1.0 - specCol) * pow((1.0 + EPSILON - loh), 5.0);
+	f *= reflection;
 	//float f = specColor + (1.0 - specColor)
 	//	* pow(2.0, (-5.55473 * loh - 6.98316) * loh);
 

+ 1 - 1
src/renderer/Clusterer.cpp

@@ -322,7 +322,7 @@ void Clusterer::binSphere(const Sphere& s, const Aabb& aabb,
 	Vec2 tileSize(1.0 / tcountX, 1.0 / tcountY);
 
 	Vec4 a = vp * s.getCenter().xyz1();
-	Vec2 c = a.xy() / a.w();
+	Vec2 c = (a.w() != 0.0) ? (a.xy() / a.w()) : a.xy();
 	c = c * 0.5 + 0.5;
 
 	Vec4 sphereCenterVSpace = (v * scent.xyz1()).xyz0();

+ 94 - 15
src/renderer/Ir.cpp

@@ -40,7 +40,9 @@ struct ShaderReflectionProbe
 
 //==============================================================================
 Ir::~Ir()
-{}
+{
+	m_cacheEntries.destroy(getAllocator());
+}
 
 //==============================================================================
 Error Ir::init(const ConfigSet& initializer)
@@ -62,6 +64,8 @@ Error Ir::init(const ConfigSet& initializer)
 		return ErrorCode::USER_DATA;
 	}
 
+	m_cacheEntries.create(getAllocator(), m_cubemapArrSize);
+
 	// Init the renderer
 	Config config;
 	config.set("dbg.enabled", false);
@@ -181,35 +185,110 @@ Error Ir::renderReflection(SceneNode& node, ShaderReflectionProbe& shaderProb)
 	const ReflectionProbeComponent& reflc =
 		node.getComponent<ReflectionProbeComponent>();
 
+	// Get cache entry
+	Bool render = false;
+	U entry;
+	findCacheEntry(node, entry, render);
+
 	// Write shader var
 	shaderProb.m_pos = (frc.getViewMatrix() * reflc.getPosition().xyz1()).xyz();
 	shaderProb.m_radiusSq = reflc.getRadius() * reflc.getRadius();
-	shaderProb.m_cubemapIndex = 0;
+	shaderProb.m_cubemapIndex = entry;
 
 	// Render cubemap
-	for(U i = 0; i < 6; ++i)
+	if(render)
 	{
-		Array<CommandBufferPtr, RENDERER_COMMAND_BUFFERS_COUNT> cmdb;
-		for(U j = 0; j < cmdb.getSize(); ++j)
+		for(U i = 0; i < 6; ++i)
 		{
-			cmdb[j] = getGrManager().newInstance<CommandBuffer>();
+			Array<CommandBufferPtr, RENDERER_COMMAND_BUFFERS_COUNT> cmdb;
+			for(U j = 0; j < cmdb.getSize(); ++j)
+			{
+				cmdb[j] = getGrManager().newInstance<CommandBuffer>();
+			}
+
+			// Render
+			ANKI_CHECK(m_nestedR.render(node, i, cmdb));
+
+			// Copy textures
+			cmdb[cmdb.getSize() - 1]->copyTextureToTexture(
+				m_nestedR.getIs().getRt(), 0, 0, m_cubemapArr, 6 * entry + i,
+				0);
+
+			// Flush
+			for(U j = 0; j < cmdb.getSize(); ++j)
+			{
+				cmdb[j]->flush();
+			}
 		}
+	}
 
-		// Render
-		ANKI_CHECK(m_nestedR.render(node, i, cmdb));
+	return ErrorCode::NONE;
+}
 
-		// Copy textures
-		cmdb[cmdb.getSize() - 1]->copyTextureToTexture(
-			m_nestedR.getIs().getRt(), 0, 0, m_cubemapArr, i, 0);
+//==============================================================================
+void Ir::findCacheEntry(SceneNode& node, U& entry, Bool& render)
+{
+	CacheEntry* it = m_cacheEntries.getBegin();
+	const CacheEntry* const end = m_cacheEntries.getEnd();
+
+	CacheEntry* canditate = nullptr;
+	CacheEntry* empty = nullptr;
+	CacheEntry* kick = nullptr;
+	Timestamp kickTime = MAX_TIMESTAMP;
 
-		// Flush
-		for(U j = 0; j < cmdb.getSize(); ++j)
+	while(it != end)
+	{
+		if(it->m_node == &node)
+		{
+			// Already there
+			canditate = it;
+			break;
+		}
+		else if(empty == nullptr && it->m_node == nullptr)
+		{
+			// Found empty
+			empty = it;
+		}
+		else if(it->m_timestamp < kickTime)
 		{
-			cmdb[j]->flush();
+			// Found one to kick
+			kick = it;
+			kickTime = it->m_timestamp;
 		}
+
+		++it;
 	}
 
-	return ErrorCode::NONE;
+	if(canditate)
+	{
+		// Update timestamp
+		canditate->m_timestamp = getGlobalTimestamp();
+		it = canditate;
+		render = false;
+	}
+	else if(empty)
+	{
+		ANKI_ASSERT(empty->m_node == nullptr);
+		empty->m_node = &node;
+		empty->m_timestamp = getGlobalTimestamp();
+
+		it = empty;
+		render = true;
+	}
+	else if(kick)
+	{
+		kick->m_node = &node;
+		kick->m_timestamp = getGlobalTimestamp();
+
+		it = kick;
+		render = true;
+	}
+	else
+	{
+		ANKI_ASSERT(0);
+	}
+
+	entry = it - m_cacheEntries.getBegin();
 }
 
 } // end namespace anki

+ 4 - 2
src/renderer/Is.cpp

@@ -622,7 +622,8 @@ I Is::writePointLight(const LightComponent& lightc,
 	Vec4 pos = camFrc.getViewMatrix()
 		* lightMove.getWorldTransform().getOrigin().xyz1();
 
-	slight.m_posRadius = Vec4(pos.xyz(), -1.0 / lightc.getRadius());
+	slight.m_posRadius = Vec4(pos.xyz(),
+		lightc.getRadius() * lightc.getRadius());
 	slight.m_diffuseColorShadowmapId = lightc.getDiffuseColor();
 
 	if(!lightc.getShadowEnabled() || !m_sm.getEnabled())
@@ -675,7 +676,8 @@ I Is::writeSpotLight(const LightComponent& lightc,
 	Vec4 pos =
 		camFrc.getViewMatrix()
 		* lightMove.getWorldTransform().getOrigin().xyz1();
-	light.m_posRadius = Vec4(pos.xyz(), -1.0 / lightc.getDistance());
+	light.m_posRadius = Vec4(pos.xyz(),
+		lightc.getDistance() * lightc.getDistance());
 
 	// Diff color and shadowmap ID now
 	light.m_diffuseColorShadowmapId =

+ 34 - 4
src/scene/Sector.cpp

@@ -468,12 +468,42 @@ void SectorGroup::binSpatial(SpatialComponent* sp)
 	{
 		Sector& sector = *(*it);
 
-		Bool collide = testCollisionShapes(sector.m_aabb, sp->getAabb());
+		Bool collide = false;
+		if(!sp->getSingleSector())
+		{
+			// Spatial can belong to multiple sectors
 
-		if(collide)
+			// Fast test
+			collide = testCollisionShapes(sector.m_aabb, sp->getAabb());
+
+			// Detailed test
+			if(collide)
+			{
+				collide = testCollisionShapes(
+					sector.getBoundingShape(), sp->getSpatialCollisionShape());
+			}
+		}
+		else
 		{
-			collide = testCollisionShapes(
-				sector.getBoundingShape(), sp->getSpatialCollisionShape());
+			// Spatial can belong to one sector
+
+			// Make sure the origin of the spatial is inside the sector
+			const Vec4& center = sp->getSpatialOrigin();
+
+			if(center >= sector.m_aabb.getMin()
+				&& center <= sector.m_aabb.getMax())
+			{
+				collide = true;
+			}
+
+			// Detailed test
+			const F32 smallf = getEpsilon<F32>() * 10.0;
+			Aabb smallBox(center, center + Vec4(smallf, smallf, smallf, 0.0));
+			if(collide)
+			{
+				collide = testCollisionShapes(
+					sector.getBoundingShape(), smallBox);
+			}
 		}
 
 		if(collide)

+ 1 - 1
testapp/Main.cpp

@@ -78,7 +78,7 @@ Error init()
 	const F32 ang = 55.0;
 	cam->setAll(
 		renderer.getAspectRatio() * toRad(ang),
-		toRad(ang), 0.2, 200.0);
+		toRad(ang), 0.2, 300.0);
 	scene.setActiveCamera(cam);
 
 	cam->getComponent<MoveComponent>().