PDA

View Full Version : pressing key once are not instantaneous



zak
26-01-2012, 12:04
of course it is not instantaneous but i want to convey something.
while trying a program called modelviewer http://psch.thinbasic.com/forum/index.php?topic=12.0;prev_next=prev
i come across a situation that pressing move key once as fast as we can are not compatible with the x=x+0.001 as an example, and the object will move more than what we intended by x=x+0.001.
after visualizing the issue i think that the loop go across the "If GetAsyncKeyState(%VK_D) Then x = x + 0.001"" tens or even hundreds of times before the old man heavy finger release his (fast!!) press on the key so the x advanced more and more than intended.
so if we insert a SLEEP function to allow the heavy finger to move up from the key then the x will increased approximately more precisely, and this depends on the speed of your cpu.
like this:
If GetAsyncKeyState(%VK_W) Then
Sleep(30)
LightZ -= 0.005
EndIf
i have found that Petr suggested using sleep before in a bug reported by me http://www.thinbasic.com/community/project.php?issueid=21&filter=all#note2163 but i forget it completely.
also i have found recently a very great function TBGL_GetWindowKeyOnce wich are absolutley precise but you can use it only step by step like this:
If TBGL_GetWindowKeyOnce( hWnd, %VK_W ) Then
'TBGL_ResetKeyState()
'Sleep(delay)
LightZ -= 0.005
EndIf
suitable for moving /rotating models and figures precisely.
if you have added :
TBGL_ResetKeyState()
Sleep(delay)
then it will function like the GetAsyncKeyState/TBGL_GetAsyncKeyState with SLEEP.
the attached example are extracted from the modelviewer mentioned above and manipulated to reflect the issue.
use W,S to move the ball more precisely through the triangle.
use A,D to move the ball horizontally (not precisely)
use <,> to rotate the triangle
i placed the figure in this specific orientation to ask Petr an intuitive question :if there is a hope that the ball when penetrate the triangle can leave a hole in the figure in which we can see through it and whats behind.
i have attached with_tiger_skin2 it is originally posted by Petr in the famous waterpatch example to show that the ball almost will go tear the skin and make a hole in it ,but we can't display a hole since the model are already loaded. for more info look "3D curves texturing between mathematica and thinbasic (http://www.thinbasic.com/community/showthread.php?10835-3D-curves-texturing-between-mathematica-and-thinbasic)"

P.S: i have an idea to make a hole at run time,this is to deal with the object as in the physical world, composed from many smaller objects (such as molecules). and collectively it is making the whole bigger object.
now if a ball penetrate this big object it is simply erase some smaller objects in its path. we just distroy those smaller objects.
i will investigate this approach. even it is possibly a cpu heavy task.

Petr Schreiber
26-01-2012, 21:00
Hi Zak,

thanks for sharing your discoveries!

I would add one more advice, which makes possible to not use SLEEP at all, and still have full control.

The approach with:


' -- This results in increasing x by 0.1 once per FRAME
x = x + 0.1
Has the general problem of being too dependant on performance on given machine.

If the script runs at 60FPS, holding the key for 1 second will make the object moved by 0.1 * 60 = 6 units

If the script runs at 1000FPS (yes, it is possible), holding the key for 1 second will make the object moved by 0.1 * 1000 = 100 units.

If we take unit as meter, it is difference of 6 meters vs. 100 meters... quite a lot :)

The approach used for example in computer games, or other application, is performance synchronised movement.

This very simple technique consists in measuring the actual time the frame took to render, and scaling the movement by this.

You can achieve this by measuring the time one frame takes to render on your own, for example using the new cTimer class, or HiResTimer_Get commands.

Even simpler is to use build in TBGL_GetFrameRate function, which will return a number reporting how many frames per second the loop can run.

There is simple relation between these two, where:


timeSpentRenderingFrame = 1 / frameRate ' -- in seconds

frameRate = 1 / timeSpentRenderingFrame ' -- in frames per second


The second approach can be applied quite simply in two steps:
- retrieving the current frame rate once per render cycle:


frameRate = TBGL_GetFrameRate


- scaling the movement by this value:


' -- This means holding the key will result in movement of 0.1 meter per second
x = x + 0.1 / frameRate


This approach is independent on PC performance, and will most likely result in the same speed of movement across different PCs.
I wrote "most likely", because the measurement works with 1 frame old data, so in case the frame rate changes a lot, it can introduce slight imprecision. This can be filtered out by using more advanced math mechanisms (various filters, using average and so on).

I modified the first example to demonstrate this and slightly modernised the used commands. The movement is now done in way it occurs at 1 m/s and the rotations at 90 degrees/second, but this can be of course tuned as you wish:


Uses "TBGL"

Dim hWnd As DWord
Dim Distance As Single = 3
Dim Rot_Y As Single = 45

hWnd = TBGL_CreateWindowEx("move the light: z_coord:WS xy_coord: DA, rotate: arrow keys >,<", 640, 480, 32, %TBGL_WS_WINDOWED)
TBGL_ShowWindow

Dim LightX, LightY, LightZ As Single
LightX = 0: LightY = 1:LightZ = 0

TBGL_UseLighting TRUE
TBGL_UseLightSource %GL_LIGHT0, TRUE
TBGL_SetLightParameter %GL_LIGHT0, %TBGL_LIGHT_DIFFUSE, 1, 1, 1, 1
TBGL_SetLightParameter %GL_LIGHT0, %TBGL_LIGHT_POSITION, LightX, LightY, LightZ, 0

TBGL_ResetKeyState() ' Resets ESC key status before checking

Dim frameRate As Double

While TBGL_IsWindow(hWnd)

frameRate = TBGL_GetFrameRate

TBGL_ClearFrame

' Camera settings
TBGL_Camera 0, Distance, Distance, 0, 0, 0

TBGL_Rotate Rot_Y, 0, 1, 0
TBGL_SetLightParameter %GL_LIGHT0, %TBGL_LIGHT_POSITION, LightX, LightY, LightZ, 0

TBGL_Color 255, 255, 255
TBGL_Box 0.5, 0.5, 0.5

TBGL_PushMatrix
TBGL_Color 255, 128, 0
TBGL_Translate LightX, LightY, LightZ
TBGL_Sphere 0.1
TBGL_PopMatrix

tbgl_DrawFrame

If TBGL_GetWindowKeyState(hWnd, %VK_RIGHT) Then Rot_Y -= 90/FrameRate ' 90 degrees/second

If TBGL_GetWindowKeyState(hWnd, %VK_LEFT) Then Rot_Y += 90/FrameRate

If TBGL_GetWindowKeyState(hWnd, %VK_W) Then
LightZ -= 1/FrameRate ' 1 meter/second
EndIf

If TBGL_GetWindowKeyState(hWnd, %VK_S) Then
LightZ += 1/FrameRate ' 1 meter/second
EndIf
If TBGL_GetWindowKeyState(hWnd, %VK_A) Then LightX -= 1/FrameRate ' 1 meter/second
If TBGL_GetWindowKeyState(hWnd, %VK_D) Then LightX += 1/FrameRate ' 1 meter/second

If TBGL_GetWindowKeyState(hWnd, %VK_P) Then LightY += 1/FrameRate ' 1 meter/second
If TBGL_GetWindowKeyState(hWnd, %VK_L) Then LightY -= 1/FrameRate ' 1 meter/second

If TBGL_GetWindowKeyState(hWnd, %VK_ESCAPE) Then Exit While

Wend

TBGL_DestroyWindow



Petr

zak
26-01-2012, 22:20
Hi Petr
thanks for the detailed description of the Framerate usage, now i can see why you have used it in your original modelview example, and i havn't used it.
indeed i have tried my examples on two computers one slow and the other speedier and they are different in the speed they present the move/rotation. but using the framerate they are almost approximately the same.
thanks