Calculate UV Coords on Sprite from Mouse Coords

Blitz3D Forums/Blitz3D Programming/Calculate UV Coords on Sprite from Mouse Coords

Matty(Posted 2007) [#1]
Hello,

for a simple game I'm working on I need to be able to 'camerapick' sprites to work out whether a masked/alphaed pixel/texel has been picked. I'm using an orthographic projection (Camera aligned to vector -1,-1,1 in x,y,z coords). As you know the pick commands do not work with sprites using 'polygon' pick detection.

I have managed to write some code that does what I need (it returns the UV location on a sprite's texture) by a bit of trial and error with particular numeric values taking in to account the camera zoom and sprite scale and sprite handleoffset (handlesprite command)

However - there is obviously an equation/formula which would be able to give me this result for any camera zoom, for any sprite scale and any sprite 'handlesprite' offset.

If someone would be able to assist with this I would appreciate that.

Thanks very much.

EDIT - here is the code I currently use to do this:

CameraProject camera,EntityX(Creature\SpriteHandle,True),EntityY(Creature\SpriteHandle,True)+(Template\SpriteScale)^2*0.35,EntityZ(Creature\SpriteHandle,True)
		f#=0.0105 ;I'd like to know how to calculate what this factor should be rather than just using one from trial and error
		ulx=ProjectedX()-(template\spritescale/(f)) ;0.015 is the camera zoom with the orthographic camera in use
		uly=ProjectedY()-((template\spritescale)/(f))	
		lrx=ProjectedX()+(template\spritescale/(f))
		lry=ProjectedY()+((template\spritescale)/(f))
		;Color 255,255,255
		;Rect ulx,uly,Abs(lrx-ulx),Abs(lry-uly),0
		If MX>=ulx And MY>=uly And MX<lrx And MY<lry And LRX<>ULX And LRY<>ULY Then 
			;we are within this creature's bounding box for the sprite texture
			If Creature\TexHandle<>0 Then 
				;this creature has a valid texture handle...hopefully.we'll soon see.
				;convert the coordinates into UV coords for the texture....(mx and my are mouse coordinates)
				U#=Float(MX-ULX)/Float(Abs(LRX-ULX))
				V#=(Float(MY-ULY)/Float(Abs(LRY-ULY)))
				If U<0 Then U=0
				If V<0 Then V=0
				If U>1 Then U=1
				If V>1 Then V=1
				SetBuffer TextureBuffer(Creature\TexHandle)
				XCoord=TextureWidth(Creature\TexHandle)*U
				YCoord=TextureHeight(Creature\TexHandle)*V
				If XCoord>=TextureWidth(Creature\TexHandle) Then XCoord=TextureWidth(Creature\TexHandle)-1
				If YCoord>=TextureHeight(Creature\TexHandle) Then YCoord=TextureHeight(Creature\TexHandle)-1


That is a short snippet, I haven't included the type declarations but it should be fairly obvious what is going on there...


Beaker(Posted 2007) [#2]
It would probably be easiest to create a quad representing (or completly replacing) the sprite. Then use polygon picking and this PickedU(),PickedV() code from the code archive.


Matty(Posted 2007) [#3]
Thanks Beaker -I'd seen that but the problem with the pick commands is they ignore transparency meaning I cannot pick a sprite behind another sprite if their quad overlaps.

That is why I'd like to do it this way. I might try using a quad which gets scaled to the size of the sprite and rotated/translated appropriately as a reference for the corner positions.


Damien Sturdy(Posted 2007) [#4]
How aboot, use Pick, then check the alpha. If transparent, ignore this pick and do another extending from it?


Matty(Posted 2007) [#5]
Thanks all, I've worked it out, using quads instead of sprites and Tformpointing the positions of the upper left and lower right vertices, then interpolating the UV from that. Works perfectly.

Quite simple in the end. Although I am using an orthographic camera which makes pointing the sprites at the camera very easy to...

If anyone is interested here is my code: (please note a lot of variables are not described very well..or at all)

Surface=GetSurface(Creature\SpriteHandle,1)
		TFormPoint VertexX(Surface,1),VertexY(Surface,1),VertexZ(Surface,1),Creature\SpriteHandle,0
		CameraProject Camera,TFormedX(),TFormedY(),TFormedZ()
		lrx=ProjectedX()
		uly=ProjectedY()
		TFormPoint VertexX(Surface,3),VertexY(Surface,3),VertexZ(Surface,3),Creature\SpriteHandle,0
		CameraProject Camera,TFormedX(),TFormedY(),TFormedZ()
		ulx=ProjectedX()
		lry=ProjectedY()
;		Color 255,255,255
	;	Rect ulx,uly,Abs(lrx-ulx),Abs(lry-uly),0

                If ulx>lrx Then templx=ulx:ulx=lrx:lrx=templx
		If uly>lry Then temply=uly:uly=lry:lry=temply

If MX>=ulx And MY>=uly And MX<lrx And MY<lry And LRX<>ULX And LRY<>ULY Then 
			;we are within this creature's bounding box for the sprite texture
			If ValidTexture(Creature\TexHandle) Then 
				;this creature has a valid texture handle...hopefully.we'll soon see.
				;convert the coordinates into UV coords for the texture....
				U#=Float(MX-ULX)/Float(Abs(LRX-ULX))
				V#=(Float(MY-ULY)/Float(Abs(LRY-ULY)))
				If U<0 Then U=0
				If V<0 Then V=0
				If U>1 Then U=1
				If V>1 Then V=1
				SetBuffer TextureBuffer(Creature\TexHandle)
				XCoord=TextureWidth(Creature\TexHandle)*U
				YCoord=TextureHeight(Creature\TexHandle)*V
				If XCoord>=TextureWidth(Creature\TexHandle) Then XCoord=TextureWidth(Creature\TexHandle)-1
				If YCoord>=TextureHeight(Creature\TexHandle) Then YCoord=TextureHeight(Creature\TexHandle)-1
				LockBuffer
					Col=ReadPixelFast( Xcoord,YCoord)
				;	If Col<>0 Then WritePixel Xcoord,YCoord,(255 Shl 24) Or 255 Shl 8
						
				UnlockBuffer
				SetBuffer BackBuffer()
					If ((Col Shr 24) And 255)<>0 Then 
						
						
						PokeInt PickBank,0,Creature\PivotHandle
						PokeFloat PickBank,4,EntityX(Creature\PivotHandle,True)
						PokeFloat PickBank,8,EntityY(Creature\PivotHandle,True)
						PokeFloat PickBank,12,EntityZ(Creature\PivotHandle,True)
						Return 
					EndIf 
				
		
			EndIf 
		EndIf