CameraZoom question

Blitz3D Forums/Blitz3D Programming/CameraZoom question

Axel Wheeler(Posted 2008) [#1]
Hi there,

I'm trying to invoke CameraZoom with the mouse wheel, which works fine. Then I thought, "Hey, why not have it zoom toward the mouse pointer screen location?" I thought it would be simple to grab the coordinates of the current mouse pointer location on the screen, but in a 3D world the pointer isn't on a single coordinate; it is on a ray extending from the camera.

However, I'm using CameraProjMode(cam,2) as this is really a 2D game (I just want the 3D shading and other features of meshes), so in fact there is no Z dimension. There is exactly one x and y location under the pointer. Any ideas how to get it? (Then I can move cam to that x,y and zoom in or out)

I'm trying to use CameraPick, but that requires a mesh. I put a big cube in the background and set its entitypickmode to 3 and its entitybox to the same size & shape as the cube, but seems to work only sometimes, pretty much randomly, which is really odd. There are no other collisions going on.

Is there a better way?

Thanks in advance!


Axel Wheeler(Posted 2008) [#2]
So either nobody knows or nobody understands the question. (Or nobody gives a smeg).

Let's try again:

You know how in Google Maps you use the scroll wheel to zoom in and out? And how it zooms in and out toward the place you are pointing to?

Well I want to do that in my Blitz3D game. I'm viewing it in orthographic projection (cameraprojmode(cam,2), so only x and y are relevant. It should be possible to find the world x and y coords from the mousex() and mousey() values and the current camerazoom().

(Why not just use 2D graphics instead, you ask? Because 3D graphics make it much easier to add shading and such.)

Anyone?


KingPod(Posted 2008) [#3]
you could use mousex and mousey for a very simple way to do this.

find out what coords the centre of screen is
work out where the mouse is in relation to this
move the camera a fraction of the distance that the mouse if offset by

hope that helps

KingPod


Axel Wheeler(Posted 2008) [#4]
KingPod,

Thanks for the reply.

Yes, your method is the one I'm using. It's the middle step - work out where the mouse is in relation to coords at the center of the screen - that is the tricky bit. That's trying to relate mouse position in pixels to world coordinates.

I guess the question can be restated; how many world units per pixel are there for a given camerazoom? (in CameraProjMode(cam,2) - orthographic projection).

CameraPick would solve it, but works unreliably for me in this view. Any ideas on that front?


KingPod(Posted 2008) [#5]
could you be more specific in how camerapick is unreliable?
have you checked the pickmode ect?

to find out the pixels you will have to experiment for yourself i guess. it depends how far the field is looking, how close your objects are to the camera and the camerazoom.


Stevie G(Posted 2008) [#6]
Re camerapick being unreliable, how are you setting the entitybox? Never had a problem with it myself. You should set it up like so, for example ...

cube = createcube()
scalemesh cube, 10,10,1
entitypickmode cube, 3
entitybox cube, -10,-10,-1,20,20,2

Failing that - post some code which shows your issue and it's probably fixable.


Axel Wheeler(Posted 2008) [#7]
Wow, thanks Stevie G. I don't generally use collisions so the structure of the EntityBox parameters was news to me. I made the mistake of thinking that "position" of the box meant the origin, not the upper left.

The documentation says:

EntityBox entity,x#,y#,z#,width#,height#,depth#
Parameters
entity - entity handle#
x# - x position of entity's collision box
y# - y position of entity's collision box
z# - z position of entity's collision box
width# - width of entity's collision box
height# - height of entity's collision box
depth# - depth of entity's collision box



No mention that the "position" means something different than an entity position.

In any event I was using a pick_geometry of 2, which shouldn't require EntityBox anyway, but still wasn't working for me. pick_geometry of 3 works fine now, once the box is set right.

As soon as I put the correct method of entitybox(-1000000,-1000000,-50,20000000,2000000,1) it works fine!

Oddly, the documentation example for PickedEntity uses a plane, no box, and pick_geometry of 2 (i.e. same as mine was) and does work, but the way I have it now is good enough.)

Thanks again.


Axel Wheeler(Posted 2008) [#8]
Here's the program. No need to fix anything, just thought I'd give it to you for helping me. I put some onscreen instructions, but of course it's very crude at this point. I don't actually know what it's going to be yet. (I know planets don't bounce off suns, but it's fun to watch!)

Graphics3D(1280,1024,32,2)

SetBuffer(BackBuffer())
AppTitle("2D Orbital Simulator")
SeedRnd(MilliSecs())

Global gravity#=10.0
Global frame
Global camzoom#=.01
Global maxtrailage=100000
Global maxalt#

Global marker1,marker2
marker1=CreateCube()
marker2=CreateCube()
PositionEntity(marker2,1,0,0)


;background=CreatePlane()
;RotateEntity(background,-90,0,0)
;EntityAlpha(background,.5)
background=CreateCube()
;ScaleEntity(background,1000,1000,1)
PositionEntity(background,0,0,-50)
;EntityColor(background,0,0,0)
EntityType(background,2)
EntityBox(background,-1000000000,-1000000000,-50,2000000000,2000000000,1)
EntityPickMode(background,3)

cam=CreateCamera()
CameraZoom(cam,camzoom)
CameraProjMode(cam,2)
PositionEntity(cam,0,0,-100)
;RotateEntity(cam,90,0,0)

sun=CreateLight()
RotateEntity(sun,10,-30,0)
LightColor(sun,255,255,128)

Global planet=CreateSphere(32)
;EntityPickMode(planet,1)
;EntityColor(planet,32,128,200)
RotateEntity(planet,90,0,0)
EntityColor(planet,255,255,128)
ScaleEntity(planet,10,10,10)

planetlight=CreateLight(2)
LightColor(planetlight,16,16,16)


Type satellite
	Field e
	Field size#
	Field x#
	Field y#
	Field xspeed#
	Field yspeed#
	Field red#
	Field green#
	Field blue#
	Field lastbounce
End Type

Type trail
	Field e
	Field satellite.satellite
	Field x#
	Field y#
	Field createdtime
End Type

Global particle=CreateMesh()
surface=CreateSurface(particle)
AddVertex(surface,1,-1,0)
AddVertex(surface,-1,-1,0)
AddVertex(surface,0,1,0)
AddTriangle(surface,0,1,2)
EntityColor(particle,255,255,255)
ScaleEntity(particle,.2,.2,.2)
EntityFX(particle,1)
UpdateNormals(particle)

For i=1 To 10
	thissatellite=createsatellite()
Next

AmbientLight(128,128,255)

While Not KeyHit(1)
	Local mzs#=MouseZSpeed()
	If mzs<>0
		CameraPick(cam,MouseX(),MouseY())
		CameraProject(cam,PickedX(),PickedY(),PickedZ())
		PositionEntity(cam,PickedX(),PickedY(),-100)
		MoveMouse(GraphicsWidth()/2.0,GraphicsHeight()/2.0)
		;PositionEntity(cam,EntityX(cam)+mzs*(MouseX()-GraphicsWidth()/2.0)/(10000.0*camzoom),EntityY(cam)-mzs*(MouseY()-GraphicsHeight()/2.0)/(10000.0*camzoom),-100)
		camzoom=camzoom*.1*(10+mzs)
		CameraZoom(cam,camzoom)
	EndIf
	If KeyDown(208); Up arrow
		PositionEntity(cam,EntityX(cam),EntityY(cam)-100,-100)
	EndIf
	If KeyDown(200); Down arrow
		PositionEntity(cam,EntityX(cam),EntityY(cam)+100,-100)
	EndIf
	If KeyDown(203)
		PositionEntity(cam,EntityX(cam)-100,EntityY(cam),-100)
	EndIf
	If KeyDown(205)
		PositionEntity(cam,EntityX(cam)+100,EntityY(cam),-100)
	EndIf
	frame=frame+1
	updategravity()
	killoldtrails()
	RenderWorld()
	pe=PickedEntity()
	If pe<>0 Then Text(0,0,"pickedentity="+pe);EntityName(pe))
	Text(0,20,"Highest Altitude="+maxalt)
	Text(0,40,"EntityX(cam)="+EntityX(cam)+"   EntityY(cam)="+EntityY(cam))
	Text(10,GraphicsHeight()-90,"Scroll-wheel zooms in/out.  Right-click to enlarge planets if necessary.  There should be 10 planets.")
	Text(10,GraphicsHeight()-75,"Distances can be extreme.  If the Hightest Altitude parameter (top-left) is high (i.e. thousands or more),")
	Text(10,GraphicsHeight()-60,"zoom way out And hold the Right mouse button To enlarge the planets Until you find it.")
	Flip()
	Delay(10)
Wend

Function createsatellite()
	pivot=CreatePivot()
	this.satellite=New satellite
	Repeat
		this\size=Rnd(.5,3.0);2.0
;		this\x=Rnd(-60,60)
;		this\y=Rnd(-60,60)
;		this\xspeed=Rnd(-.5,.5)
;		this\yspeed=Rnd(-.5,.5)
		Repeat
			altitude#=1.0/Rnd(1)
			angle#=Rnd(360)
			RotateEntity(pivot,0,0,angle)
			MoveEntity(pivot,altitude,0,0)
			this\x=EntityX(pivot);altitude*ACos(angle);1.0/Rnd(1);Rnd(-10000,10000)*Rnd(1)
			this\y=EntityY(pivot);altitude*ASin(angle);1.0/Rnd(1);Rnd(-10000,10000)*Rnd(1)
		Until Sqr(this\x*this\x+this\y*this\y)+this\size>10
		
		speed#=10.0/Rnd(1)-10.0
		direction#=Rnd(360)
		this\xspeed=speed*Cos(direction);1.0/Rnd(1)-1;Rnd(-10,10)*Rnd(1)
		this\yspeed=speed*Sin(direction);1.0/Rnd(1)-1;Rnd(-10,10)*Rnd(1)
		
		PositionEntity(pivot,this\x,this\y,0)
		netspeed#=Sqr(this\xspeed*this\xspeed+this\yspeed*this\yspeed)
		altitude#=EntityDistance(pivot,planet)
		gravforce#=gravity/(altitude*altitude)
		escapevelocity#=Sqr(2.0*gravforce*altitude)
	Until netspeed<escapevelocity
	
	this\e=CreateSphere(16)
		;this\y=this\y+this\y
	RotateMesh(this\e,90,0,0)
	ScaleEntity(this\e,this\size,this\size,this\size)
	PositionEntity(this\e,this\x,this\y,0)
	Repeat
		this\red=(Rnd(0,255)+Rnd(0,255))/2.0
		this\green=(Rnd(0,255)+Rnd(0,255))/2.0
		this\blue=(Rnd(0,255)+Rnd(0,255))/2.0
	Until this\red+this\green+this\blue>400
	EntityColor(this\e,this\red,this\green,this\blue)
	;EntityAlpha(this\e,.9)
	FreeEntity(pivot)
End Function

Function drawtrails()
	now=MilliSecs()
	For thistrail.trail=Each trail
		age=now-thistrail\createdtime
		If age>100
			Delete thistrail
		Else
			agecolor#=255.0-255.0*(age/100.0)
			
		EndIf
	Next
End Function

Function killoldtrails()
	Local now=MilliSecs()
	Local thistrail.trail=First trail
	If thistrail<>Null
		While now-(thistrail\createdtime)>maxtrailage
			FreeEntity(thistrail\e)
			Delete(thistrail)
			thistrail=First trail
		Wend
	EndIf
End Function

Function updategravity()
	maxalt=0.0
	For this.satellite=Each satellite
		If MouseDown(2)
			If .01*this\size/camzoom>this\size Then ScaleEntity(this\e,.01*this\size/camzoom,.01*this\size/camzoom,this\size)
		Else
			ScaleEntity(this\e,this\size,this\size,this\size)
		EndIf
		killit=False
		f#=frame/10.0
		If f=frame/10
			thistrail.trail=New trail
			thistrail\e=CopyEntity(particle)
			EntityColor(thistrail\e,this\red,this\green,this\blue)
			thistrail\satellite=this
			thistrail\x=this\x
			thistrail\y=this\y
			PositionEntity(thistrail\e,thistrail\x,thistrail\y,0)
			thistrail\createdtime=MilliSecs()
		EndIf
		
		altitude#=EntityDistance(this\e,planet)
		If altitude>maxalt Then maxalt=altitude
		
		minalt#=10.0+this\size
		If altitude<minalt
			If this\lastbounce<>0 And frame-this\lastbounce<100
				killit=True
			Else
				this\lastbounce=frame
				checkalt#=2*10.0-altitude
				checkx#=this\x*checkalt/altitude
				checky#=this\y*checkalt/altitude
				checkdestx#=this\x+this\xspeed
				checkdesty#=this\y+this\yspeed
				checkdestalt#=Sqr(checkdestx*checkdestx+checkdesty*checkdesty)
				destalt#=(2*10.0-checkdestalt#)*.995
				
				destx#=checkdestx*destalt/checkdestalt
				desty#=checkdesty*destalt/checkdestalt
				
				
				this\xspeed=(destx-checkx);this\x
				this\yspeed=(desty-checky);this\y
				If destalt<10.0+this\size Then destalt=(10.0+this\size)*2.0-destalt
				destx#=checkdestx*destalt/checkdestalt
				desty#=checkdesty*destalt/checkdestalt
			EndIf
			;this\yspeed=-this\yspeed
			;this\xspeed=-this\xspeed
			
			;killit=True
		Else
			gravforce#=gravity/(altitude*altitude)
			this\xspeed=this\xspeed-gravforce*this\x/altitude
			this\yspeed=this\yspeed-gravforce*this\y/altitude
		EndIf
		this\x=this\x+this\xspeed
		this\y=this\y+this\yspeed
		
		PositionEntity(this\e,this\x,this\y,0)
		If killit=True
			FreeEntity(this\e)
			Delete(this)
			For thistrail.trail=Each trail
				If thistrail\satellite=this
					FreeEntity(thistrail\e)
					Delete(thistrail)
				EndIf
			Next
			createsatellite()
		EndIf
	Next
End Function



Stevie G(Posted 2008) [#9]
Not bad. I'd reduce the scale otherwise you're going to run into floating point precision issues and strange things will start to happen.


Axel Wheeler(Posted 2008) [#10]
Yeah. I wanted to simulate the actual range issues involved in orbits. (i.e. Mercury vs. the Oort Cloud). I use 1.0/rnd(1.0)-1.0 to generate both the starting altitude and the speed. Then I calculate the escape velocity from that; if it's exceeds the excape velocity it starts from scratch. So even the very distant ones are in orbit, just verrrrry sloooow.

As far as going too slow to clear the center star, there's no easy way to measure that, so it just kills them after two bounces sufficiently close in time, and creates a new one.

The result is an evolved solar system without limits but still looking pretty good. Next I'll have all the objects interact with each other. Maybe. We'll see.

Game ideas:

Something like Asteroids but with gravity; you have to defend your home planet (a random orbiter) from all the others. But if you shoot them when they are crossing your orbit the bits will still cross your orbit.

Interplanetary war game (slower pace, of course)

Planet Pong? :)