Moving the Camera vs. Moving the Terrain

Blitz3D Forums/Blitz3D Beginners Area/Moving the Camera vs. Moving the Terrain

Mahan(Posted 2011) [#1]
Hi guys,

Instead of moving the camera I'd like to move the terrain below to achieve the same effect.

I want my camera being static @ x=0, y=0, z=0 but i want the movement of the terrain below give the illusion of the camera moving.

I've played around a little but somehow my brain is locked up and I'd really appreciate a hint on where to continue.

If you try out my program that I've come up with this far, you'll see that when using Left-Shift the camera is moving and everything is working as designed. But strange things happen when i try to simulate the same behavior without Left-Shift pressed (i.e. when i move the terrain itself, and try to turn the view using a pivot.)

Program keys:

WASD - navigation
Arrow-Keys - turning and tilting

Left-Shift - Use normal camera movement.

R - reset everything and start over


Const KEY_ESC=				1
Const KEY_W=				17
Const KEY_A=				30
Const KEY_S=				31
Const KEY_D=				32
Const KEY_UP=				200
Const KEY_DOWN=				208
Const KEY_LEFT=				203
Const KEY_RIGHT=			205
Const KEY_R=				19
Const KEY_LEFTSHIFT=		42

Graphics3D(800, 600, 0, 2)
Local plane = CreateTerrain(8)
EntityColor(plane, 127, 127, 255)
PositionEntity(plane, -4, -2, -4)

Local cam=CreateCamera()
Local camPivot=CreatePivot(cam)
Local light=CreateLight()

While Not KeyDown(KEY_ESC)
	
	If KeyDown(KEY_R) 
		;reset everything
		EntityParent(plane, 0)
		RotateEntity(cam, 0, 0, 0)
		PositionEntity(cam, 0, 0, 0)
		RotateEntity(plane, 0, 0, 0)
		PositionEntity(plane, -4, -2, -4)
		FreeEntity(camPivot)
		camPivot=CreatePivot(cam)		
	EndIf 
	
	
	Local xmov = KeyDown(KEY_A)-KeyDown(KEY_D)
	Local zmov = KeyDown(KEY_W)-KeyDown(KEY_S)
	Local xturn = KeyDown(KEY_UP)-KeyDown(KEY_DOWN)
	Local yturn = KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT)
	
	
	If KeyDown(KEY_LEFTSHIFT)
		;moving by camera, static entity
		EntityParent(plane, 0)
		MoveEntity(cam, xmov * 0.1, 0, zmov * 0.1)
		TurnEntity(cam, xturn, yturn, 0)
	Else
		;static camera, moving entity
		EntityParent(plane, camPivot)
		MoveEntity(plane, xmov * -0.1, 0, zmov * -0.1)
		TurnEntity(camPivot, -xturn, -yturn, 0)
	EndIf
	
	UpdateWorld()
	RenderWorld()
	Flip()
Wend




Kryzon(Posted 2011) [#2]
Blitz3D doesn't work with matrices, which would fit like a glove to this coordinate-context changing you want.
When you move with the camera itself (with left shift), it's in its own space. When you move everything while the camera is standing still, you need to move and rotate objects within the camera's local space so it appears that it's the camera itself that is moving.

While Blitz3D provides a way for you to know the value of a vector transformed into different spaces, it doesn't for rotations. So we do have a way to fake the camera's movement, but not its rotation.
MoveEntity works locally: doing a MoveEntity(entity,0,0,+1) will move any entity forward, whatever direction it's facing. Doing the same with rotations is not as simple.
Anyway, here's what I came up with (I've modified your code directly):
Const KEY_ESC=				1
Const KEY_W=				17
Const KEY_A=				30
Const KEY_S=				31
Const KEY_D=				32
Const KEY_UP=				200
Const KEY_DOWN=			208
Const KEY_LEFT=				203
Const KEY_RIGHT=			205
Const KEY_R=				19
Const KEY_LEFTSHIFT=			42

Graphics3D(800, 600, 0, 2)

Local cam=CreateCamera()
Local camPivot=CreatePivot()
Local light=CreateLight()
Local FPSTimer = CreateTimer(60)

Local plane = CreateTerrain(8,camPivot) ;Parented to 'camPivot', which is the "peg" that will move everything. Any object in the level needs to be parented to this.

EntityColor(plane, 127, 127, 255)
PositionEntity(plane, -4, -2, -4)

While Not KeyDown(KEY_ESC)
	WaitTimer(FPSTimer) ;Limit the frame-rate so it doesn't use 100% CPU.
	
	If KeyDown(KEY_R) 
		;Reset everything.
		ResetTransform(cam)
		ResetTransform(camPivot)
	EndIf 
	
	
	Local xmov = KeyDown(KEY_A)-KeyDown(KEY_D)
	Local zmov = KeyDown(KEY_W)-KeyDown(KEY_S)
	Local xturn = KeyDown(KEY_UP)-KeyDown(KEY_DOWN)
	Local yturn = KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT)
	
	
	If KeyDown(KEY_LEFTSHIFT)
		;Moving by camera, static entity.
		TFormVector(-xmov*0.1, 0, zmov*0.1, cam, 0) ;Transform from 'cam' to 'world'.
		TranslateEntity(cam, TFormedX(), TFormedY(), TFormedZ())
		
		TurnEntity(cam, xturn, yturn, 0)
	Else
		;Static camera, moving entity.
		TFormVector( xmov*0.1, 0, -zmov*0.1, cam, 0) ;Transform from 'cam' to 'world'.
		TranslateEntity(camPivot, TFormedX(), TFormedY(), TFormedZ())
		
		TurnEntity(cam, xturn, yturn, 0)
	EndIf
	
	UpdateWorld()
	RenderWorld()
	
	Flip()
Wend

Function ResetTransform(entity%)
	PositionEntity(entity,0,0,0)
	RotateEntity(entity,0,0,0)
	ScaleEntity(entity,1,1,1)
End Function 
It still uses the camera's own rotation when not holding the shift key, but when doing so, the movement at least is all faked.
I used TFormVector to retrieve a transformed movement-vector. I want to strafe left and right, so I transform a local 'xmov*0.1' vector on the entity's local X axis to the world-space coordinate system, which takes into account the entity's rotation. It'll move left wherever it may be facing.
Since I'm already using a transformed vector, I can't use MoveEntity (which also works similarly, working locally within each entity's local-space); so I use TranslateEntity which works with world coordinates only: I transformed my vector into world-space, so I need to use a function that expects world-space values.

An easier way to imagine what TFormVector does:
• Look into any random direction, and point with your hand towards it: this direction is your Z+ local axis.
• Now consider the world's Z+ axis - it won't point in the same direction. You would have to use TFormVector(0,0,+1, Me, 0) to retrieve with TFormedX(),Y() and Z() the direction your arm would be pointing in relation to the world's origin.

Last edited 2011


Mahan(Posted 2011) [#3]
Thank you very much! That's a lot more than I hoped for!

Now I have a lot to check out but at a quick glance your code seems very good and fitting for my intended usage.

Rotating the camera in place @(0, 0, 0) will probably work perfectly well, since the original problem was that I didn't want to get very high coord-values for the camera, to avoid the loss of floating point precision.


EDIT: Even ymov (new variable) works when added to TFormVector(). Nice!

Last edited 2011


Rob the Great(Posted 2011) [#4]

An easier way to imagine what TFormVector does:
• Look into any random direction, and point with your hand towards it: this direction is your Z+ local axis.
• Now consider the world's Z+ axis - it won't point in the same direction. You would have to use TFormVector(0,0,+1, Me, 0) to retrieve with TFormedX(),Y() and Z() the direction your arm would be pointing in relation to the world's origin.


Ah, beautiful. I've always wanted to understand that command more, but I haven't been able to fully grasp it 'til now. I knew what it would do, but not how to use it.