Browse Source

Move from GL's default [-1,1] NDC space for Z to [0,1] that is used in Vulkan and DX

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
a676a1777c

+ 1 - 1
programs/DeferredShading.ankiprog

@@ -31,7 +31,7 @@ layout(ANKI_UBO_BINDING(0, 0), row_major) uniform u0_
 
 void main()
 {
-	ANKI_WRITE_POSITION(u_mvp * vec4(in_position, 1.0));
+	gl_Position = u_mvp * vec4(in_position, 1.0);
 }
 			]]></source>
 		</shader>

+ 1 - 1
programs/ForwardShadingFog.ankiprog

@@ -19,7 +19,7 @@ http://www.anki3d.org/LICENSE
 
 void main() 
 {
-	ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
+	gl_Position = mvp * vec4(in_position, 1.0);
 	out_posViewSpace = (modelView * vec4(in_position, 1.0)).xyz;
 }
 			]]></source>

+ 1 - 1
programs/GBufferGeneric.ankiprog

@@ -45,7 +45,7 @@ void main()
 		parallax(modelViewMat);
 	#endif
 #else
-	ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
+	gl_Position = mvp * vec4(in_position, 1.0);
 #endif
 }
 			]]>

+ 1 - 1
programs/LensFlareOcclusionTest.ankiprog

@@ -25,7 +25,7 @@ out gl_PerVertex
 
 void main()
 {
-	ANKI_WRITE_POSITION(u_mvp * vec4(in_position, 1.0));
+	gl_Position = u_mvp * vec4(in_position, 1.0);
 	gl_PointSize = 16.0;
 }
 			]]></source>

+ 1 - 1
programs/LensFlareSprite.ankiprog

@@ -46,7 +46,7 @@ void main()
 	out_uv = vec3((position * 0.5) + 0.5, sprite.depthPad3.x);
 
 	vec4 posScale = sprite.posScale;
-	ANKI_WRITE_POSITION(vec4(position * posScale.zw + posScale.xy, 0.0, 1.0));
+	gl_Position = vec4(position * posScale.zw + posScale.xy, 0.0, 1.0);
 
 	out_color = sprite.color;
 }

+ 3 - 3
programs/LightShading.ankiprog

@@ -29,7 +29,7 @@ void main()
 {
 	out_uv = vec2(gl_VertexID & 1, gl_VertexID >> 1) * 2.0;
 	vec2 pos = out_uv * 2.0 - 1.0;
-	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
+	gl_Position = vec4(pos, 0.0, 1.0);
 
 	out_clusterIJ = vec2(CLUSTER_COUNT_X, CLUSTER_COUNT_Y) * out_uv;
 }
@@ -148,13 +148,13 @@ void main()
 	vec2 ndc = UV_TO_NDC(in_uv);
 
 	// Get frag pos in view space
-	vec4 fragPos4 = u_invProjMat * vec4(ndc, UV_TO_NDC(depth), 1.0);
+	vec4 fragPos4 = u_invProjMat * vec4(ndc, depth, 1.0);
 	vec3 fragPos = fragPos4.xyz / fragPos4.w;
 
 	// Get world position
 	vec3 worldPos;
 	{
-		vec4 worldPos4 = u_invViewProjMat * vec4(ndc, UV_TO_NDC(depth), 1.0);
+		vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
 		worldPos4 = worldPos4 / worldPos4.w;
 		worldPos = worldPos4.xyz;
 	}

+ 1 - 1
programs/Ssao.ankiprog

@@ -101,7 +101,7 @@ void main(void)
 	vec3 randFactors = readRandom(in_uv);
 
 	// Get prev SSAO
-	vec4 clip = u_prevViewProjMatMulInvViewProjMat * vec4(vec3(ndc, UV_TO_NDC(depth)), 1.0);
+	vec4 clip = u_prevViewProjMatMulInvViewProjMat * vec4(vec3(ndc, depth), 1.0);
 	clip.xy /= clip.w;
 	vec2 oldUv = NDC_TO_UV(clip.xy);
 	float prevSsao = textureLod(u_prevSsaoRt, oldUv, 0.0).r;

+ 1 - 1
programs/TemporalAAResolve.ankiprog

@@ -49,7 +49,7 @@ void main()
 	float depth = textureLod(u_depthRt, in_uv, 0.0).r;
 
 	// Get prev uv coords
-	vec4 v4 = u_prevViewProjMatMulInvViewProjMat * UV_TO_NDC(vec4(in_uv, depth, 1.0));
+	vec4 v4 = u_prevViewProjMatMulInvViewProjMat * vec4(UV_TO_NDC(in_uv), depth, 1.0);
 	vec2 oldUv = NDC_TO_UV(v4.xy / v4.w);
 
 	// Read textures

+ 1 - 1
programs/VolumetricFog.ankiprog

@@ -131,7 +131,7 @@ void main()
 {
 	float depth = textureLod(u_msDepthRt, in_uv, 0.0).r;
 
-	vec3 ndc = UV_TO_NDC(vec3(in_uv, depth));
+	vec3 ndc = vec3(UV_TO_NDC(in_uv), depth);
 
 	vec3 farPos;
 	farPos.z = u_unprojectionParams.z / (u_unprojectionParams.w + depth);

+ 1 - 1
shaders/ForwardShadingCommonFrag.glsl

@@ -131,7 +131,7 @@ void fog(vec3 color, float fogAlphaScale, float fogDistanceOfMaxThikness)
 	float depth = texture(anki_msDepthRt, texCoords).r;
 	float zFeatherFactor;
 
-	vec4 fragPosVspace4 = u_invProjMat * vec4(UV_TO_NDC(vec3(texCoords, depth)), 1.0);
+	vec4 fragPosVspace4 = u_invProjMat * vec4(vec3(UV_TO_NDC(texCoords), depth), 1.0);
 	float sceneZVspace = fragPosVspace4.z / fragPosVspace4.w;
 
 	float diff = max(0.0, in_posViewSpace.z - sceneZVspace);

+ 1 - 1
shaders/ForwardShadingCommonVert.glsl

@@ -39,7 +39,7 @@ void particle(in mat4 mvp, in mat3 camRot, in mat4 viewMat)
 	out_uv = vec2(gl_VertexID & 1, gl_VertexID >> 1);
 
 	vec3 worldPos = camRot * vec3((out_uv - 0.5) * in_scale, 0.0) + in_position;
-	ANKI_WRITE_POSITION(mvp * vec4(worldPos, 1.0));
+	gl_Position = mvp * vec4(worldPos, 1.0);
 
 	out_posViewSpace = (viewMat * vec4(worldPos, 1.0)).xyz;
 

+ 3 - 3
shaders/Functions.glsl

@@ -35,13 +35,13 @@ float dither(in float col, in float C)
 // Convert to linear depth
 float linearizeDepth(in float depth, in float zNear, in float zFar)
 {
-	return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
+	return zNear / ((zNear - zFar) + zFar / depth);
 }
 
-// This is the optimal linearizeDepth where a=(f+n)/2n and b=(n-f)/2n
+// This is the optimal linearizeDepth where a=(n-f)/n and b=f/n
 float linearizeDepthOptimal(in float depth, in float a, in float b)
 {
-	return 1.0 / (a + depth * b);
+	return 1.0 / (a + b / depth);
 }
 
 // Project a vector by knowing only the non zero values of a perspective matrix

+ 1 - 1
shaders/GBufferCommonVert.glsl

@@ -45,7 +45,7 @@ layout(location = 6) out mediump vec3 out_normalTangentSpace; // Parallax
 void positionUvNormalTangent(mat4 mvp, mat3 normalMat)
 {
 	out_uv = in_uv;
-	ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
+	gl_Position = mvp * vec4(in_position, 1.0);
 
 	out_normal = normalMat * in_normal.xyz;
 	out_tangent.xyz = normalMat * in_tangent.xyz;

+ 1 - 2
shaders/LightFunctions.glsl

@@ -148,10 +148,9 @@ float computeShadowFactorOmni(
 
 	// Original code:
 	// float g = near - far;
-	// float z = (far + near) / g * dist + (2.0 * far * near) / g;
+	// float z = far / g * dist + (far * near) / g;
 	// float w = -dist;
 	// z /= w;
-	// z = z * 0.5 + 0.5;
 	// Optimized:
 	float z = (far * (dist + near)) / (dist * (far - near));
 

+ 1 - 1
shaders/QuadVert.glsl

@@ -17,5 +17,5 @@ void main()
 	out_uv = vec2(gl_VertexID & 1, gl_VertexID >> 1) * 2.0;
 	vec2 pos = out_uv * 2.0 - 1.0;
 
-	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
+	gl_Position = vec4(pos, 0.0, 1.0);
 }

+ 1 - 0
src/anki/gr/gl/GlState.cpp

@@ -136,6 +136,7 @@ void GlState::initRenderThread()
 	glEnable(GL_CULL_FACE);
 	glEnable(GL_SCISSOR_TEST);
 	glScissor(0, 0, MAX_U16, MAX_U16);
+	glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
 
 	// Create default VAO
 	glGenVertexArrays(1, &m_defaultVao);

+ 0 - 4
src/anki/gr/gl/ShaderImpl.cpp

@@ -42,10 +42,6 @@ static const char* SHADER_HEADER = R"(#version %u %s
 #define ANKI_USING_FRAG_COORD(height_) vec4 anki_fragCoord = gl_FragCoord;
 #endif
 
-#if defined(ANKI_VERTEX_SHADER)
-#define ANKI_WRITE_POSITION(x_) gl_Position = x_
-#endif
-
 #if 1
 #extension GL_ARB_shader_ballot : require
 #define ANKI_ARB_SHADER_BALLOT 1

+ 0 - 4
src/anki/gr/vulkan/ShaderImpl.cpp

@@ -170,10 +170,6 @@ static const char* SHADER_HEADER = R"(#version 450 core
 	vec4(gl_FragCoord.x, h_ - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);
 #endif
 
-#if defined(ANKI_VERTEX_SHADER)
-#define ANKI_WRITE_POSITION(x_) gl_Position = x_; gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5
-#endif
-
 #if %s
 #extension GL_ARB_shader_ballot : require
 #define ANKI_ARB_SHADER_BALLOT 1

+ 17 - 14
src/anki/math/Mat4.h

@@ -31,7 +31,7 @@ public:
 };
 #endif
 
-/// 4x4 Matrix. Used mainly for transformations but not necessarily. Its row major. SSE optimized
+/// 4x4 Matrix. Used mainly for transformations but not necessarily. It's row major. SSE optimized
 /// @note TMat4*TMat4: 64 muls 48 adds
 template<typename T>
 class alignas(16) TMat4 : public TMat<T, 4, 4, typename TMat4Simd<T>::Type, TMat4<T>, TVec4<T>, TVec4<T>>
@@ -352,6 +352,7 @@ public:
 			m(2, 0) * v.x() + m(2, 1) * v.y() + m(2, 2) * v.z() + m(2, 3));
 	}
 
+	/// Calculate a perspective projection matrix. The z is mapped in [0, 1] range just like DX and Vulkan.
 	static TMat4 calculatePerspectiveProjectionMatrix(T fovX, T fovY, T near, T far)
 	{
 		ANKI_ASSERT(fovX > T(0) && fovY > T(0) && near > T(0) && far > T(0));
@@ -370,8 +371,8 @@ public:
 		proj(1, 3) = T(0);
 		proj(2, 0) = T(0);
 		proj(2, 1) = T(0);
-		proj(2, 2) = (far + near) / g;
-		proj(2, 3) = (T(2) * far * near) / g;
+		proj(2, 2) = far / g;
+		proj(2, 3) = (far * near) / g;
 		proj(3, 0) = T(0);
 		proj(3, 1) = T(0);
 		proj(3, 2) = T(-1);
@@ -380,6 +381,7 @@ public:
 		return proj;
 	}
 
+	/// Calculate an orthographic projection matrix. The z is mapped in [0, 1] range just like DX and Vulkan.
 	static TMat4 calculateOrthographicProjectionMatrix(T right, T left, T top, T bottom, T near, T far)
 	{
 		ANKI_ASSERT(right != T(0) && left != T(0) && top != T(0) && bottom != T(0) && near != T(0) && far != T(0));
@@ -388,7 +390,7 @@ public:
 		T difz = far - near;
 		T tx = -(right + left) / difx;
 		T ty = -(top + bottom) / dify;
-		T tz = -(far + near) / difz;
+		T tz = -near / difz;
 		TMat4 m;
 
 		m(0, 0) = T(2) / difx;
@@ -401,7 +403,7 @@ public:
 		m(1, 3) = ty;
 		m(2, 0) = T(0);
 		m(2, 1) = T(0);
-		m(2, 2) = T(-2) / difz;
+		m(2, 2) = T(-1) / difz;
 		m(2, 3) = tz;
 		m(3, 0) = T(0);
 		m(3, 1) = T(0);
@@ -427,16 +429,17 @@ public:
 
 		T m00 = f * (fovY / fovX);
 		T m11 = f;
-		T m22 = (far + near) / g;
-		T m23 = (T(2) * far * near) / g;
+		T m22 = far / g;
+		T m23 = (far * near) / g;
 
-		// First, z' = (m * Pv) / 2 + 0.5 where Pv is the view space position.
+		// First, clip = (m * Pv) where Pv is the view space position.
+		// ndc.z = clip.z / clip.w = (m22 * Pv.z + m23) / -Pv.z. Note that ndc.z == depth in zero_to_one projection.
 		// Solving that for Pv.z we get
-		// Pv.z = A / (z' + B)
-		// where A = (-m23 / 2) and B = (m22 / 2 - 0.5)
+		// Pv.z = A / (depth + B)
+		// where A = -m23 and B = m22
 		// so we save the A and B in the projection params vector
-		out.z() = -m23 * T(0.5);
-		out.w() = m22 * T(0.5) - T(0.5);
+		out.z() = -m23;
+		out.w() = m22;
 
 		// Using the same logic the Pv.x = x' * w / m00
 		// so Pv.x = x' * Pv.z * (-1 / m00)
@@ -454,8 +457,8 @@ public:
 	{
 		TVec4<T> out;
 		const TMat4& m = *this;
-		out.z() = -m(2, 3) * T(0.5);
-		out.w() = m(2, 2) * T(0.5) - T(0.5);
+		out.z() = -m(2, 3);
+		out.w() = m(2, 2);
 		out.x() = -T(1.0) / m(0, 0);
 		out.y() = -T(1.0) / m(1, 1);
 		return out;

+ 3 - 3
src/anki/renderer/Common.h

@@ -67,11 +67,11 @@ const U BLOOM_FRACTION = 4;
 /// Volumetric size is rendererSize/VOLUMETRIC_FRACTION.
 const U VOLUMETRIC_FRACTION = 4;
 
-/// Computes the 'a' and 'b' numbers for linearizeDepthOptimal
+/// Computes the 'a' and 'b' numbers for linearizeDepthOptimal (see shaders)
 inline void computeLinearizeDepthOptimal(F32 near, F32 far, F32& a, F32& b)
 {
-	a = (far + near) / (2.0f * near);
-	b = (near - far) / (2.0f * near);
+	a = (near - far) / near;
+	b = far / near;
 }
 
 const U GBUFFER_COLOR_ATTACHMENT_COUNT = 3;

+ 1 - 1
src/anki/scene/DecalComponent.cpp

@@ -57,7 +57,7 @@ void DecalComponent::updateInternal()
 		FRUSTUM_NEAR_PLANE,
 		m_sizes.z());
 
-	static const Mat4 biasMat4(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
+	static const Mat4 biasMat4(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
 
 	m_biasProjViewMat = biasMat4 * projMat * viewMat;
 

+ 1 - 1
src/anki/scene/LightComponent.cpp

@@ -32,7 +32,7 @@ Error LightComponent::update(SceneNode&, F32, F32, Bool& updated)
 
 		if(m_type == LightComponentType::SPOT)
 		{
-			static const Mat4 biasMat4(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
+			static const Mat4 biasMat4(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
 			Mat4 proj =
 				Mat4::calculatePerspectiveProjectionMatrix(m_outerAngle, m_outerAngle, FRUSTUM_NEAR_PLANE, m_distance);
 			m_spotTextureMatrix = biasMat4 * proj * Mat4(m_trf.getInverse());

+ 6 - 6
src/anki/scene/SoftwareRasterizer.cpp

@@ -283,15 +283,15 @@ void SoftwareRasterizer::rasterizeTriangle(const Vec4* tri)
 			Vec3 bc;
 			if(!computeBarycetrinc(window[0], window[1], window[2], p, bc))
 			{
-				F32 z0 = ndc[0].z() / 2.0 + 0.5;
-				F32 z1 = ndc[1].z() / 2.0 + 0.5;
-				F32 z2 = ndc[2].z() / 2.0 + 0.5;
+				const F32 z0 = ndc[0].z();
+				const F32 z1 = ndc[1].z();
+				const F32 z2 = ndc[2].z();
 
-				F32 depth = z0 * bc[0] + z1 * bc[1] + z2 * bc[2];
+				const F32 depth = z0 * bc[0] + z1 * bc[1] + z2 * bc[2];
 				ANKI_ASSERT(depth >= 0.0 && depth <= 1.0);
 
 				// Store the min of the current value and new one
-				U32 depthi = depth * MAX_U32;
+				const U32 depthi = depth * MAX_U32;
 				m_zbuffer[U(y) * m_width + U(x)].min(depthi);
 			}
 		}
@@ -349,7 +349,7 @@ Bool SoftwareRasterizer::visibilityTestInternal(const CollisionShape& cs, const
 			bboxMax[i] = clamp(bboxMax[i], 0.0f, windowSize[i]);
 		}
 
-		minZ = min(minZ, p.z() / 2.0f + 0.5f);
+		minZ = min(minZ, p.z());
 	}
 
 	for(U y = bboxMin.y(); y < bboxMax.y(); y += 1.0f)

+ 4 - 4
tests/gr/Gr.cpp

@@ -28,7 +28,7 @@ void main()
 {
 	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, 1.0), vec2(0.0, -1.0), vec2(1.0, 1.0));
 
-	ANKI_WRITE_POSITION(vec4(POSITIONS[gl_VertexID % 3], 0.0, 1.0));
+	gl_Position = vec4(POSITIONS[gl_VertexID % 3], 0.0, 1.0);
 })";
 
 static const char* VERT_QUAD_STRIP_SRC = R"(
@@ -41,7 +41,7 @@ void main()
 {
 	const vec2 POSITIONS[4] = vec2[](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0));
 
-	ANKI_WRITE_POSITION(vec4(POSITIONS[gl_VertexID % 4], 0.0, 1.0));
+	gl_Position = vec4(POSITIONS[gl_VertexID % 4], 0.0, 1.0);
 })";
 
 static const char* VERT_UBO_SRC = R"(
@@ -110,7 +110,7 @@ void main()
 		vec2[](vec2(-1.0, 1.0), vec2(-1.0, -1.0), vec2(1.0, -1.0),
 		vec2(1.0, -1.0), vec2(1.0, 1.0), vec2(-1.0, 1.0));
 
-	ANKI_WRITE_POSITION(vec4(POSITIONS[gl_VertexID], 0.0, 1.0));
+	gl_Position = vec4(POSITIONS[gl_VertexID], 0.0, 1.0);
 	out_uv = POSITIONS[gl_VertexID] / 2.0 + 0.5;
 })";
 
@@ -129,7 +129,7 @@ layout(ANKI_UBO_BINDING(0, 0), std140, row_major) uniform u0_
 
 void main()
 {
-	ANKI_WRITE_POSITION(u_mvp * vec4(in_pos, 1.0));
+	gl_Position = u_mvp * vec4(in_pos, 1.0);
 })";
 
 static const char* FRAG_SRC = R"(layout (location = 0) out vec4 out_color;