Browse Source

New feature: Multisampling & Changed the packing of G buffer normals. Less quality. A bit faster & Other refactoring

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
85d056c569

+ 1 - 1
include/anki/event/EventManager.h

@@ -40,7 +40,7 @@ public:
 	/// @{
 
 	std::shared_ptr<Event> newSceneAmbientColorEvent(
-		F32 startTime, F32 duration, const Vec3& finalColor);
+		F32 startTime, F32 duration, const Vec4& finalColor);
 
 	std::shared_ptr<Event> newLightEvent(
 		F32 startTime, F32 duration, const LightEventData& data);

+ 3 - 3
include/anki/event/SceneAmbientColorEvent.h

@@ -15,14 +15,14 @@ class SceneAmbientColorEvent: public Event
 public:
 	/// Constructor
 	SceneAmbientColorEvent(F32 startTime, F32 duration, EventManager* manager,
-		const Vec3& finalColor, SceneGraph* scene);
+		const Vec4& finalColor, SceneGraph* scene);
 
 	/// Implements Event::update
 	void update(F32 prevUpdateTime, F32 crntTime);
 
 private:
-	Vec3 originalColor; ///< Original scene color. The constructor sets it
-	Vec3 finalColor;
+	Vec4 originalColor; ///< Original scene color. The constructor sets it
+	Vec4 finalColor;
 	SceneGraph* scene = nullptr;
 };
 

+ 3 - 3
include/anki/gl/BufferObject.h

@@ -10,10 +10,10 @@ namespace anki {
 	
 /// A wrapper for OpenGL buffer objects (vertex arrays, texture buffers etc)
 /// to prevent us from making idiotic errors
-class BufferObject: public GlMultiObject
+class BufferObject: public GlObject
 {
 public:
-	typedef GlMultiObject Base;
+	typedef GlObject Base;
 
 	/// @name Constructors/Destructor
 	/// @{
@@ -69,7 +69,7 @@ public:
 	void bind() const
 	{
 		ANKI_ASSERT(isCreated());
-		glBindBuffer(target, glId[getGlobTimestamp() % objectsCount]);
+		glBindBuffer(target, getGlId());
 	}
 
 	/// Unbind BO

+ 40 - 63
include/anki/gl/GlObject.h

@@ -10,61 +10,16 @@
 #include "anki/util/StdTypes.h"
 #include "anki/core/Timestamp.h"
 #include <thread>
+#include <atomic>
+#include <cstring>
 
 namespace anki {
 
 /// @addtogroup OpenGL
 /// @{
 
-/// An OpenGL object. It is never copyable
-class GlObject: public NonCopyable
-{
-public:
-	/// Default
-	GlObject()
-	{}
-
-	/// Move
-	GlObject(GlObject&& b)
-	{
-		*this = std::move(b);
-	}
-
-	~GlObject()
-	{
-		// The destructor of the derived GL object should pass 0 name
-		ANKI_ASSERT(!isCreated());
-	}
-
-	/// Move
-	GlObject& operator=(GlObject&& b)
-	{
-		ANKI_ASSERT(!isCreated());
-		glId = b.glId;
-		b.glId = 0;
-		return *this;
-	}
-
-	/// Get the GL name
-	GLuint getGlId() const
-	{
-		ANKI_ASSERT(isCreated());
-		return glId;
-	}
-
-	/// GL object is created
-	Bool isCreated() const
-	{
-		return glId != 0;
-	}
-
-protected:
-	/// OpenGL name
-	GLuint glId = 0;
-};
-
 /// A compound GL object that supports buffering depending on the frame
-class GlMultiObject: public NonCopyable
+class GlObject: public NonCopyable
 {
 public:
 	/// Buffering technique
@@ -77,68 +32,90 @@ public:
 	};
 
 	/// Default
-	GlMultiObject()
-	{}
+	GlObject()
+	{
+		memset(&glIds[0], 0, sizeof(glIds));
+		objectsCount = 1;
+#if ANKI_DEBUG
+		refCount.store(0);
+#endif
+	}
 
 	/// Move
-	GlMultiObject(GlMultiObject&& b)
+	GlObject(GlObject&& b)
+		: GlObject()
 	{
 		*this = std::move(b);
 	}
 
-	~GlMultiObject()
+	~GlObject()
 	{
 		// The destructor of the derived GL object should pass 0 name
 		ANKI_ASSERT(!isCreated());
 	}
 
 	/// Move
-	GlMultiObject& operator=(GlMultiObject&& b)
+	GlObject& operator=(GlObject&& b)
 	{
 		ANKI_ASSERT(!isCreated());
 		
 		for(U i = 0; i < MAX_OBJECTS; i++)
 		{
-			glId[i] = b.glId[i];
-			b.glId[i] = 0;
+			glIds[i] = b.glIds[i];
+			b.glIds[i] = 0;
 		}
 
 		objectsCount = b.objectsCount;
-		b.objectsCount = 0;
+		b.objectsCount = 1;
+#if ANKI_DEBUG
+		refCount.store(b.refCount.load());
+		b.refCount.store(0);
+#endif
 		return *this;
 	}
 
-	/// Get the GL name
+	/// Get the GL name for the current frame
 	GLuint getGlId() const
 	{
 		ANKI_ASSERT(isCreated());
-		return glId[getGlobTimestamp() % MAX_OBJECTS];
+		return glIds[getGlobTimestamp() % objectsCount];
 	}
 
 	/// GL object is created
 	Bool isCreated() const
 	{
+		ANKI_ASSERT(objectsCount > 0);
 #if ANKI_DEBUG
 		U mask = 0;
 		for(U i = 0; i < MAX_OBJECTS; i++)
 		{
 			mask <<= 1;
-			mask |= (glId[i] != 0);
+			mask |= (glIds[i] != 0);
 		}
 
 		// If the mask is not zero then make sure that objectsCount is sane
 		ANKI_ASSERT(!(mask != 0 && __builtin_popcount(mask) != objectsCount));
 #endif
 
-		return objectsCount > 0;
+		return glId != 0;
 	}
 
 protected:
 	/// OpenGL names
-	Array<GLuint, MAX_OBJECTS> glId = {{0, 0, 0}};
+	union
+	{
+		Array<GLuint, MAX_OBJECTS> glIds;
+		GLuint glId;
+	};
 
-	/// The size of the glId array
-	U8 objectsCount = 0;
+	/// The size of the glIds array
+	U8 objectsCount;
+
+#if ANKI_DEBUG
+	/// Textures and buffers can be attached so keep a refcount for sanity
+	/// checks
+	std::atomic<U32> refCount;
+#endif
 };
 
 /// Defines an non sharable GL object. Used to avoid idiotic mistakes and more

+ 0 - 1
include/anki/math/Axisang.h

@@ -199,7 +199,6 @@ private:
 
 /// F32 Axisang
 typedef TAxisang<F32> Axisang;
-
 /// @}
 
 } // end namespace anki

+ 0 - 3
include/anki/math/Mat3.h

@@ -724,8 +724,6 @@ private:
 	/// @}
 };
 
-/// @name TMat3 friends
-/// @{
 template<typename T>
 TMat3<T> operator+(T f, const TMat3<T>& m3)
 {
@@ -759,7 +757,6 @@ TMat3<T> operator/(T f, const TMat3<T>& m3)
 	}
 	return out;
 }
-/// @}
 
 /// F32 3x3 matrix
 typedef TMat3<F32> Mat3;

+ 0 - 10
include/anki/math/Mat4.h

@@ -216,16 +216,6 @@ public:
 	{
 		return arr1[i];
 	}
-
-	Simd& getSimd(const U i)
-	{
-		return simd[i];
-	}
-
-	const Simd& getSimd(const U i) const
-	{
-		return simd[i];
-	}
 	/// @}
 
 	/// @name Operators with same type

+ 14 - 15
include/anki/math/Quat.h

@@ -70,7 +70,7 @@ public:
 		T trace = m3(0, 0) + m3(1, 1) + m3(2, 2) + 1.0;
 		if(trace > getEpsilon<T>())
 		{
-			T s = 0.5 / sqrt(trace);
+			T s = 0.5 / sqrt<T>(trace);
 			w() = 0.25 / s;
 			x() = (m3(2, 1) - m3(1, 2)) * s;
 			y() = (m3(0, 2) - m3(2, 0)) * s;
@@ -80,7 +80,7 @@ public:
 		{
 			if(m3(0, 0) > m3(1, 1) && m3(0, 0) > m3(2, 2))
 			{
-				T s = 0.5 / sqrt(1.0 + m3(0, 0) - m3(1, 1) - m3(2, 2));
+				T s = 0.5 / sqrt<T>(1.0 + m3(0, 0) - m3(1, 1) - m3(2, 2));
 				w() = (m3(1, 2) - m3(2, 1)) * s;
 				x() = 0.25 / s;
 				y() = (m3(0, 1) + m3(1, 0)) * s;
@@ -88,7 +88,7 @@ public:
 			}
 			else if(m3(1, 1) > m3(2, 2))
 			{
-				T s = 0.5 / sqrt(1.0 + m3(1, 1) - m3(0, 0) - m3(2, 2));
+				T s = 0.5 / sqrt<T>(1.0 + m3(1, 1) - m3(0, 0) - m3(2, 2));
 				w() = (m3(0, 2) - m3(2, 0)) * s;
 				x() = (m3(0, 1) + m3(1, 0)) * s;
 				y() = 0.25 / s;
@@ -96,7 +96,7 @@ public:
 			}
 			else
 			{
-				T s = 0.5 / sqrt(1.0 + m3(2, 2) - m3(0, 0) - m3(1, 1));
+				T s = 0.5 / sqrt<T>(1.0 + m3(2, 2) - m3(0, 0) - m3(1, 1));
 				w() = (m3(0, 1) - m3(1, 0)) * s;
 				x() = (m3(0, 2) + m3(2, 0)) * s;
 				y() = (m3(1, 2) + m3(2, 1)) * s;
@@ -260,7 +260,7 @@ public:
 
 	T getLength() const
 	{
-		return sqrt(w() * w() + x() * x() + y() * y() + z() * z());
+		return sqrt<T>(w() * w() + x() * x() + y() * y() + z() * z());
 	}
 
 	TQuat getInverted() const
@@ -308,17 +308,16 @@ public:
 	/// Returns slerp(this, q1, t)
 	TQuat slerp(const TQuat& q1_, const T t) const
 	{
-		const TQuat& q0 = *this;
-		TQuat q1(q1_);
-		T cosHalfTheta = q0.w() * q1.w() + q0.x() * q1.x() + q0.y() * q1.y() 
-			+ q0.z() * q1.z();
+		TVec4<T> q0(*this);
+		TVec4<T> q1(q1_);
+		T cosHalfTheta = q0.dot(q1);
 		if(cosHalfTheta < 0.0)
 		{
-			q1 = TQuat(-TVec4<T>(q1)); // quat changes
+			q1 = -q1; // quat changes
 			cosHalfTheta = -cosHalfTheta;
 		}
 
-		if(fabs(cosHalfTheta) >= 1.0f)
+		if(fabs<T>(cosHalfTheta) >= 1.0)
 		{
 			return TQuat(q0);
 		}
@@ -326,15 +325,15 @@ public:
 		T halfTheta = acos<T>(cosHalfTheta);
 		T sinHalfTheta = sqrt<T>(1.0 - cosHalfTheta * cosHalfTheta);
 
-		if(fabs(sinHalfTheta) < 0.001)
+		if(fabs<T>(sinHalfTheta) < 0.001)
 		{
-			return TQuat((TVec4<T>(q0) + TVec4<T>(q1)) * 0.5);
+			return TQuat((q0 + q1) * 0.5);
 		}
 		T ratioA = sin<T>((1.0 - t) * halfTheta) / sinHalfTheta;
 		T ratio_b = sin<T>(t * halfTheta) / sinHalfTheta;
 		TVec4<T> tmp, tmp1, sum;
-		tmp = TVec4<T>(q0) * ratioA;
-		tmp1 = TVec4<T>(q1) * ratio_b;
+		tmp = q0 * ratioA;
+		tmp1 = q1 * ratio_b;
 		sum = tmp + tmp1;
 		sum.normalize();
 		return TQuat(sum);

+ 35 - 22
include/anki/math/Vec2.h

@@ -12,6 +12,17 @@ namespace anki {
 template<typename T>
 class TVec2
 {
+	/// @name Friends
+	template<typename Y>
+	friend TVec2<Y> operator+(const Y f, const TVec2<Y>& v2);
+	template<typename Y>
+	friend TVec2<Y> operator-(const Y f, const TVec2<Y>& v2);
+	template<typename Y>
+	friend TVec2<Y> operator*(const Y f, const TVec2<Y>& v2);
+	template<typename Y>
+	friend TVec2<Y> operator/(const Y f, const TVec2<Y>& v2);
+	///@]
+
 public:
 	/// @name Constructors
 	/// @{
@@ -260,28 +271,6 @@ public:
 	}
 	/// @}
 
-	/// @name Friends
-	friend TVec2 operator+(const T f, const TVec2& v2)
-	{
-		return v2 + f;
-	}
-
-	friend TVec2 operator-(const T f, const TVec2& v2)
-	{
-		return TVec2(f - v2.x(), f - v2.y());
-	}
-
-	friend TVec2 operator*(const T f, const TVec2& v2)
-	{
-		return v2 * f;
-	}
-
-	friend TVec2 operator/(const T f, const TVec2& v2)
-	{
-		return TVec2(f / v2.x(), f / v2.y());
-	}
-	///@]
-
 private:
 	/// @name Data members
 	/// @{
@@ -297,6 +286,30 @@ private:
 	/// @}
 };
 
+template<typename T>
+TVec2<T> operator+(const T f, const TVec2<T>& v2)
+{
+	return v2 + f;
+}
+
+template<typename T>
+TVec2<T> operator-(const T f, const TVec2<T>& v2)
+{
+	return TVec2<T>(f - v2.x(), f - v2.y());
+}
+
+template<typename T>
+TVec2<T> operator*(const T f, const TVec2<T>& v2)
+{
+	return v2 * f;
+}
+
+template<typename T>
+TVec2<T> operator/(const T f, const TVec2<T>& v2)
+{
+	return TVec2<T>(f / v2.x(), f / v2.y());
+}
+
 /// F32 2D vector
 typedef TVec2<F32> Vec2;
 static_assert(sizeof(Vec2) == sizeof(F32) * 2, "Incorrect size");

+ 36 - 24
include/anki/math/Vec3.h

@@ -12,6 +12,18 @@ namespace anki {
 template<typename T>
 class TVec3
 {
+	/// @name Friends
+	/// @{
+	template<typename Y>
+	friend TVec3<Y> operator+(const Y f, const TVec3<Y>& v);
+	template<typename Y>
+	friend TVec3<Y> operator-(const Y f, const TVec3<Y>& v);
+	template<typename Y>
+	friend TVec3<Y> operator*(const Y f, const TVec3<Y>& v);
+	template<typename Y>
+	friend TVec3<Y> operator/(const Y f, const TVec3<Y>& v);
+	/// @}
+
 public:
 	/// @name Constructors
 	/// @{
@@ -424,29 +436,6 @@ public:
 	}
 	/// @}
 
-	/// @name Friends
-	/// @{
-	friend TVec3 operator+(const T f, const TVec3& v)
-	{
-		return v + f;
-	}
-
-	friend TVec3 operator-(const T f, const TVec3& v)
-	{
-		return TVec3(f) - v;
-	}
-
-	friend TVec3 operator*(const T f, const TVec3& v)
-	{
-		return v * f;
-	}
-
-	friend TVec3 operator/(const T f, const TVec3& v)
-	{
-		return TVec3(f) / v;
-	}
-	/// @}
-
 private:
 	/// @name Data
 	/// @{
@@ -462,6 +451,30 @@ private:
 	/// @}
 };
 
+template<typename T>
+TVec3<T> operator+(const T f, const TVec3<T>& v)
+{
+	return v + f;
+}
+
+template<typename T>
+TVec3<T> operator-(const T f, const TVec3<T>& v)
+{
+	return TVec3<T>(f) - v;
+}
+
+template<typename T>
+TVec3<T> operator*(const T f, const TVec3<T>& v)
+{
+	return v * f;
+}
+
+template<typename T>
+TVec3<T> operator/(const T f, const TVec3<T>& v)
+{
+	return TVec3<T>(f) / v;
+}
+
 /// F32 3D vector
 typedef TVec3<F32> Vec3;
 static_assert(sizeof(Vec3) == sizeof(F32) * 3, "Incorrect size");
@@ -471,7 +484,6 @@ typedef TVec3<I32> IVec3;
 
 /// 32bit unsigned integer 3D vector
 typedef TVec3<U32> UVec3;
-
 /// @}
 
 } // end namespace anki

+ 10 - 7
include/anki/renderer/Ms.h

@@ -22,19 +22,19 @@ public:
 	/// @{
 	const Texture& getFai0() const
 	{
-		return fai0;
+		return fai0[1];
 	}
 
 #if ANKI_RENDERER_USE_MRT
 	const Texture& getFai1() const
 	{
-		return fai1;
+		return fai1[1];
 	}
 #endif
 
 	const Texture& getDepthFai() const
 	{
-		return depthFai;
+		return depthFai[1];
 	}
 	/// @}
 
@@ -43,12 +43,15 @@ public:
 
 private:
 	Ez ez; /// EarlyZ pass
-	Fbo fbo;
-	Texture fai0; ///< The FAI for diffuse color, normals and specular
+	Array<Fbo, 2> fbo;
+	Array<Texture, 2> fai0; ///< The FAI for diffuse color, normals and specular
 #if ANKI_RENDERER_USE_MRT
-	Texture fai1;
+	Array<Texture, 2> fai1;
 #endif
-	Texture depthFai; ///< The FAI for depth
+	Array<Texture, 2> depthFai; ///< The FAI for depth
+
+	/// Create a G buffer FBO
+	void createFbo(U index, U samples);
 };
 
 } // end namespace anki

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

@@ -101,6 +101,7 @@ struct RendererInitializer
 	U32 height;
 	F32 renderingQuality = 1.0; ///< Applies only to MainRenderer
 	F32 lodDistance = 10.0; ///< Distance that used to calculate the LOD
+	U32 samples = 1; ///< Enables multisampling
 
 	// funcs
 	RendererInitializer()
@@ -120,6 +121,8 @@ class ModelNode;
 /// external renderers for security cameras for example
 class Renderer
 {
+	friend class Ms;
+
 public:
 	typedef RendererInitializer Initializer;
 
@@ -323,7 +326,8 @@ protected:
 
 private:
 	U framesNum; ///< Frame number
-	Mat4 viewProjectionMat; ///< Precalculated in case anyone needs it
+	Mat4 viewProjectionMat; ///< Precalculated in case anyone needs it XXX
+	U8 samples;
 
 	/// @name For drawing a quad into the active framebuffer
 	/// @{

+ 4 - 4
include/anki/scene/SceneGraph.h

@@ -61,13 +61,13 @@ public:
 		return SceneAllocator<U8>(frameAlloc);
 	}
 
-	const Vec3& getAmbientColor() const
+	Vec4 getAmbientColor() const
 	{
-		return ambientCol;
+		return Vec4(ambientCol, 1.0);
 	}
-	void setAmbientColor(const Vec3& x)
+	void setAmbientColor(const Vec4& x)
 	{
-		ambientCol = x;
+		ambientCol = x.xyz();
 		ambiendColorUpdateTimestamp = getGlobTimestamp();
 	}
 	U32 getAmbientColorUpdateTimestamp() const

+ 2 - 2
shaders/BsCommonFrag.glsl

@@ -5,7 +5,7 @@
 #pragma anki include "shaders/MsBsCommon.glsl"
 
 #define vTexCoords_DEFINED
-in vec2 vTexCoords;
+in vec2 vTexCoord;
 #define vInstanceId_DEFINED
 flat in uint vInstanceId;
 
@@ -29,7 +29,7 @@ void writeFais(in vec4 color)
 #define particleAlpha_DEFINED
 void particleAlpha(in sampler2D tex, in float alpha)
 {
-	vec4 color = DEFAULT_FLOAT_PRECISION vec4(texture(tex, vTexCoords));
+	vec4 color = DEFAULT_FLOAT_PRECISION vec4(texture(tex, vTexCoord));
 	color.w *= alpha;
 	writeFais(color);
 }

+ 4 - 4
shaders/BsCommonVert.glsl

@@ -3,11 +3,11 @@
 #pragma anki include "shaders/MsBsCommon.glsl"
 
 layout(location = 0) in vec3 position;
-layout(location = 3) in vec2 texCoords;
+layout(location = 3) in vec2 texCoord;
 
 /// @name Varyings
 /// @{
-out vec2 vTexCoords;
+out vec2 vTexCoord;
 flat out uint vInstanceId;
 /// @}
 
@@ -29,14 +29,14 @@ void setPositionVec4(in vec4 pos)
 #define setTexCoords_DEFINED
 void setTexCoords(in vec2 x)
 {
-	vTexCoords = x;
+	vTexCoord = x;
 }
 
 //==============================================================================
 #define particle_DEFINED
 void particle(in mat4 mvp)
 {
-	vTexCoords = texCoords;
+	vTexCoord = texCoord;
 	gl_Position = mvp * vec4(position, 1);
 	vInstanceId = uint(gl_InstanceID);
 }

+ 3 - 1
shaders/Final.glsl

@@ -6,6 +6,7 @@
 
 #pragma anki start fragmentShader
 #pragma anki include shaders/CommonFrag.glsl
+#pragma anki include shaders/Pack.glsl
 
 uniform lowp sampler2D rasterImage;
 
@@ -14,6 +15,7 @@ layout(location = 0) out lowp vec3 fFragColor;
 
 void main()
 {
-	lowp vec3 col = textureLod(rasterImage, vTexCoords, 0.0).rgb;
+	lowp vec3 col = texture(rasterImage, vTexCoords).rgb;
+	//lowp vec3 col = vec3(readAndUnpackNormal(rasterImage, vTexCoords) * 0.5 + 0.5);
 	fFragColor = col;
 }

+ 1 - 2
shaders/IsLp.glsl

@@ -87,7 +87,6 @@ layout(std140)
 	Tile tiles[TILES_COUNT];
 };
 
-
 #if USE_MRT
 uniform sampler2D msFai0;
 uniform sampler2D msFai1;
@@ -227,7 +226,7 @@ void main()
 
 	// Decode MS
 #if USE_MRT
-	vec3 normal = unpackNormal(texture(msFai1, vTexCoords).rg);
+	vec3 normal = readAndUnpackNormal(msFai1, vTexCoords);
 	vec4 diffuseAndSpec = texture(msFai0, vTexCoords);
 #else
 	uvec2 msAll = texture(msFai0, vTexCoords).rg;

+ 2 - 2
shaders/MsCommonFrag.glsl

@@ -29,7 +29,7 @@ flat in lowp float vSpecularComponent;
 #if defined(PASS_COLOR)
 #	if USE_MRT
 layout(location = 0) out vec4 fMsFai0;
-layout(location = 1) out vec2 fMsFai1;
+layout(location = 1) out vec4 fMsFai1;
 #	else
 layout(location = 0) out uvec2 fMsFai0;
 #	endif
@@ -160,7 +160,7 @@ void writeFais(
 	// Diffuse color and specular
 	fMsFai0 = vec4(diffCol, specularComponent);
 	// Normal
-	fMsFai1 = packNormal(normal);
+	packAndWriteNormal(normal, fMsFai1);
 #else
 	// Diffuse color and specular
 	fMsFai0[0] = packUnorm4x8(vec4(diffCol, specularComponent));

+ 69 - 0
shaders/Pack.glsl

@@ -19,6 +19,75 @@ vec3 unpackNormal(in vec2 enc)
 	return normal;
 }
 
+vec2 encodeUnormFloatToVec2(in float f)
+{
+	vec2 vec = vec2(1.0, 65025.0) * f;
+	return vec2(vec.x, fract(vec.y));
+	//return unpackSnorm2x16(floatBitsToUint(f));
+}
+
+float decodeVec2ToUnormFloat(in vec2 vec)
+{
+	//return uintBitsToFloat(packSnorm2x16(vec));
+	return dot(vec, vec2(1.0, 1.0 / 65025.0));
+}
+
+void packAndWriteNormal(in vec3 normal, out vec4 fai)
+{
+#if 1
+	vec3 unorm = normal * 0.5 + 0.5;
+	fai = vec4(unorm.xyz, 0.0);
+#endif
+
+#if 0
+	vec3 unorm = normal * 0.5 + 0.5;
+	float maxc = max(max(unorm.x, unorm.y), unorm.z);
+	fai = vec4(unorm.xyz * maxc, maxc);
+#endif
+
+#if 0
+	vec2 enc = packNormal(normal) * 0.5 + 0.5;
+	fai = vec4(encodeUnormFloatToVec2(enc.x), encodeUnormFloatToVec2(enc.y));
+#endif
+
+#if 0
+	vec2 unorm = normal.xy * 0.5 + 0.5;
+	vec2 x = encodeUnormFloatToVec2(unorm.x);
+	vec2 y = encodeUnormFloatToVec2(unorm.y);
+	fai = vec4(x, y);
+#endif
+	//fai = packNormal(normal_);
+}
+
+vec3 readAndUnpackNormal(in sampler2D fai, in vec2 texCoord)
+{
+#if 1
+	return normalize(texture(fai, texCoord).xyz * 2.0 - 1.0);
+#endif
+
+#if 0
+	vec4 enc = texture(fai, texCoord);
+	return normalize(enc.xyz * (2.0 / enc.w) - 1.0);
+#endif
+
+#if 0
+	vec4 enc = texture(fai, texCoord);
+	vec2 enc2 = vec2(decodeVec2ToUnormFloat(enc.xy), 
+		decodeVec2ToUnormFloat(enc.zw)) * 2.0 - 1.0;
+	return unpackNormal(enc2);
+#endif
+
+#if 0
+	vec4 enc = texture(fai, texCoord);
+	vec2 xy = vec2(decodeVec2ToUnormFloat(enc.xy),
+		decodeVec2ToUnormFloat(enc.zw)) * 2.0 - 1.0;
+	float z = sqrt(1.0 - dot(xy, xy)) ;
+	vec3 snorm = vec3(xy, z);
+	return snorm;
+#endif
+	//unpackNormal(texture(fai_, texCoord_).rg)
+}
+
 #define MAX_SPECULARITY 128.0
 
 /// Pack specular stuff

+ 2 - 2
shaders/PpsSsao.glsl

@@ -43,14 +43,14 @@ uniform sampler2D noiseMap;
 /// @}
 
 #define RADIUS 0.5
-#define DARKNESS_MULTIPLIER 2.0 // Initial is 1.0 but the bigger it is the more
+#define DARKNESS_MULTIPLIER 1.0 // Initial is 1.0 but the bigger it is the more
                                 // darker the SSAO factor gets
 
 // Get normal
 vec3 getNormal(in vec2 uv)
 {
 #if USE_MRT
-	vec3 normal = unpackNormal(texture(msGFai, uv).rg);
+	vec3 normal = readAndUnpackNormal(msGFai, uv);
 #else
 	uvec2 msAll = texture(msGFai, uv).rg;
 	vec3 normal = unpackNormal(unpackHalf2x16(msAll[1]));

+ 6 - 6
src/collision/Obb.cpp

@@ -104,13 +104,13 @@ void Obb::getExtremePoints(Array<Vec3, 8>& points) const
 
 	// Reflection: x1' = 2n|x1.n| - x1
 
-	points[RBB] = 2.0 * er.dot(xAxis) * xAxis - er;
-	points[LTB] = 2.0 * er.dot(yAxis) * yAxis - er;
-	points[LBF] = 2.0 * er.dot(zAxis) * zAxis - er;
+	points[RBB] = 2.0f * er.dot(xAxis) * xAxis - er;
+	points[LTB] = 2.0f * er.dot(yAxis) * yAxis - er;
+	points[LBF] = 2.0f * er.dot(zAxis) * zAxis - er;
 
-	points[LTF] = 2.0 * points[LBB].dot(-xAxis) * -xAxis - points[LBB];
-	points[RTB] = 2.0 * points[LTF].dot(yAxis) * yAxis - points[LTF];
-	points[RBF] = 2.0 * points[LTF].dot(zAxis) * zAxis - points[LTF];
+	points[LTF] = 2.0f * points[LBB].dot(-xAxis) * -xAxis - points[LBB];
+	points[RTB] = 2.0f * points[LTF].dot(yAxis) * yAxis - points[LTF];
+	points[RBF] = 2.0f * points[LTF].dot(zAxis) * zAxis - points[LTF];
 
 	for(Vec3& point : points)
 	{

+ 1 - 1
src/event/EventManager.cpp

@@ -113,7 +113,7 @@ void EventManager::updateAllEvents(F32 prevUpdateTime_, F32 crntTime_)
 
 //==============================================================================
 std::shared_ptr<Event> EventManager::newSceneAmbientColorEvent(
-	F32 startTime, F32 duration, const Vec3& finalColor)
+	F32 startTime, F32 duration, const Vec4& finalColor)
 {
 	return registerEvent(new SceneAmbientColorEvent(startTime, duration, this, 
 		finalColor, scene));

+ 1 - 1
src/event/SceneAmbientColorEvent.cpp

@@ -6,7 +6,7 @@ namespace anki {
 
 //==============================================================================
 SceneAmbientColorEvent::SceneAmbientColorEvent(F32 startTime, F32 duration, 
-	EventManager* manager, const Vec3& finalColor_, SceneGraph* scene_)
+	EventManager* manager, const Vec4& finalColor_, SceneGraph* scene_)
 	:	Event(startTime, duration, manager), 
 		finalColor(finalColor_), 
 		scene(scene_)

+ 6 - 8
src/gl/BufferObject.cpp

@@ -15,8 +15,6 @@ namespace anki {
 /// Instead of map/unmap use glBufferSubData() when writing to the whole buffer
 #define USE_BUFFER_DATA_ON_WRITE 1
 
-#define GL_ID glId[getGlobTimestamp() % objectsCount]
-
 //==============================================================================
 // BufferObject                                                                =
 //==============================================================================
@@ -41,8 +39,8 @@ void BufferObject::destroy()
 	if(isCreated())
 	{
 		unbind();
-		glDeleteBuffers(objectsCount, &glId[0]);
-		memset(&glId[0], sizeof(Base::glId), 0);
+		glDeleteBuffers(objectsCount, &glIds[0]);
+		memset(&glIds[0], sizeof(Base::glIds), 0);
 		objectsCount = 0;
 	}
 }
@@ -66,11 +64,11 @@ void BufferObject::create(GLenum target_, U32 sizeInBytes_,
 		&& "Multibuffering with data is not making sence");
 
 	// Create
-	glGenBuffers(objectsCount, &glId[0]);
+	glGenBuffers(objectsCount, &glIds[0]);
 
 	for(U i = 0; i < objectsCount; i++)
 	{
-		glBindBuffer(target, glId[i]);
+		glBindBuffer(target, glIds[i]);
 		glBufferData(target, sizeInBytes, dataPtr, usage);
 
 		// make a check
@@ -164,7 +162,7 @@ void BufferObject::read(void* outBuff, U32 offset, U32 size)
 void BufferObject::setBinding(GLuint binding) const
 {
 	ANKI_ASSERT(isCreated());
-	glBindBufferBase(target, binding, GL_ID);
+	glBindBufferBase(target, binding, getGlId());
 	ANKI_CHECK_GL_ERROR();
 }
 
@@ -176,7 +174,7 @@ void BufferObject::setBindingRange(
 	ANKI_ASSERT(offset + size <= sizeInBytes);
 	ANKI_ASSERT(size > 0);
 
-	glBindBufferRange(target, binding, GL_ID, offset, size);
+	glBindBufferRange(target, binding, getGlId(), offset, size);
 	ANKI_CHECK_GL_ERROR();
 }
 

+ 10 - 2
src/gl/Fbo.cpp

@@ -140,8 +140,15 @@ void Fbo::setColorAttachments(const std::initializer_list<const Texture*>&
 	U i = 0;
 	for(const Texture* tex : textures)
 	{
+#if ANKI_GL == ANKI_GL_DESKTOP
+		ANKI_ASSERT(tex->getTarget() == GL_TEXTURE_2D 
+			|| tex->getTarget() == GL_TEXTURE_2D_MULTISAMPLE);
+#else
+		ANKI_ASSERT(tex->getTarget() == GL_TEXTURE_2D);
+#endif
+
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-			GL_TEXTURE_2D, tex->getGlId(), 0);
+			tex->getTarget(), tex->getGlId(), 0);
 
 		attachments[attachmentsCount++] = GL_COLOR_ATTACHMENT0 + i;
 
@@ -159,9 +166,10 @@ void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex,
 	switch(tex.getTarget())
 	{
 	case GL_TEXTURE_2D:
+	case GL_TEXTURE_2D_MULTISAMPLE:
 		ANKI_ASSERT(layer < 0 && face < 0);
 		glFramebufferTexture2D(target, attachment,
-			GL_TEXTURE_2D, tex.getGlId(), 0);
+			tex.getTarget(), tex.getGlId(), 0);
 		break;
 	case GL_TEXTURE_CUBE_MAP:
 		ANKI_ASSERT(layer < 0 && face >= 0);

+ 1 - 1
src/gl/GlState.cpp

@@ -317,7 +317,7 @@ void GlState::setDepthFunc(const GLenum val)
 #if ANKI_DEBUG
 	GLint real;
 	glGetIntegerv(GL_DEPTH_FUNC, &real);
-	ANKI_ASSERT(real == depthFunc);
+	ANKI_ASSERT((GLenum)real == depthFunc);
 #endif
 
 	if(val != depthFunc)

+ 2 - 1
src/gl/ShaderProgram.cpp

@@ -148,7 +148,8 @@ void ShaderProgramUniformVariable::set(const Texture& tex) const
 		|| getGlDataType() == GL_SAMPLER_2D_SHADOW
 		|| getGlDataType() == GL_UNSIGNED_INT_SAMPLER_2D
 		|| getGlDataType() == GL_SAMPLER_2D_ARRAY_SHADOW
-		|| getGlDataType() == GL_SAMPLER_2D_ARRAY);
+		|| getGlDataType() == GL_SAMPLER_2D_ARRAY
+		|| getGlDataType() == GL_SAMPLER_2D_MULTISAMPLE);
 	
 	glUniform1i(getLocation(), tex.bind());
 }

+ 9 - 1
src/gl/Texture.cpp

@@ -226,6 +226,7 @@ void Texture::create(const Initializer& init)
 	format = init.format;
 	type = init.type;
 	samples = init.samples;
+	ANKI_ASSERT(samples > 0);
 
 	// Bind
 	TextureUnitsSingleton::get().bindTextureAndActivateUnit(*this);
@@ -356,6 +357,7 @@ void Texture::create(const Initializer& init)
 				}
 			}
 			break;
+#if ANKI_GL == ANKI_GL_DESKTOP
 		case GL_TEXTURE_2D_MULTISAMPLE:
 			glTexImage2DMultisample(
 				target,
@@ -363,8 +365,9 @@ void Texture::create(const Initializer& init)
 				internalFormat,
 				w,
 				h,
-				GL_TRUE);
+				GL_FALSE);
 			break;
+#endif
 		default:
 			ANKI_ASSERT(0);
 		}
@@ -454,6 +457,11 @@ U Texture::bind() const
 	case GL_TEXTURE_2D_ARRAY:
 		bindingPoint = GL_TEXTURE_BINDING_2D_ARRAY;
 		break;
+#if ANKI_GL == ANKI_GL_DESKTOP
+	case GL_TEXTURE_2D_MULTISAMPLE:
+		bindingPoint = GL_TEXTURE_BINDING_2D_MULTISAMPLE;
+		break;
+#endif
 	default:
 		ANKI_ASSERT(0 && "Unimplemented");
 		break;

+ 1 - 1
src/renderer/Hdr.cpp

@@ -10,7 +10,7 @@ Hdr::~Hdr()
 //==============================================================================
 void Hdr::initFbo(Fbo& fbo, Texture& fai)
 {
-	fai.create2dFai(width, height, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
+	fai.create2dFai(width, height, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
 
 	// Set to bilinear because the blurring techniques take advantage of that
 	fai.setFiltering(Texture::TFT_LINEAR);

+ 2 - 3
src/renderer/Is.cpp

@@ -484,11 +484,10 @@ void Is::initInternal(const RendererInitializer& initializer)
 	//
 
 	// IS FBO
-	fai.create2dFai(r->getWidth(), r->getHeight(), GL_SRGB8,
+	fai.create2dFai(r->getWidth(), r->getHeight(), GL_RGB8,
 		GL_RGB, GL_UNSIGNED_BYTE);
 	fbo.create();
 	fbo.setColorAttachments({&fai});
-	fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
 
 	if(!fbo.isComplete())
 	{
@@ -894,7 +893,7 @@ void Is::run()
 	{
 		shader::CommonUniforms blk;
 		blk.planes = Vec4(r->getPlanes().x(), r->getPlanes().y(), 0.0, 0.0);
-		blk.sceneAmbientColor = Vec4(scene.getAmbientColor(), 0.0);
+		blk.sceneAmbientColor = scene.getAmbientColor();
 
 		if(groundLightEnabled)
 		{

+ 1 - 1
src/renderer/Lf.cpp

@@ -102,7 +102,7 @@ void Lf::initInternal(const RendererInitializer& initializer)
 	// Create the FAI
 	fai.create2dFai(r->getPps().getHdr().getFai().getWidth(), 
 		r->getPps().getHdr().getFai().getHeight(), 
-		GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
+		GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
 
 	fbo.create();
 	fbo.setColorAttachments({&fai});

+ 2 - 2
src/renderer/MainRenderer.cpp

@@ -67,7 +67,7 @@ void MainRenderer::initGl()
 	GlStateSingleton::get().setDepthMaskEnabled(true);
 	GlStateSingleton::get().setDepthFunc(GL_LESS);
 
-	glEnable(GL_FRAMEBUFFER_SRGB);
+	//glEnable(GL_FRAMEBUFFER_SRGB);
 
 	glDisable(GL_DITHER);
 
@@ -102,7 +102,7 @@ void MainRenderer::render(SceneGraph& scene)
 		GlStateSingleton::get().disable(GL_BLEND);
 		sProg->bind();
 #if 0
-		const Texture& finalFai = pps.getLf().fai;
+		const Texture& finalFai = ms.getFai1();
 #else
 		const Texture& finalFai = pps.getFai();
 #endif

+ 68 - 24
src/renderer/Ms.cpp

@@ -13,42 +13,53 @@ Ms::~Ms()
 {}
 
 //==============================================================================
-void Ms::init(const RendererInitializer& initializer)
+void Ms::createFbo(U index, U samples)
 {
-	try
-	{
 #if ANKI_RENDERER_USE_MRT
-		fai0.create2dFai(r->getWidth(), r->getHeight(), GL_SRGB8_ALPHA8,
-			GL_RGBA, GL_UNSIGNED_BYTE, 16);
-		fai1.create2dFai(r->getWidth(), r->getHeight(), GL_RG16F,
-			GL_RG, GL_FLOAT);
+	fai0[index].create2dFai(r->getWidth(), r->getHeight(), GL_RGBA8,
+		GL_RGBA, GL_UNSIGNED_BYTE, samples);
+	fai1[index].create2dFai(r->getWidth(), r->getHeight(), GL_RGBA8,
+		GL_RGBA, GL_UNSIGNED_BYTE, samples);
 #else
-		fai0.create2dFai(r->getWidth(), r->getHeight(), GL_RG32UI,
-			GL_RG_INTEGER, GL_UNSIGNED_INT);
+	fai0[index].create2dFai(r->getWidth(), r->getHeight(), GL_RG32UI,
+		GL_RG_INTEGER, GL_UNSIGNED_INT, samples);
 #endif
-		depthFai.create2dFai(r->getWidth(), r->getHeight(),
-			GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
-			GL_UNSIGNED_INT_24_8);
+	depthFai[index].create2dFai(r->getWidth(), r->getHeight(),
+		GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
+		GL_UNSIGNED_INT_24_8, samples);
+
+	fbo[index].create();
 
-		fbo.create();
 #if ANKI_RENDERER_USE_MRT
-		fbo.setColorAttachments({&fai0, &fai1});
+	fbo[index].setColorAttachments({&fai0[index], &fai1[index]});
 #else
-		fbo.setColorAttachments({&fai0});
+	fbo[index].setColorAttachments({&fai0[index]});
 #endif
-		fbo.setOtherAttachment(GL_DEPTH_STENCIL_ATTACHMENT, depthFai);
-		if(!fbo.isComplete())
+	fbo[index].setOtherAttachment(GL_DEPTH_STENCIL_ATTACHMENT, depthFai[index]);
+
+	if(!fbo[index].isComplete())
+	{
+		throw ANKI_EXCEPTION("FBO is incomplete");
+	}
+}
+
+//==============================================================================
+void Ms::init(const RendererInitializer& initializer)
+{
+	try
+	{
+		if(initializer.samples > 1)
 		{
-			throw ANKI_EXCEPTION("FBO is incomplete");
+			createFbo(0, initializer.samples);
 		}
+		createFbo(1, 1);
+
+		ez.init(initializer);
 	}
-	catch(std::exception& e)
+	catch(const std::exception& e)
 	{
-		throw ANKI_EXCEPTION("Cannot create deferred "
-			"shading material stage") << e;
+		throw ANKI_EXCEPTION("Failed to initialize material stage") << e;
 	}
-
-	ez.init(initializer);
 }
 
 //==============================================================================
@@ -56,7 +67,16 @@ void Ms::run()
 {
 	GlState& gl = GlStateSingleton::get();
 
-	fbo.bind();
+	// Chose the multisampled or the singlesampled FBO
+	if(r->samples > 1)
+	{
+		fbo[0].bind();
+	}
+	else
+	{
+		fbo[1].bind();
+	}
+
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
 	gl.setViewport(0, 0, r->getWidth(), r->getHeight());
@@ -86,6 +106,30 @@ void Ms::run()
 			(*it).subSpatialIndices, (*it).subSpatialIndicesCount);
 	}
 
+	// If there is multisampling then resolve to singlesampled
+	if(r->samples > 1)
+	{
+		fbo[0].bind(Fbo::FT_READ);
+		glReadBuffer(GL_COLOR_ATTACHMENT1);
+		fbo[1].bind(Fbo::FT_DRAW);
+		glDrawBuffer(GL_COLOR_ATTACHMENT1);
+
+		glBlitFramebuffer(
+			0, 0, r->width, r->height, 
+			0, 0, r->width, r->height,
+			GL_COLOR_BUFFER_BIT,
+			GL_NEAREST);
+
+		glReadBuffer(GL_COLOR_ATTACHMENT0);
+		glDrawBuffer(GL_COLOR_ATTACHMENT0);
+
+		glBlitFramebuffer(
+			0, 0, r->width, r->height, 
+			0, 0, r->width, r->height,
+			GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
+			GL_NEAREST);
+	}
+
 	// Gen mips
 	//fai0.generateMipmaps();
 

+ 1 - 1
src/renderer/Pps.cpp

@@ -34,7 +34,7 @@ void Pps::initInternal(const RendererInitializer& initializer)
 	height = initializer.height / initializer.renderingQuality;
 
 	// FBO
-	fai.create2dFai(r->getWidth(), r->getHeight(), GL_SRGB8, GL_RGB,
+	fai.create2dFai(r->getWidth(), r->getHeight(), GL_RGB8, GL_RGB,
 		GL_UNSIGNED_BYTE);
 
 	fbo.create();

+ 7 - 0
src/renderer/Renderer.cpp

@@ -23,8 +23,15 @@ void Renderer::init(const RendererInitializer& initializer)
 	height = initializer.height;
 	lodDistance = initializer.lodDistance;
 	framesNum = 0;
+	samples = initializer.samples;
 
 	// a few sanity checks
+	if(samples != 1 && samples != 4 && samples != 8 && samples != 16
+		&& samples != 32)
+	{
+		throw ANKI_EXCEPTION("Incorrect samples");
+	}
+
 	if(width < 10 || height < 10)
 	{
 		throw ANKI_EXCEPTION("Incorrect sizes");

+ 1 - 1
src/scene/Renderable.cpp

@@ -118,7 +118,7 @@ void Renderable::init(PropertyMap& pmap)
 
 	if(block)
 	{
-		ubo.create(block->getSize(), nullptr, GlMultiObject::DOUBLE_OBJECT);
+		ubo.create(block->getSize(), nullptr, GlObject::DOUBLE_OBJECT);
 	}
 
 	// Instancing sanity checks

+ 1 - 1
src/scene/SceneGraph.cpp

@@ -105,7 +105,7 @@ SceneGraph::SceneGraph()
 {
 	nodes.reserve(ANKI_SCENE_OPTIMAL_SCENE_NODES_COUNT);
 
-	ambientCol = Vec3(0.1, 0.05, 0.05) * 3;
+	ambientCol = Vec3(0.0);
 }
 
 //==============================================================================

+ 3 - 2
testapp/Main.cpp

@@ -119,7 +119,7 @@ void init()
 	ANKI_LOGI("Other init...");
 
 	SceneGraph& scene = SceneGraphSingleton::get();
-	scene.setAmbientColor(Vec3(0.04));
+	scene.setAmbientColor(Vec4(0.1, 0.05, 0.05, 0.0) * 3);
 
 #if 0
 	painter = new UiPainter(Vec2(AppSingleton::get().getWindowWidth(),
@@ -527,7 +527,7 @@ void initSubsystems(int argc, char* argv[])
 	nwinit.depthBits = 0;
 	nwinit.stencilBits = 0;
 	nwinit.fullscreenDesktopRez = true;
-	nwinit.debugContext = true;
+	nwinit.debugContext = false;
 	win = new NativeWindow;	
 	win->create(nwinit);
 
@@ -567,6 +567,7 @@ void initSubsystems(int argc, char* argv[])
 	initializer.width = win->getWidth();
 	initializer.height = win->getHeight();
 	initializer.lodDistance = 20.0;
+	initializer.samples = 16;
 
 	MainRendererSingleton::get().init(initializer);