浏览代码

Smoothed input even at high frame rates

Marko Pintera 11 年之前
父节点
当前提交
976574faea
共有 4 个文件被更改,包括 34 次插入14 次删除
  1. 1 1
      BansheeOISInput/Include/BsInputHandlerOIS.h
  2. 15 11
      BansheeOISInput/Source/BsInputHandlerOIS.cpp
  3. 2 2
      ExampleProject/Main/Main.cpp
  4. 16 0
      Polish.txt

+ 1 - 1
BansheeOISInput/Include/BsInputHandlerOIS.h

@@ -161,7 +161,7 @@ namespace BansheeEngine
 		INT32 mMouseSampleAccumulator[2];
 		INT32 mMouseSampleAccumulator[2];
 		float mMouseSmoothedAxis[2];
 		float mMouseSmoothedAxis[2];
 		UINT32 mLastMouseUpdateFrame;
 		UINT32 mLastMouseUpdateFrame;
-		bool mMouseSamplesObsolete;
+		float mMouseSampleCounter;
 
 
 		UINT64 mTimestampClockOffset;
 		UINT64 mTimestampClockOffset;
 	};
 	};

+ 15 - 11
BansheeOISInput/Source/BsInputHandlerOIS.cpp

@@ -53,7 +53,7 @@ namespace BansheeEngine
 
 
 	InputHandlerOIS::InputHandlerOIS(unsigned int hWnd)
 	InputHandlerOIS::InputHandlerOIS(unsigned int hWnd)
 		:mInputManager(nullptr), mKeyboard(nullptr), mMouse(nullptr), mTimestampClockOffset(0),
 		:mInputManager(nullptr), mKeyboard(nullptr), mMouse(nullptr), mTimestampClockOffset(0),
-		mLastMouseUpdateFrame(0), mMouseSamplesObsolete(true)
+		mLastMouseUpdateFrame(0), mMouseSampleCounter(0.0f)
 	{
 	{
 		mMouseSampleAccumulator[0] = 0;
 		mMouseSampleAccumulator[0] = 0;
 		mMouseSampleAccumulator[1] = 0;
 		mMouseSampleAccumulator[1] = 0;
@@ -193,6 +193,13 @@ namespace BansheeEngine
 			gamepadData.gamepad->capture();
 			gamepadData.gamepad->capture();
 		}
 		}
 
 
+		// We limit mouse sampling to at least 6ms interval because lower values might cause
+		// incorrect 0-sized samples to be introduced as DirectInput is not able to sample
+		// the mouse quick enough, which might cause jitter in the movement.
+		mMouseSampleCounter += gTime().getFrameDelta();
+		if (mMouseSampleCounter < 0.006f)
+			return;
+
 		float rawXValue = 0.0f;
 		float rawXValue = 0.0f;
 		float rawYValue = 0.0f;
 		float rawYValue = 0.0f;
 
 
@@ -208,18 +215,21 @@ namespace BansheeEngine
 			rawYValue = (float)mMouseSampleAccumulator[1];
 			rawYValue = (float)mMouseSampleAccumulator[1];
 		}
 		}
 
 
-		mMouseSamplesObsolete = true;
+		mMouseSampleAccumulator[0] = 0;
+		mMouseSampleAccumulator[1] = 0;
 
 
 		// Scale by time so that we are framerate independant: rawXValue = rawXValue * (MOUSE_MAX_TIME / gTime().getFrameDelta());
 		// Scale by time so that we are framerate independant: rawXValue = rawXValue * (MOUSE_MAX_TIME / gTime().getFrameDelta());
 		// Scale to valid [-1.0, 1.0] range: rawXValue / (MOUSE_DPI * MOUSE_MAX)
 		// Scale to valid [-1.0, 1.0] range: rawXValue / (MOUSE_DPI * MOUSE_MAX)
 		// This is just the combination of the two:
 		// This is just the combination of the two:
 
 
-		float axisScale = ((MOUSE_DPI * MOUSE_MAX) / MOUSE_MAX_TIME) * gTime().getFrameDelta();
+		float axisScale = ((MOUSE_DPI * MOUSE_MAX) / MOUSE_MAX_TIME) * mMouseSampleCounter;
 
 
 		RawAxisState xState;
 		RawAxisState xState;
 		xState.rel = -Math::clamp(rawXValue / axisScale, -1.0f, 1.0f);
 		xState.rel = -Math::clamp(rawXValue / axisScale, -1.0f, 1.0f);
 		xState.abs = xState.rel; // Abs value irrelevant for mouse
 		xState.abs = xState.rel; // Abs value irrelevant for mouse
 
 
+		LOGWRN(toString(xState.rel));
+
 		onAxisMoved(0, xState, (UINT32)InputAxis::MouseX);
 		onAxisMoved(0, xState, (UINT32)InputAxis::MouseX);
 
 
 		RawAxisState yState;
 		RawAxisState yState;
@@ -227,6 +237,8 @@ namespace BansheeEngine
 		yState.abs = yState.rel; // Abs value irrelevant for mouse
 		yState.abs = yState.rel; // Abs value irrelevant for mouse
 		
 		
 		onAxisMoved(0, yState, (UINT32)InputAxis::MouseY);
 		onAxisMoved(0, yState, (UINT32)InputAxis::MouseY);
+
+		mMouseSampleCounter = 0.0f;
 	}
 	}
 
 
 	void InputHandlerOIS::_inputWindowChanged(const RenderWindow& win)
 	void InputHandlerOIS::_inputWindowChanged(const RenderWindow& win)
@@ -253,14 +265,6 @@ namespace BansheeEngine
 
 
 	bool InputHandlerOIS::mouseMoved(const OIS::MouseEvent& arg)
 	bool InputHandlerOIS::mouseMoved(const OIS::MouseEvent& arg)
 	{
 	{
-		if (mMouseSamplesObsolete)
-		{
-			mMouseSampleAccumulator[0] = 0;
-			mMouseSampleAccumulator[1] = 0;
-
-			mMouseSamplesObsolete = false;
-		}
-
 		mMouseSampleAccumulator[0] += arg.state.X.rel;
 		mMouseSampleAccumulator[0] += arg.state.X.rel;
 		mMouseSampleAccumulator[1] += arg.state.Y.rel;
 		mMouseSampleAccumulator[1] += arg.state.Y.rel;
 
 

+ 2 - 2
ExampleProject/Main/Main.cpp

@@ -84,14 +84,14 @@ int CALLBACK WinMain(
 	Application::startUp(renderWindowDesc, RenderSystemPlugin::DX11);
 	Application::startUp(renderWindowDesc, RenderSystemPlugin::DX11);
 
 
 	// Imports all of ours assets and prepares GameObject that handle the example logic.
 	// Imports all of ours assets and prepares GameObject that handle the example logic.
-	//setUpExample();
+	setUpExample();
 	
 	
 	// Runs the main loop that does most of the work. This method will exit when user closes the main
 	// Runs the main loop that does most of the work. This method will exit when user closes the main
 	// window or exits in some other way.
 	// window or exits in some other way.
 	Application::instance().runMainLoop();
 	Application::instance().runMainLoop();
 
 
 	// Perform cleanup
 	// Perform cleanup
-	//shutDownExample();
+	shutDownExample();
 
 
 	Application::shutDown();
 	Application::shutDown();
 
 

+ 16 - 0
Polish.txt

@@ -18,10 +18,26 @@ Polish TODO:
  - Test checking out source and extracting dependencies and see if it compiles
  - Test checking out source and extracting dependencies and see if it compiles
  - Test compiling on another PC
  - Test compiling on another PC
 
 
+Automatically release resources on shutdown instead of forcing the user to manually call unload() and set handles to nullptr.
+ - e.g. just invalidate all handles automatically
+
 Input issues:
 Input issues:
  - I cannot have input of 1 one frame and input of 0 another. This happens when frames are too short. I might need to add very short smoothing times?
  - I cannot have input of 1 one frame and input of 0 another. This happens when frames are too short. I might need to add very short smoothing times?
  - I cannot have input set to 1 during the entire frame if the frame is very long and user just moved the mouse a bit.
  - I cannot have input set to 1 during the entire frame if the frame is very long and user just moved the mouse a bit.
    - This might be even more of an issue with joystick axes as I currently have no mechanism of knowing what % of the frame are they being moved.
    - This might be even more of an issue with joystick axes as I currently have no mechanism of knowing what % of the frame are they being moved.
+ - Maybe: Ability to define input sampling rate. Input sampling then runs on its own thread at 120/240/etc/Hz. Every frame the collected values are averaged.
+   - This could be a part of OIS. Mouse sampling should already be doing something similar.
+   - I can't think of ANY other way gamepad axes can work with long frame times, other than this approach
+   - Check DirectInput::Poll
+   - And DirectInput::GetDeviceState to get immediate mouse data
+     - Check if this state is an absolute value, difference from last call or what.
+   - Potentially also GetRawInputData as I might be able to use that instead of windows messages
+ - Probably remove UE4 smoothing as I'm not even sure what it does
+
+Problem with current OIS mouse approach is that if I call capture() too often, no new sampling data is available 
+but the mouse might still be moving and it just reports 0. Which is wrong if the mouse is moving.
+ - These is no way around this if querying the state too quickly. I can either keep the current system and remember
+   last 5-10ms of input and average that, or I can use the above solution with polling which should have the similar effect.
 
 
 -----------------
 -----------------