Browse Source

- Fix camera movement in Framework.cpp used by some samples as default logic (Sponza).
- Add new argument "elapsedTime" to "userMainLoop" (can be used for movement related purposes to get stability if a fixed framerate is not used)
- Expose "newOption" in ConfigSet so samples can have custom initialization parameters
- Add "SetPitchYawRoll" to MoveComponent. Used for correct camera rotation to avoid rolling
- Added some util functions like "smoothstep", "wrap" or "sign" to Functions.h

Sergio 5 years ago
parent
commit
ff49e5ba71

+ 13 - 7
samples/common/Framework.cpp

@@ -41,10 +41,10 @@ Error SampleApp::init(int argc, char** argv, CString sampleName)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error SampleApp::userMainLoop(Bool& quit)
+Error SampleApp::userMainLoop(Bool& quit, F64 elapsedTime)
 {
 {
 	const F32 ROTATE_ANGLE = toRad(2.5f);
 	const F32 ROTATE_ANGLE = toRad(2.5f);
-	const F32 MOUSE_SENSITIVITY = 9.0f;
+	const F32 MOUSE_SENSITIVITY = 6.0f;
 	quit = false;
 	quit = false;
 
 
 	SceneGraph& scene = getSceneGraph();
 	SceneGraph& scene = getSceneGraph();
@@ -209,11 +209,17 @@ Error SampleApp::userMainLoop(Bool& quit)
 
 
 		if(in.getMousePosition() != Vec2(0.0))
 		if(in.getMousePosition() != Vec2(0.0))
 		{
 		{
-			F32 angY =
-				-ROTATE_ANGLE * in.getMousePosition().x() * MOUSE_SENSITIVITY * getMainRenderer().getAspectRatio();
-
-			mover->rotateLocalY(angY);
-			mover->rotateLocalX(ROTATE_ANGLE * in.getMousePosition().y() * MOUSE_SENSITIVITY);
+			static Vec2 sEulerYawPitch = Vec2(0.0f);
+			static Vec2 sDeadArea = Vec2(0.0f, 0.25f); // Define smooth transition area
+
+			Vec2 velocity = in.getMousePosition();
+			Vec2 velSign = Vec2(sign(velocity.x()), sign(velocity.y()));
+			velocity = velocity.abs();
+			velocity = Vec2(smoothstep(sDeadArea.x(), sDeadArea.y(), velocity.x()),
+							smoothstep(sDeadArea.x(), sDeadArea.y(), velocity.y())) * velSign;
+			sEulerYawPitch += velocity * Vec2(360.0f, 90.0f) * elapsedTime * MOUSE_SENSITIVITY;
+			sEulerYawPitch.y() = clamp(sEulerYawPitch.y(), -90.0f, 90.0f); // Avoid cycle in Y axis
+			mover->SetPitchYawRoll(toRad(sEulerYawPitch.y()), toRad(sEulerYawPitch.x()), 0.0f);
 		}
 		}
 	}
 	}
 	else
 	else

+ 1 - 1
samples/common/Framework.h

@@ -11,7 +11,7 @@ class SampleApp : public anki::App
 {
 {
 public:
 public:
 	anki::Error init(int argc, char** argv, anki::CString sampleName);
 	anki::Error init(int argc, char** argv, anki::CString sampleName);
-	anki::Error userMainLoop(anki::Bool& quit) override;
+	anki::Error userMainLoop(anki::Bool& quit, anki::F64 elapsedTime) override;
 
 
 	virtual anki::Error sampleExtraInit() = 0;
 	virtual anki::Error sampleExtraInit() = 0;
 };
 };

+ 2 - 2
samples/physics_playground/Main.cpp

@@ -102,7 +102,7 @@ class MyApp : public SampleApp
 {
 {
 public:
 public:
 	Error sampleExtraInit() override;
 	Error sampleExtraInit() override;
-	Error userMainLoop(Bool& quit) override;
+	Error userMainLoop(Bool& quit, F64 elapsedTime) override;
 };
 };
 
 
 Error MyApp::sampleExtraInit()
 Error MyApp::sampleExtraInit()
@@ -193,7 +193,7 @@ Error MyApp::sampleExtraInit()
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error MyApp::userMainLoop(Bool& quit)
+Error MyApp::userMainLoop(Bool& quit, F64 elapsedTime)
 {
 {
 	// ANKI_CHECK(SampleApp::userMainLoop(quit));
 	// ANKI_CHECK(SampleApp::userMainLoop(quit));
 
 

+ 2 - 2
samples/skeletal_animation/Main.cpp

@@ -38,7 +38,7 @@ public:
 		return Error::NONE;
 		return Error::NONE;
 	}
 	}
 
 
-	Error userMainLoop(Bool& quit) override
+	Error userMainLoop(Bool& quit, F64 elapsedTime) override
 	{
 	{
 		if(getInput().getKey(KeyCode::H) == 1)
 		if(getInput().getKey(KeyCode::H) == 1)
 		{
 		{
@@ -53,7 +53,7 @@ public:
 				.playAnimation(1, m_waveAnim, animInfo);
 				.playAnimation(1, m_waveAnim, animInfo);
 		}
 		}
 
 
-		return SampleApp::userMainLoop(quit);
+		return SampleApp::userMainLoop(quit, elapsedTime);
 	}
 	}
 };
 };
 
 

+ 2 - 2
sandbox/Main.cpp

@@ -19,7 +19,7 @@ public:
 	Bool m_profile = false;
 	Bool m_profile = false;
 
 
 	Error init(int argc, char* argv[]);
 	Error init(int argc, char* argv[]);
-	Error userMainLoop(Bool& quit) override;
+	Error userMainLoop(Bool& quit, F64 elapsedTime) override;
 };
 };
 
 
 MyApp* app = nullptr;
 MyApp* app = nullptr;
@@ -87,7 +87,7 @@ Error MyApp::init(int argc, char* argv[])
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error MyApp::userMainLoop(Bool& quit)
+Error MyApp::userMainLoop(Bool& quit, F64 elapsedTime)
 {
 {
 	F32 ang = toRad(2.5f);
 	F32 ang = toRad(2.5f);
 	F32 scale = 0.01f;
 	F32 scale = 0.01f;

+ 1 - 1
src/anki/core/App.cpp

@@ -563,7 +563,7 @@ Error App::mainLoop()
 			ANKI_CHECK(m_input->handleEvents());
 			ANKI_CHECK(m_input->handleEvents());
 
 
 			// User update
 			// User update
-			ANKI_CHECK(userMainLoop(quit));
+			ANKI_CHECK(userMainLoop(quit, crntTime - prevUpdateTime));
 
 
 			ANKI_CHECK(m_scene->update(prevUpdateTime, crntTime));
 			ANKI_CHECK(m_scene->update(prevUpdateTime, crntTime));
 
 

+ 1 - 1
src/anki/core/App.h

@@ -97,7 +97,7 @@ public:
 	ANKI_USE_RESULT Error mainLoop();
 	ANKI_USE_RESULT Error mainLoop();
 
 
 	/// The user code to run along with the other main loop code.
 	/// The user code to run along with the other main loop code.
-	virtual ANKI_USE_RESULT Error userMainLoop(Bool& quit)
+	virtual ANKI_USE_RESULT Error userMainLoop(Bool& quit, F64 elapsedTime)
 	{
 	{
 		// Do nothing
 		// Do nothing
 		return Error::NONE;
 		return Error::NONE;

+ 17 - 16
src/anki/core/ConfigSet.h

@@ -61,6 +61,23 @@ public:
 	CString getString(CString option) const;
 	CString getString(CString option) const;
 	/// @}
 	/// @}
 
 
+	/// @name Create new options.
+	/// @{
+	void newOption(CString optionName, CString value, CString helpMsg);
+
+	template<typename T, ANKI_ENABLE(std::is_integral<T>::value)>
+	void newOption(CString optionName, T value, T minValue, T maxValue, CString helpMsg = "")
+	{
+		newOptionInternal(optionName, U64(value), U64(minValue), U64(maxValue), helpMsg);
+	}
+
+	template<typename T, ANKI_ENABLE(std::is_floating_point<T>::value)>
+	void newOption(CString optionName, T value, T minValue, T maxValue, CString helpMsg = "")
+	{
+		newOptionInternal(optionName, F64(value), F64(minValue), F64(maxValue), helpMsg);
+	}
+	/// @}
+
 	ANKI_USE_RESULT Error loadFromFile(CString filename);
 	ANKI_USE_RESULT Error loadFromFile(CString filename);
 
 
 	ANKI_USE_RESULT Error saveToFile(CString filename) const;
 	ANKI_USE_RESULT Error saveToFile(CString filename) const;
@@ -93,22 +110,6 @@ private:
 	void setInternal(CString option, F64 value);
 	void setInternal(CString option, F64 value);
 	void setInternal(CString option, U64 value);
 	void setInternal(CString option, U64 value);
 
 
-	/// @name Create new options.
-	/// @{
-	void newOption(CString optionName, CString value, CString helpMsg);
-
-	template<typename T, ANKI_ENABLE(std::is_integral<T>::value)>
-	void newOption(CString optionName, T value, T minValue, T maxValue, CString helpMsg = "")
-	{
-		newOptionInternal(optionName, U64(value), U64(minValue), U64(maxValue), helpMsg);
-	}
-
-	template<typename T, ANKI_ENABLE(std::is_floating_point<T>::value)>
-	void newOption(CString optionName, T value, T minValue, T maxValue, CString helpMsg = "")
-	{
-		newOptionInternal(optionName, F64(value), F64(minValue), F64(maxValue), helpMsg);
-	}
-	/// @}
 
 
 	void newOptionInternal(CString optionName, U64 value, U64 minValue, U64 maxValue, CString helpMsg);
 	void newOptionInternal(CString optionName, U64 value, U64 minValue, U64 maxValue, CString helpMsg);
 	void newOptionInternal(CString optionName, F64 value, F64 minValue, F64 maxValue, CString helpMsg);
 	void newOptionInternal(CString optionName, F64 value, F64 minValue, F64 maxValue, CString helpMsg);

+ 9 - 1
src/anki/scene/components/MoveComponent.h

@@ -146,13 +146,21 @@ public:
 		ANKI_ASSERT(point.w() == 0.0f);
 		ANKI_ASSERT(point.w() == 0.0f);
 		const Vec4 j = Vec4(0.0f, 1.0f, 0.0f, 0.0f);
 		const Vec4 j = Vec4(0.0f, 1.0f, 0.0f, 0.0f);
 		const Vec4 vdir = (point - m_ltrf.getOrigin()).getNormalized();
 		const Vec4 vdir = (point - m_ltrf.getOrigin()).getNormalized();
-		const Vec4 vup = j - vdir * j.dot(vdir);
+		const Vec4 vup = (j - vdir * j.dot(vdir)).getNormalized();
 		const Vec4 vside = vdir.cross(vup);
 		const Vec4 vside = vdir.cross(vup);
 
 
 		Mat3x4& rot = m_ltrf.getRotation();
 		Mat3x4& rot = m_ltrf.getRotation();
 		rot.setColumns(vside.xyz(), vup.xyz(), (-vdir).xyz());
 		rot.setColumns(vside.xyz(), vup.xyz(), (-vdir).xyz());
 		markForUpdate();
 		markForUpdate();
 	}
 	}
+
+	void SetPitchYawRoll(F32 radPitch, F32 radYaw, F32 radRoll) 
+	{
+		Vec4 forward = Vec4(	cos(radYaw) * cos(radPitch),
+								sin(radPitch),
+								sin(radYaw) * cos(radPitch), 0.0f).getNormalized();
+		lookAtPoint(m_ltrf.getOrigin() + forward);
+	}
 	/// @}
 	/// @}
 
 
 private:
 private:

+ 23 - 0
src/anki/util/Functions.h

@@ -151,6 +151,13 @@ inline T max(T a, T b)
 	return (a > b) ? a : b;
 	return (a > b) ? a : b;
 }
 }
 
 
+/// Returns 1 or -1 based on the sign
+template <typename T>
+inline T sign(T v) 
+{
+	return v > 0 ? 1 : -1;
+}
+
 template<typename T>
 template<typename T>
 inline T clamp(T v, T minv, T maxv)
 inline T clamp(T v, T minv, T maxv)
 {
 {
@@ -158,6 +165,22 @@ inline T clamp(T v, T minv, T maxv)
 	return min<T>(max<T>(minv, v), maxv);
 	return min<T>(max<T>(minv, v), maxv);
 }
 }
 
 
+/// When a value goes out of bounds it cycles rom the other side
+template <typename T>
+inline T wrap(T value, T min, T max) 
+{
+	ANKI_ASSERT(min < max);
+	return (value < min) ? (max - (min - value)) : ((value > max) ? (min + (value - max)) : value);
+}
+
+/// Same as smoothstep in glsl
+template <typename T>
+inline T smoothstep(T edge0, T edge1, T value) 
+{
+	value = clamp((value - edge0) / (edge1 - edge0), (T)0, (T)1);
+	return value * value * (3 - 2 * value);
+}
+
 /// Check if a number is a power of 2
 /// Check if a number is a power of 2
 template<typename Int, ANKI_ENABLE(std::is_integral<Int>::value)>
 template<typename Int, ANKI_ENABLE(std::is_integral<Int>::value)>
 inline Bool isPowerOfTwo(Int x)
 inline Bool isPowerOfTwo(Int x)