PDA

View Full Version : camera+movement in 3d



ReneMiner
24-03-2014, 16:57
Played a little around this morning to make some use of udt-functions.

Result is a small unit-file which can be used to control camera-entity & look-at-position in 3d-space.

Simple testscript, use arrow-keys to move on XZ-plane, pageup+pagedown to move along Y-axis
hold shift-key to send input to camera directly
home-key resets the look-at-position to 0,0,0

needs attached unit-file below



Uses "TBGL"

Begin Const
%sScene = 1
'---
%eCamera = 1
%eLight ' a light-source gets attached to the camera if specified

%eLookAt ' some "pointer" to visualize the position we look at

%eBox ' some visible stuff for the eyes
%eTorus
End Const

#INCLUDE "t_Camera.tBasicU" ' that unit takes care of camera

Dim Camera As t_camera


'-----------------------------------------------------------
' Main program
'-----------------------------------------------------------

Function TBMain()

Local hWin As DWord '-- handle of window
Local scrWidth, scrHeight, scrDepth As Long '-- store screen-info
Local FrameRate As Double '-- use this for constant speed


TBGL_GetDesktopInfo(ScrWidth, ScrHeight, ScrDepth)

hWin = TBGL_CreateWindowEx( "TBGL-script, ESC to quit", _
640, 480, scrDepth, _
%TBGL_WS_WINDOWED Or %TBGL_WS_DONTSIZE Or %TBGL_WS_CLOSEBOX _
)

' -- Resets status of all keys
TBGL_ResetKeyState()
' -- open the window
TBGL_ShowWindow

If TBGL_IsWindow(hWin) Then

TBGL_SceneCreate(%sScene)
' init the camera with default white light-source attached

' |has light| Target X,Y,Z |Angle|Height|Distance
Camera.Init( %sScene, %eCamera, %eLight, 1.0, 2.0, 3.0, 360.0, 8.0, 32.0 )
' something to visualize where we look at
TBGL_EntityCreateSphere ( %sScene, %eLookAt, 0, 1)

' some stuff to please the eyes
TBGL_EntityCreateBox( %sScene, %eBox, 0, 3, 3, 3, 0, 0, 128, 255 )
TBGL_EntitySetPos ( %sScene, %eBox, 4, 3, 2 )
TBGL_EntityCreateTorus ( %sScene, %eTorus, 0, 2, 4, 0, 255, 0, 128 )
TBGL_EntitySetPos ( %sScene, %eTorus, -2, -3, -4 )

EndIf


' -- Main-Loop

While TBGL_IsWindow(hWin)

FrameRate = TBGL_GetFrameRate

' -- proceed inputs:

If TBGL_GetWindowKeyState(hWin, %VK_ESCAPE) Then Exit While

If TBGL_GetWindowKeyState(hWin, %VK_SHIFT) Then
' input moves camera

If TBGL_GetWindowKeyState(hWin, %VK_UP) Then
Camera.ZoomIn()
ElseIf TBGL_GetWindowKeyState(hWin, %VK_DOWN) Then
Camera.ZoomOut()
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGUP) Then
' height-change-speed depends on total distance
Camera.Lift( Sqr(Pow(Camera.Distance, 2) + Pow(Camera.Height, 2)) * Framerate/1000 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGDN) Then
Camera.Lift(-Sqr(Pow(Camera.Distance, 2) + Pow(Camera.Height, 2)) * FrameRate/1000 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_LEFT) Then
Camera.Turn(-FrameRate/16 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_RIGHT) Then
Camera.Turn( FrameRate/16 )
EndIf

Else

' input moves look-at-position (target) then

If TBGL_GetWindowKeyState(hWin, %VK_UP) Then
Camera.MoveTarget(%Move_Forward, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_DOWN) Then
Camera.MoveTarget(%Move_Backward, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGUP) Then
Camera.MoveTarget(%Move_Up, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGDN) Then
Camera.MoveTarget(%Move_Down, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_LEFT) Then
Camera.MoveTarget(%Move_Left, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_RIGHT) Then
Camera.MoveTarget(%Move_Right, FrameRate/1000)

ElseIf TBGL_GetWindowKeyState(hWin, %VK_HOME) Then
' simply look at 0,0,0
Camera.SetTargetPos( 0.0, 0.0, 0.0 )
EndIf

EndIf




TBGL_ClearFrame

' place a "look-at-pointer" so we don't lose orientation in space
TBGL_EntitySetPos(%sScene, %eLookAt, Camera.Target.X, Camera.Target.Y, Camera.Target.Z )

TBGL_SceneRender(%sScene)
TBGL_DrawFrame


Wend

End Function

Petr Schreiber
24-03-2014, 21:44
Hi Rene,

I like your camera encapsulation a lot! The only complaint is regarding frame rate synchronization for MoveTarget - it is too fast on my PC when holding shift :D


Petr

ReneMiner
24-03-2014, 22:03
yes- there's a bug hidden. Finder= keeper ;)
FrameRate not used when Shift nor calls .MoveTarget - or something like that - but at least the direction it moves is correct...

Mostly (but not 100% clean) - I wanted to use a unit for each Type and it's functions and the idea was to have some



Alias #Include "types_name_here.tBasicU" As #IncludeType types_name_here


which will do nothing special but be better readeable as first - but type-units have to be in same folder as main-program then, i fear. (EDIT- or they have a special TYPES-subfolder)
Second thought: it would tell thinBasic that unit contains only one type and it's functions and #IncludeType could be restricted to that.

And: the unit looks awesome clearly structured in codebrowser I could get addicted to it :D

ReneMiner
25-03-2014, 10:42
I could not leave it like that and I fine-tuned just a little bit- changed something in the script and in the unit-file, so "FrameRate As Double" is not a global to both- and actually make use of it now hopefully correct.

See first post for changes.
_________________________________________________________________________________________

Something else I discovered, check this example and keep thinking of type-unit-files:


Uses "console"

Type t_myType
Static MaxWidth As Long
End Type

Dim T1 As t_myType
Dim T2 As t_myType

T1.MaxWidth = 123

PrintL "T1:" + T1.MaxWidth
PrintL "T2:" + T2.MaxWidth

PrintL Repeat$(50,"-") + $CRLF

T2.MaxWidth = 321

PrintL "T1:" + T1.MaxWidth
PrintL "T2:" + T2.MaxWidth

PrintL Repeat$(50,"-") + $CRLF
PrintL "Key to end"
WaitKey


I do have to dim some variable to assign a value that is common to all variables of this type then.

Why is there no way to assign a default-value to the "shared" subset (here MaxWidth) without having to specify a variables name?
(except Me in Function .Init() using some local static doOnce for example)
The only way is to call a sub, dim a local of that type and assign the values in that sub.
After leaving the sub the variable is destroyed - but the assigned value stays in place for all later dimensioned of this type.
example:


Uses "console"

Type t_myType
Static MaxWidth As Long
End Type

Sub assign_shared()
Local a As t_myType
a.MaxWidth = 567
End Sub

assign_shared

Dim T1 As t_myType
Dim T2 As t_myType

PrintL "T1:" + T1.MaxWidth
PrintL "T2:" + T2.MaxWidth

PrintL Repeat$(50,"-") + $CRLF
PrintL "Key to end"
WaitKey


2 possible uses I have in mind:

Shared Variable - as current static in type
Shared Const - never changes

so the Const-Expressions of the type-unit would/could always have a variable-names-prefix and read as


x = Camera.MaxDistance
'or
x = Me.MaxDistance
' even
x= Me.%MaxDistance ' is thinkable
'instead of
x = %MaxCamDistance


maybe I should move this to suggestions - but then the context might get lost...

ErosOlmi
25-03-2014, 12:47
maybe I should move this to suggestions - but then the context might get lost...
Adding in Suggestions is not bad idea, just add the title and refer to this post.

Anyway, interesting: assigning a default value in Static variable inside a TYPE is something I should develop.


Type t_myType
Static MaxWidth As Long Value 123
End Type

Difficult is how to get back that value without creating a variable of that type.
Maybe I should let use static variables in string and numeric expression like:

If t_myType.MaxWidth > [Whatever] Then
...
End If
I need to understand if I can

Ciao
Eros

ReneMiner
25-03-2014, 14:30
ok, I suggested (http://www.thinbasic.com/community/project.php?issueid=458) it and moved the rest from here over there since it goes way off-topic

+ one more test-script, needs the unit attached to first post.

Now can move in 3d by mouse- same as keyboard-
hold left mouse for movement in XZ-plane, hold right mousebutton for up/down
hold additional shift-key to change the camera-height, -angle and -distance



Uses "TBGL"

Begin Const
%sScene = 1
'---
%eCamera = 1
%eLight ' a light-source gets attached to the camera if specified

%eLookAt ' some "pointer" to visualize the position we look at

%eBox ' some visible stuff for the eyes
%eTorus
End Const

#INCLUDE "t_Camera.tBasicU" ' that unit takes care of camera

Dim Camera As t_camera

Dim keepRunning As Boolean = TRUE




'-----------------------------------------------------------
' Main program
'-----------------------------------------------------------

Function TBMain()

Local hWin As DWord '-- handle of window
Local scrWidth, scrHeight, scrDepth As Long '-- store screen-info
Local FrameRate As Double '-- use this for constant speed


TBGL_GetDesktopInfo(ScrWidth, ScrHeight, ScrDepth)

hWin = TBGL_CreateWindowEx( "TBGL-script, ESC to quit", _
640, 480, scrDepth, _
%TBGL_WS_WINDOWED Or %TBGL_WS_DONTSIZE Or %TBGL_WS_CLOSEBOX _
)

' -- Resets status of all keys
TBGL_ResetKeyState()
' -- open the window
TBGL_ShowWindow

If TBGL_IsWindow(hWin) Then

TBGL_SceneCreate(%sScene)
' init the camera with default white light-source attached

' |has light| Target X,Y,Z |Angle|Height|Distance
Camera.Init( %sScene, %eCamera, %eLight, 1.0, 2.0, 3.0, 360.0, 8.0, 32.0 )
' something to visualize where we look at
TBGL_EntityCreateSphere ( %sScene, %eLookAt, 0, 1)

' some stuff to please the eyes
TBGL_EntityCreateBox( %sScene, %eBox, 0, 3, 3, 3, 0, 0, 128, 255 )
TBGL_EntitySetPos ( %sScene, %eBox, 4, 3, 2 )
TBGL_EntityCreateTorus ( %sScene, %eTorus, 0, 2, 4, 0, 255, 0, 128 )
TBGL_EntitySetPos ( %sScene, %eTorus, -2, -3, -4 )

EndIf


' -- Main-Loop

While TBGL_IsWindow(hWin) And keepRunning And TRUE


FrameRate = TBGL_GetFrameRate

Input_proceed hWin, Framerate




TBGL_ClearFrame

' place a "look-at-pointer" so we don't lose orientation in space
TBGL_EntitySetPos(%sScene, %eLookAt, Camera.Target.X, Camera.Target.Y, Camera.Target.Z )

TBGL_SceneRender(%sScene)
TBGL_DrawFrame


Wend

End Function

Sub Input_proceed(ByRef hWin As DWord, ByVal FrameRate As Double)

Static MouseX As Long
Static MouseY As Long
Static MouseDeltaX As Long
Static MouseDeltaY As Long
Static MouseWheel As Long

Static bDone As Boolean



If TBGL_GetWindowKeyState(hWin, %VK_ESCAPE) Then
keepRunning = FALSE
Exit Sub
EndIf

If bDone Then
' skip this in very first frame
MouseDeltaX = TBGL_MouseGetPosX - MouseX
MouseDeltaY = TBGL_MouseGetPosY - MouseY
MouseWheel = TBGL_MouseGetWheelDelta
EndIf



If TBGL_GetWindowKeyState(hWin, %VK_SHIFT) Then
' input moves camera

If TBGL_GetWindowKeyState(hWin, %VK_UP) Then
Camera.ZoomIn()
ElseIf TBGL_GetWindowKeyState(hWin, %VK_DOWN) Then
Camera.ZoomOut()
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGUP) Then
' height-change-speed depends on total distance
Camera.Lift( Sqr(Pow(Camera.Distance, 2) + Pow(Camera.Height, 2)) * Framerate/1000 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGDN) Then
Camera.Lift(-Sqr(Pow(Camera.Distance, 2) + Pow(Camera.Height, 2)) * FrameRate/1000 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_LEFT) Then
Camera.Turn(-FrameRate/16 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_RIGHT) Then
Camera.Turn( FrameRate/16 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_LBUTTON) Then
If Abs(MouseDeltaX) > Abs(MouseDeltaY) Then
Camera.Turn( FrameRate / 64 * -MouseDeltaX)
Else
If MouseDeltaY > 0 Then
Camera.ZoomOut()
ElseIf MouseDeltaY < 0 Then
Camera.ZoomIn()
EndIf
EndIf
ElseIf TBGL_GetWindowKeyState(hWin, %VK_RBUTTON) Then
Camera.Lift(-MouseDeltaY * Sqr(Pow(Camera.Distance, 2) + Pow(Camera.Height, 2)) * FrameRate/2000 )

EndIf

Else

' input moves look-at-position (target) then

If TBGL_GetWindowKeyState(hWin, %VK_UP) Then
Camera.MoveTarget(%Move_Forward, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_DOWN) Then
Camera.MoveTarget(%Move_Backward, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGUP) Then
Camera.MoveTarget(%Move_Up, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_PGDN) Then
Camera.MoveTarget(%Move_Down, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_LEFT) Then
Camera.MoveTarget(%Move_Left, FrameRate/1000)
ElseIf TBGL_GetWindowKeyState(hWin, %VK_RIGHT) Then
Camera.MoveTarget(%Move_Right, FrameRate/1000)

ElseIf TBGL_GetWindowKeyState(hWin, %VK_HOME) Then
' simply look at 0,0,0 again
Camera.SetTargetPos( 0.0, 0.0, 0.0 )
ElseIf TBGL_GetWindowKeyState(hWin, %VK_LBUTTON) Then
If Abs(MouseDeltaX) > Abs(MouseDeltaY) Then
If MouseDeltaX > 0 Then
Camera.MoveTarget(%Move_Right, FrameRate / 4000 * MouseDeltaX)
Else
Camera.MoveTarget(%Move_Left, FrameRate / 4000 * Abs(MouseDeltaX))
EndIf
Else
If MouseDeltaY > 0 Then
Camera.MoveTarget(%Move_Backward, FrameRate/4000 * MouseDeltaY)
Else
Camera.MoveTarget(%Move_Forward, FrameRate/4000 * Abs(MouseDeltaY))
EndIf
EndIf
ElseIf TBGL_GetWindowKeyState(hWin, %VK_RBUTTON) Then
If MouseDeltaY > 0 Then
Camera.MoveTarget(%Move_Down, FrameRate/4000 * MouseDeltaY)
Else
Camera.MoveTarget(%Move_Up, FrameRate/4000 * Abs(MouseDeltaY))
EndIf
EndIf
EndIf

If MouseWheel < 0 Then
Camera.ZoomOut()
ElseIf MouseWheel > 0 Then
Camera.ZoomIn()
EndIf

MouseX = TBGL_MouseGetPosX
MouseY = TBGL_MouseGetPosY

bDone = TRUE

End Sub

Petr Schreiber
30-03-2014, 11:00
Hi Rene,

could you please upload the latest t_Camera unit? I cannot run the example, as the interface changed.


Petr

ReneMiner
30-03-2014, 11:37
of course, i just tested: example above runs using this unit (same attachement as in mandelbrot-thread)

+ some other thing to play with, colorful, senseless,
additional R-key to toggle auto-rotation