Browse Source

Start working on lighing in the forward shading pass

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
6baf26ee49

+ 2 - 1
include/anki/renderer/Is.h

@@ -167,7 +167,8 @@ private:
 	/// Prepare GL for rendering
 	/// Prepare GL for rendering
 	void setState(CommandBufferPtr& cmdBuff);
 	void setState(CommandBufferPtr& cmdBuff);
 
 
-	void updateCommonBlock(CommandBufferPtr& cmdBuff, FrustumComponent& frc);
+	void updateCommonBlock(
+		CommandBufferPtr& cmdBuff, const FrustumComponent& frc);
 
 
 	// Binning
 	// Binning
 	void binLights(U32 threadId, PtrSize threadsCount, TaskCommonData& data);
 	void binLights(U32 threadId, PtrSize threadsCount, TaskCommonData& data);

+ 2 - 2
include/anki/scene/Clusterer.h

@@ -77,9 +77,9 @@ public:
 	void bin(const CollisionShape& cs, const Aabb& csBox,
 	void bin(const CollisionShape& cs, const Aabb& csBox,
 		ClustererTestResult& rez) const;
 		ClustererTestResult& rez) const;
 
 
-	void fillShaderParams(Vec4& params) const
+	F32 getDivisor() const
 	{
 	{
-		params = Vec4(m_near, m_calcNearOpt, 0.0, 0.0);
+		return m_calcNearOpt;
 	}
 	}
 
 
 	U getClusterCount() const
 	U getClusterCount() const

+ 1 - 0
include/anki/scene/Light.h

@@ -52,6 +52,7 @@ class PointLight: public Light
 {
 {
 public:
 public:
 	/// The near plane on the shadow map frustums.
 	/// The near plane on the shadow map frustums.
+	/// WARNING: If you change here update the shaders.
 	static constexpr F32 FRUSTUM_NEAR_PLANE = 0.1 / 4.0;
 	static constexpr F32 FRUSTUM_NEAR_PLANE = 0.1 / 4.0;
 
 
 	PointLight(SceneGraph* scene);
 	PointLight(SceneGraph* scene);

+ 30 - 5
shaders/BsCommonFrag.glsl

@@ -18,10 +18,14 @@ layout(TEX_BINDING(1, 0)) uniform sampler2D anki_u_msDepthRt;
 #undef LIGHT_SS_BINDING
 #undef LIGHT_SS_BINDING
 #undef LIGHT_TEX_BINDING
 #undef LIGHT_TEX_BINDING
 
 
-layout(location = 1) flat in float inAlpha;
+layout(location = 0) in vec3 in_vertPosViewSpace;
+layout(location = 1) flat in float in_alpha;
 
 
 layout(location = 0) out vec4 out_color;
 layout(location = 0) out vec4 out_color;
 
 
+#pragma anki include "shaders/LightFunctions.glsl"
+
+//==============================================================================
 #if PASS == COLOR
 #if PASS == COLOR
 #	define texture_DEFINED
 #	define texture_DEFINED
 #endif
 #endif
@@ -30,7 +34,7 @@ layout(location = 0) out vec4 out_color;
 #define getAlpha_DEFINED
 #define getAlpha_DEFINED
 float getAlpha()
 float getAlpha()
 {
 {
-	return inAlpha;
+	return in_alpha;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -128,12 +132,13 @@ void fog(in sampler2D depthMap, in vec3 color, in float fogScale)
 
 
 	vec2 texCoords = gl_FragCoord.xy * screenSize;
 	vec2 texCoords = gl_FragCoord.xy * screenSize;
 	float depth = texture(depthMap, texCoords).r;
 	float depth = texture(depthMap, texCoords).r;
-	float zNear = 0.2;
-	float zFar = 200.0;
+	float zNear = u_nearFarClustererDivisor.x;
+	float zFar = u_nearFarClustererDivisor.y;
 	float linearDepth = (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
 	float linearDepth = (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
 
 
 	float depth2 = gl_FragCoord.z;
 	float depth2 = gl_FragCoord.z;
-	float linearDepth2 = (2.0 * zNear) / (zFar + zNear - depth2 * (zFar - zNear));
+	float linearDepth2 =
+		(2.0 * zNear) / (zFar + zNear - depth2 * (zFar - zNear));
 
 
 	float diff = linearDepth - linearDepth2;
 	float diff = linearDepth - linearDepth2;
 
 
@@ -141,3 +146,23 @@ void fog(in sampler2D depthMap, in vec3 color, in float fogScale)
 	writeGBuffer(vec4(color, diff * fogScale));
 	writeGBuffer(vec4(color, diff * fogScale));
 }
 }
 #endif
 #endif
+
+//==============================================================================
+#if PASS == COLOR
+#	define computeLightColor_DEFINED
+vec3 computeLightColor()
+{
+	// Find the cluster
+	uint cluster;
+	{
+		uint k = calcClusterSplit(in_vertPosViewSpace.z);
+
+		vec2 tilef = ceil(gl_FragCoord.xy / u_tileCount.xy);
+		uint tile = uint(tilef.y) * u_tileCount.x + uint(tilef.x);
+
+		cluster = u_clusters[tile + k * u_tileCount.z];
+	}
+
+	return vec3(0.0);
+}
+#endif

+ 11 - 3
shaders/BsCommonVert.glsl

@@ -10,7 +10,8 @@ layout(location = POSITION_LOCATION) in vec3 in_position;
 layout(location = SCALE_LOCATION) in float in_scale;
 layout(location = SCALE_LOCATION) in float in_scale;
 layout(location = ALPHA_LOCATION) in float in_alpha;
 layout(location = ALPHA_LOCATION) in float in_alpha;
 
 
-layout(location = 1) flat out float outAlpha;
+layout(location = 0) out vec3 out_vertPosViewSpace;
+layout(location = 1) flat out float out_alpha;
 
 
 out gl_PerVertex
 out gl_PerVertex
 {
 {
@@ -44,7 +45,7 @@ void writePositionMvp(in mat4 mvp)
 void particle(in mat4 mvp)
 void particle(in mat4 mvp)
 {
 {
 	gl_Position = mvp * vec4(in_position, 1);
 	gl_Position = mvp * vec4(in_position, 1);
-	outAlpha = in_alpha;
+	out_alpha = in_alpha;
 	gl_PointSize = in_scale * float(ANKI_RENDERER_WIDTH) / gl_Position.w;
 	gl_PointSize = in_scale * float(ANKI_RENDERER_WIDTH) / gl_Position.w;
 }
 }
 
 
@@ -52,5 +53,12 @@ void particle(in mat4 mvp)
 #define writeAlpha_DEFINED
 #define writeAlpha_DEFINED
 void writeAlpha(in float alpha)
 void writeAlpha(in float alpha)
 {
 {
-	outAlpha = alpha;
+	out_alpha = alpha;
+}
+
+//==============================================================================
+#define writeVertPosViewSpace_DEFINED
+void writeVertPosViewSpace(in mat4 modelViewMat)
+{
+	out_vertPosViewSpace = vec3(modelViewMat * vec4(in_position, 1.0));
 }
 }

+ 2 - 0
shaders/IsLp.frag.glsl

@@ -27,6 +27,8 @@ layout(location = 0) out vec3 out_color;
 
 
 #pragma anki include "shaders/LightFunctions.glsl"
 #pragma anki include "shaders/LightFunctions.glsl"
 
 
+const uint TILE_COUNT = TILES_COUNT_X * TILES_COUNT_Y;
+
 //==============================================================================
 //==============================================================================
 // Return frag pos in view space
 // Return frag pos in view space
 vec3 getFragPosVSpace()
 vec3 getFragPosVSpace()

+ 6 - 1
shaders/IsLp.vert.glsl

@@ -4,7 +4,12 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #pragma anki type vert
 #pragma anki type vert
-#pragma anki include "shaders/IsCommon.glsl"
+
+#define LIGHT_SET 0
+#define LIGHT_SS_BINDING 0
+#pragma anki include "shaders/LightResources.glsl"
+#undef LIGHT_SET
+#undef LIGHT_SS_BINDING
 
 
 layout(location = 0) out vec2 out_texCoord;
 layout(location = 0) out vec2 out_texCoord;
 layout(location = 1) flat out int out_instanceId;
 layout(location = 1) flat out int out_instanceId;

+ 149 - 0
shaders/LightFunctions.glsl

@@ -0,0 +1,149 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// Contains functions for light calculations
+
+#ifndef ANKI_SHADERS_LIGHT_FUNCTIONS_GLSL
+#define ANKI_SHADERS_LIGHT_FUNCTIONS_GLSL
+
+#pragma anki include "shaders/Common.glsl"
+
+const float ATTENUATION_BOOST = 0.05;
+const float OMNI_LIGHT_FRUSTUM_NEAR_PLANE = 0.1 / 4.0;
+
+//==============================================================================
+/// Calculate the cluster split
+uint calcClusterSplit(float zVspace)
+{
+	zVspace = -zVspace;
+	float fk = sqrt(
+		(zVspace - u_nearFarClustererDivisor.x) / u_nearFarClustererDivisor.z);
+	uint k = uint(fk);
+	return k;
+}
+
+//==============================================================================
+float computeAttenuationFactor(float lightRadius, vec3 frag2Light)
+{
+	float fragLightDist = length(frag2Light);
+
+	float att = (fragLightDist * lightRadius) + (1.0 + ATTENUATION_BOOST);
+	att = max(0.0, att);
+	att *= att;
+
+	return att;
+}
+
+//==============================================================================
+// Performs BRDF specular lighting
+vec3 computeSpecularColorBrdf(
+	vec3 v, // view dir
+	vec3 l, // light dir
+	vec3 n, // normal
+	vec3 specCol,
+	vec3 lightSpecCol,
+	float a2, // rougness^2
+	float nol) // N dot L
+{
+	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);
+	//float f = specColor + (1.0 - specColor)
+	//	* pow(2.0, (-5.55473 * loh - 6.98316) * loh);
+
+	// NDF: GGX Trowbridge-Reitz
+	float noh = max(EPSILON, dot(n, h));
+	float d = a2 / (PI * pow(noh * noh * (a2 - 1.0) + 1.0, 2.0));
+
+	// Visibility term: Geometric shadowing devided by BRDF denominator
+	float nov = max(EPSILON, dot(n, v));
+	float vv = nov + sqrt((nov - nov * a2) * nov + a2);
+	float vl = nol + sqrt((nol - nol * a2) * nol + a2);
+	float vis = 1.0 / (vv * vl);
+
+	return f * (vis * d) * lightSpecCol;
+}
+
+//==============================================================================
+vec3 computeDiffuseColor(vec3 diffCol, vec3 lightDiffCol)
+{
+	return diffCol * lightDiffCol;
+}
+
+//==============================================================================
+float computeSpotFactor(
+	vec3 l,
+	float outerCos,
+	float innerCos,
+	vec3 spotDir)
+{
+	float costheta = -dot(l, spotDir);
+	float spotFactor = smoothstep(outerCos, innerCos, costheta);
+	return spotFactor;
+}
+
+//==============================================================================
+float computeShadowFactorSpot(mat4 lightProjectionMat, vec3 fragPos,
+	float layer)
+{
+	vec4 texCoords4 = lightProjectionMat * vec4(fragPos, 1.0);
+	vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
+
+#if POISSON == 1
+	const vec2 poissonDisk[4] = vec2[](
+		vec2(-0.94201624, -0.39906216),
+		vec2(0.94558609, -0.76890725),
+		vec2(-0.094184101, -0.92938870),
+		vec2(0.34495938, 0.29387760));
+
+	float shadowFactor = 0.0;
+
+	vec2 cordpart0 = vec2(layer, texCoords3.z);
+
+	for(int i = 0; i < 4; i++)
+	{
+		vec2 cordpart1 = texCoords3.xy + poissonDisk[i] / (300.0);
+		vec4 tcoord = vec4(cordpart1, cordpart0);
+
+		shadowFactor += texture(u_spotMapArr, tcoord);
+	}
+
+	return shadowFactor / 4.0;
+#else
+	vec4 tcoord = vec4(texCoords3.x, texCoords3.y, layer, texCoords3.z);
+	float shadowFactor = texture(u_spotMapArr, tcoord);
+
+	return shadowFactor;
+#endif
+}
+
+//==============================================================================
+float computeShadowFactorOmni(vec3 frag2Light, float layer, float radius)
+{
+	vec3 dir = (u_viewMat * vec4(-frag2Light, 1.0)).xyz;
+	vec3 dirabs = abs(dir);
+	float dist = -max(dirabs.x, max(dirabs.y, dirabs.z));
+	dir = normalize(dir);
+
+	const float near = OMNI_LIGHT_FRUSTUM_NEAR_PLANE;
+	const float far = radius;
+
+	// Original code:
+	// float g = near - far;
+	// float z = (far + near) / g * dist + (2.0 * far * near) / g;
+	// float w = -dist;
+	// z /= w;
+	// z = z * 0.5 + 0.5;
+	// Optimized:
+	float z = (far * (dist + near)) / (dist * (far - near));
+
+	float shadowFactor = texture(u_omniMapArr, vec4(dir, layer), z).r;
+	return shadowFactor;
+}
+
+#endif
+

+ 71 - 0
shaders/LightResources.glsl

@@ -0,0 +1,71 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_SHADERS_LIGHT_RESOURCES_GLSL
+#define ANKI_SHADERS_LIGHT_RESOURCES_GLSL
+
+#pragma anki include "shaders/Common.glsl"
+
+// Common uniforms between lights
+layout(std140, row_major, SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING))
+	readonly buffer _s0
+{
+	vec4 u_projectionParams;
+	vec4 u_sceneAmbientColor;
+	vec4 u_groundLightDir;
+	vec4 u_nearFarClustererDivisor;
+	mat4 u_viewMat;
+	uvec4 u_tileCount;
+};
+
+#ifdef FRAGMENT_SHADER
+
+// Point light
+struct PointLight
+{
+	vec4 posRadius; // xyz: Light pos in eye space. w: The -1/radius
+	vec4 diffuseColorShadowmapId; // xyz: diff color, w: shadowmap tex ID
+	vec4 specularColorTexId; // xyz: spec color, w: diffuse tex ID
+};
+
+// Spot light
+struct SpotLight
+{
+	vec4 posRadius; // xyz: Light pos in eye space. w: The -1/radius
+	vec4 diffuseColorShadowmapId; // xyz: diff color, w: shadowmap tex ID
+	vec4 specularColorTexId; // xyz: spec color, w: diffuse tex ID
+	vec4 lightDir;
+	vec4 outerCosInnerCos;
+	mat4 texProjectionMat;
+};
+
+layout(std140, SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING + 1)) readonly buffer _s1
+{
+	PointLight u_pointLights[];
+};
+
+layout(std140, SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING + 2)) readonly buffer _s2
+{
+	SpotLight u_spotLights[];
+};
+
+layout(std430, SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING + 3)) readonly buffer _s3
+{
+	uint u_clusters[];
+};
+
+layout(std430, SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING + 4)) readonly buffer _s4
+{
+	uint u_lightIndices[];
+};
+
+layout(TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING))
+	uniform highp sampler2DArrayShadow u_spotMapArr;
+layout(TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 1))
+	uniform highp samplerCubeArrayShadow u_omniMapArr;
+
+#endif // FRAGMENT_SHADER
+
+#endif

+ 12 - 7
src/renderer/Is.cpp

@@ -54,8 +54,9 @@ struct ShaderCommonUniforms
 	Vec4 m_projectionParams;
 	Vec4 m_projectionParams;
 	Vec4 m_sceneAmbientColor;
 	Vec4 m_sceneAmbientColor;
 	Vec4 m_groundLightDir;
 	Vec4 m_groundLightDir;
-	Vec4 m_clustererParams;
+	Vec4 m_nearFarClustererDivisor;
 	Mat4 m_viewMat;
 	Mat4 m_viewMat;
+	UVec4 m_tileCount;
 };
 };
 
 
 using Lid = U32; ///< Light ID
 using Lid = U32; ///< Light ID
@@ -244,8 +245,7 @@ Error Is::initInternal(const ConfigSet& config)
 		"#define MAX_SPOT_LIGHTS %u\n"
 		"#define MAX_SPOT_LIGHTS %u\n"
 		"#define MAX_LIGHT_INDICES %u\n"
 		"#define MAX_LIGHT_INDICES %u\n"
 		"#define GROUND_LIGHT %u\n"
 		"#define GROUND_LIGHT %u\n"
-		"#define POISSON %u\n"
-		"#define OMNI_LIGHT_FRUSTUM_NEAR_PLANE %f\n",
+		"#define POISSON %u\n",
 		m_r->getTileCountXY().x(),
 		m_r->getTileCountXY().x(),
 		m_r->getTileCountXY().y(),
 		m_r->getTileCountXY().y(),
 		m_r->getClusterCount(),
 		m_r->getClusterCount(),
@@ -255,8 +255,7 @@ Error Is::initInternal(const ConfigSet& config)
 		m_maxSpotLights,
 		m_maxSpotLights,
 		m_maxLightIds,
 		m_maxLightIds,
 		m_groundLightEnabled,
 		m_groundLightEnabled,
-		m_sm.getPoissonEnabled(),
-		PointLight::FRUSTUM_NEAR_PLANE);
+		m_sm.getPoissonEnabled());
 
 
 	// point light
 	// point light
 	ANKI_CHECK(getResourceManager().loadResourceToCache(m_lightVert,
 	ANKI_CHECK(getResourceManager().loadResourceToCache(m_lightVert,
@@ -790,7 +789,7 @@ Error Is::run(CommandBufferPtr& cmdBuff)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Is::updateCommonBlock(CommandBufferPtr& cmdb, FrustumComponent& fr)
+void Is::updateCommonBlock(CommandBufferPtr& cmdb, const FrustumComponent& fr)
 {
 {
 	ShaderCommonUniforms* blk =
 	ShaderCommonUniforms* blk =
 		static_cast<ShaderCommonUniforms*>(
 		static_cast<ShaderCommonUniforms*>(
@@ -802,7 +801,11 @@ void Is::updateCommonBlock(CommandBufferPtr& cmdb, FrustumComponent& fr)
 	blk->m_projectionParams = m_r->getProjectionParameters();
 	blk->m_projectionParams = m_r->getProjectionParameters();
 	blk->m_sceneAmbientColor = m_ambientColor;
 	blk->m_sceneAmbientColor = m_ambientColor;
 	blk->m_viewMat = fr.getViewMatrix().getTransposed();
 	blk->m_viewMat = fr.getViewMatrix().getTransposed();
-	m_r->getClusterer().fillShaderParams(blk->m_clustererParams);
+	blk->m_nearFarClustererDivisor = Vec4(
+		fr.getFrustum().getNear(),
+		fr.getFrustum().getFar(),
+		m_r->getClusterer().getDivisor(),
+		0.0);
 
 
 	Vec3 groundLightDir;
 	Vec3 groundLightDir;
 	if(m_groundLightEnabled)
 	if(m_groundLightEnabled)
@@ -812,6 +815,8 @@ void Is::updateCommonBlock(CommandBufferPtr& cmdb, FrustumComponent& fr)
 		blk->m_groundLightDir = Vec4(-viewMat.getColumn(1).xyz(), 1.0);
 		blk->m_groundLightDir = Vec4(-viewMat.getColumn(1).xyz(), 1.0);
 	}
 	}
 
 
+	blk->m_tileCount = UVec4(m_r->getTileCountXY(), m_r->getTileCount(), 0);
+
 	m_commonVarsBuffs[m_currentFrame]->unmap();
 	m_commonVarsBuffs[m_currentFrame]->unmap();
 }
 }
 
 

+ 2 - 2
src/scene/Clusterer.cpp

@@ -168,7 +168,7 @@ void Clusterer::prepare(ThreadPool& threadPool, const SceneNode& node)
 	m_frc = &frc;
 	m_frc = &frc;
 	m_near = pfr.getNear();
 	m_near = pfr.getNear();
 	m_far = pfr.getFar();
 	m_far = pfr.getFar();
-	m_calcNearOpt = (pfr.getFar() - m_near) / pow(m_counts[2], 2.0);
+	m_calcNearOpt = (m_far - m_near) / pow(m_counts[2], 2.0);
 
 
 	//
 	//
 	// Issue parallel jobs
 	// Issue parallel jobs
@@ -217,7 +217,7 @@ void Clusterer::computeSplitRange(const CollisionShape& cs, U& zBegin,
 	dist = m_far - dist;
 	dist = m_far - dist;
 
 
 	// Find split
 	// Find split
-	zEnd = calcZ(-dist) + 1;
+	zEnd = min<U>(calcZ(-dist) + 1, m_counts[2]);
 	ANKI_ASSERT(zEnd <= m_counts[2]);
 	ANKI_ASSERT(zEnd <= m_counts[2]);
 }
 }