Need alignment math help!

Blitz3D Forums/Blitz3D Programming/Need alignment math help!

Finjogi(Posted 2006) [#1]
Okay, here goes.. Sprites face to the camera nicely usually but if I parent sprite to object that moves and spins then sprite does not seem to do that. Goal is to make sprites one(two) axis to be in line with object whic is its parent and still turn its face to camera like sprites usually do (like trees in Castle.bb example..)

here is mockup for result I want:

In .bb example below sprite sits nicely to its parent end but rolls all too wrong..





b32(Posted 2006) [#2]
Do you want to make the sprite smaller when viewed from the back ? Maybe you could use a few round sprites in a row with a descending alpha ?


Chroma(Posted 2006) [#3]
I'm on it.


Chroma(Posted 2006) [#4]
HandleSprite is the culprit.

Try this:




Finjogi(Posted 2006) [#5]
bram32: thats the usual way to do that but not the way I want :)

Chroma:
It did not seem to fix it.. when using "SpriteViewMode sp,4" (which i want to use :) ) it does not matter which command to position sprite, HandleSprite or PositionEntity.
Exhaust sprite still rolls with the tube.

AlignToVector should make this work but it is bit hazy to me how calc suitable vector.. I know that one alignment vector from sprite should cross camera Z axis.. and still sprites other two axis should be same as tubes.. so rolling is only thing I want to adjust.


Stevie G(Posted 2006) [#6]
Finjogi,

You simply can't use a sprite entity in this situation. In order to align it the way you're looking for you'd need to use a quad and continuously update the vertices relative to the camera. Also, you'd need to use different textures depending on it's angle to the camera.

TBH, I think you're over-complicating this and should just use a mesh ... once textured it'll look much better than some overcomplex aligned quad.

I guess that's not what you want but I'll leave an example of what I mean.

Stevie

Graphics3D 640,480,32,2

light = CreateLight()
cam = CreateCamera()
PositionEntity cam, 0, 0, -10

tube = CreateCylinder( 12,True )
RotateMesh tube, 90, 0, 0
FitMesh tube, -1,-1,-2,2,2,2
EntityColor tube, 128,128,128

flame = CreateCone( 12, False, tube )
RotateMesh flame, 90, 0, 0
FitMesh flame, -1,-1,0,2,2,1
EntityAlpha flame, .25
EntityColor flame, 250,150,50

While Not KeyDown(1)


	TurnEntity tube,1,1,1

	ScaleEntity flame, 1, 1, Rnd( .5, 10 )

	RenderWorld
	Flip True
Wend

End 



Defoc8(Posted 2006) [#7]
A=emitter to camera vector
B=emitter eject vector -> the direction of the burner
C=cross product of those vectors..
-C=opposite of C

position top and bottom verts using C, and -C..these should
be unit vectors perpendicular to the plane formed by the vectors A and B.

These vectors are the up and down positions of the verts,
you need to scale them to radius of your burner, and add the
burner position - resulting in the first two vertex positions
in world space.. the end vertices are simply offsets from
these two points, along the emitter vector..

hope that wasnt too hard to follow...there may be easier
ways to create cylindrical billboards..but this method
works quite well..


Finjogi(Posted 2006) [#8]
Defoc8: Thanks for tips, It did not need to build verts every frame. And yes, like you wrote, cross product was my missing part and so now it works, with sprites :)



And here is whole code + sprite images:
exhaust.zip


b32(Posted 2006) [#9]
Cool! Looks very nice.


PoliteProgrammer(Posted 2006) [#10]
This looks fantastic. But I have run up against a problem. I've tried importing the effect into my own program, and used it to obtain a laser effect.

The problem is that the lasers lie in the vertical direction, not the horizontal direction, and can when I rotate the camera, the sprites are flat when sometimes viewed from the sides. This leads me to believe that i've made a mistake in the alignment, somehow.

Any advice?

Here's the code. (I've edited it to contain only the essential parts.)

graphicsX = 1280
graphicsY = 1024

Graphics3D graphicsX, graphicsY, 32, 1
SetBuffer = BackBuffer()

Type laserType
Field pivot, sprite, colour$, status$, speed#, damage#, range#, distanceTravelled# 
Field x#, y#, z#, x2#, y2#, z2#, cx#, cy#, cz#, tx#, ty#, tz#, vx#, vy#, vz#
End Type
Dim laserArray.laserType(9999)
For i = 0 To 9999
  laserArray(i) = New laserType
  laserArray(i)\status = "Dead" 
Next

BlueLaserSprite = LoadSprite("BlueLaser.bmp", 1+8+16+32)

While Not KeyDown(1) 
WaitTimer(frameTimer)

  ; Fire Player's Primary Weapons
  If MouseHit(1)
    Gosub playerPrimaryWeapons
  EndIf

  ; Keep Track of all Weapons
  Gosub Weapons


RenderWorld
Flip True
Wend 
End 

.Weapons

  For i = 0 To 9999
    If laserArray(i)\status = "Alive"
     TranslateEntity laserArray(i)\pivot, -laserArray(i)\speed*Sin(EntityYaw(laserArray(i)\pivot)), -laserArray(i)\speed*Sin(EntityPitch(laserArray(i)\pivot)), laserArray(i)\speed*Cos(EntityYaw(laserArray(i)\pivot))

     laserArray(i)\x# = EntityX(laserArray(i)\pivot, True)
     laserArray(i)\y# = EntityY(laserArray(i)\pivot, True)
     laserArray(i)\z# = EntityZ(laserArray(i)\pivot, True)	
     laserArray(i)\x2# = EntityX(camera, True)
     laserArray(i)\y2# = EntityY(camera, True)
     laserArray(i)\z2# = EntityZ(camera, True)
	
	 laserArray(i)\cx# = laserArray(i)\x# - laserArray(i)\x2#
	 laserArray(i)\cy# = laserArray(i)\y# - laserArray(i)\y2#
	 laserArray(i)\cz# = laserArray(i)\z# - laserArray(i)\z2#
	
	 TFormVector 0,0,-1, laserArray(i)\pivot,0 
       laserArray(i)\tx# = TFormedX()
	 laserArray(i)\ty# = TFormedY()
	 laserArray(i)\tz# = TFormedZ()	
	
	
	
	 laserArray(i)\vx# =  laserArray(i)\cy# * laserArray(i)\tz# - laserArray(i)\cz# * laserArray(i)\ty# 
	 laserArray(i)\vy# =  laserArray(i)\cz# * laserArray(i)\tx# - laserArray(i)\cx# * laserArray(i)\tz#
	 laserArray(i)\vz# =  laserArray(i)\cx# * laserArray(i)\ty# - laserArray(i)\cy# * laserArray(i)\tx#	
	
	AlignToVector(laserArray(i)\sprite, laserArray(i)\vx#, laserArray(i)\vy#, laserArray(i)\vz#, 1)

	AlignToVector(laserArray(i)\sprite, laserArray(i)\tx#, laserArray(i)\ty#, laserArray(i)\tz#, 2)
	
   EndIf
 Next

Return


.playerPrimaryWeapons
  i = 0
  Repeat
    If laserArray(i)\status = "Dead"

      ; Speed and other variables should be set here, determined by what weapon is firing.
      laserArray(i)\status = "Alive"
      laserArray(i)\speed = 0.1
      
      laserArray(i)\pivot = CreatePivot()
      PositionEntity laserArray(i)\pivot, EntityX(masterPivot), EntityY(masterPivot), EntityZ(masterPivot)
      RotateEntity laserArray(i)\pivot, EntityPitch(playerPivot), EntityYaw(playerPivot), 0


      ;Set Up Laser Sprite
      laserArray(i)\sprite = CopyEntity(BlueLaserSprite)
      SpriteViewMode laserArray(i)\sprite, 4
      ScaleSprite laserArray(i)\sprite, 1, 10
      EntityFX laserArray(i)\sprite, 17
      EntityParent laserArray(i)\sprite, laserArray(i)\pivot, False

      Exit

    Else
      i = i + 1
    EndIf

  Forever
  i = 0
Return





Finjogi(Posted 2006) [#11]
Working example would be helpful :)
I guess some vector calc goes wrong because camera moves/rotates.. I'll try to check how camera movement/rotation affects alignment on my simple example..

edit: Yep, if I move the camera then "tube to cam" vector calc goes nuts.. back to bug hunt :)


PoliteProgrammer(Posted 2006) [#12]
Okay, here's my entire code. Apart from the player model itself, everything should be in working order.
I changed the player model to a cone for you.
Most non-essential code covering other things has been removed.

graphicsX = 1280
graphicsY = 1024

Graphics3D graphicsX, graphicsY, 32, 1
SetBuffer = BackBuffer()
AntiAlias True
WBuffer True
frameTimer = CreateTimer(60)


Type userType
Field currentMode$
End Type
user.userType = New userType
user\currentMode = "FreeCamera"


Type weaponType
Field xOffset#, yOffset#, zOffset#, weaponName$, charge#, requiredCharge#, ammunition, heat#, hitPoints#, model
End Type 





Type fighterType
Field model, speed#, inertiaRating#, primaryWeapon.weaponType
End Type
player.fighterType = New fighterType
player\primaryWeapon.weaponType = New weaponType



Type laserType
Field pivot, sprite, colour$, status$, speed#, damage#, range#, distanceTravelled# 
Field x#, y#, z#, x2#, y2#, z2#, cx#, cy#, cz#, tx#, ty#, tz#, vx#, vy#, vz#
End Type
Dim laserArray.laserType(9999)
For i = 0 To 9999
  laserArray(i) = New laserType
  laserArray(i)\status = "Dead" 
Next



BlueLaserSprite = LoadSprite("C:\Documents and Settings\James Robinson\Desktop\Stuff\Blitz and Idea\Blitz3D\MY PROGRAMS\Star Wars\Sprites and Textures\BlueLaser.bmp", 1+8+16+32)


Gosub LoadAllModels

; Create required pivots
masterPivot = CreatePivot()
PositionEntity masterPivot, 0, 0, -120000
cameraPivot = CreatePivot(masterPivot)
playerPivot = CreatePivot(masterPivot)


; Create Player
player\model = createcone(8, True, playerPivot)

; The player model should point towards the star initially.

PositionEntity player\model, EntityX(masterPivot), EntityY(masterPivot), EntityZ(masterPivot)
EntityParent player\model, playerPivot

; Important! All game models are hidden initially.
ShowEntity player\model


; Create a camera and make cameraPivot the parent of the camera. 
camera = CreateCamera(cameraPivot) 
TranslateEntity camera, 0, 0, -30
CameraRange camera, 1, 99999999999

; Create a light.
light = CreateLight() 
RotateEntity light, 90, 0, 0 


; Create a star and define a pivot to orbit the planets around.
star = CreateSphere(32)
PositionEntity star, 0, 0, 0
EntityColor star, 255, 150, 0
ScaleEntity star, 60000, 60000, 60000


; Hide mouse pointer and move to screen center initially.
HidePointer
MoveMouse 640, 512









While Not KeyDown(1) 
WaitTimer(frameTimer)

  ; Make player's ship move
  Gosub playerMovement

  ; Fire Player's Primary Weapons
  If MouseHit(1)
    Gosub playerPrimaryWeapons
  EndIf

  ; Keep Track of all Weapons
  Gosub Weapons


  ; Change Ship Control Mechanism
  If MouseHit(2)
     If user\currentMode = "FreeCamera"
      user\currentMode = "MousePilot"

    ElseIf user\currentMode = "MousePilot"
      user\currentMode = "FreeCamera"
    EndIf
  EndIf

  ; Allows rotation of the camera around the player with the mouse.
   Gosub cameraRotate 


  ; Allow turning of ship with mouse
  If user\currentMode = "MousePilot"
    Gosub MousePilot
  EndIf


RenderWorld
Flip True
Wend 
End 







.playerMovement
  ; A to increase speed
  If KeyDown(30)
    player\speed = player\speed + 1
  EndIf

  ; Z to decrease speed 
  If KeyDown(44)
    player\speed = player\speed - 1
  EndIf

  ; SHIFT-A to enter cruise mode
  If KeyDown(30) And KeyDown(42)
    player\speed = 500
  EndIf

  ; SHIFT-Z for emergency stop
  If KeyDown(44) And KeyDown(42)
    player\speed = 0
  EndIf


  TranslateEntity masterPivot, -player\speed*Sin(EntityYaw(playerPivot)), -player\speed*Sin(EntityPitch(playerPivot)), player\speed*Cos(EntityYaw(playerPivot))

Return








.MousePilot


  If EntityYaw(cameraPivot) >= 0 And EntityYaw(playerPivot) >= 0
    If EntityYaw(cameraPivot) > EntityYaw(playerPivot) + 1
      TurnEntity playerPivot, 0, 1/player\inertiaRating, 0
    ElseIf EntityYaw(cameraPivot) < EntityYaw(playerPivot) - 1
       TurnEntity playerPivot, 0, -1/player\inertiaRating, 0
    EndIf


  ElseIf EntityYaw(cameraPivot) < 0 And EntityYaw(playerPivot) < 0
    If EntityYaw(cameraPivot) > EntityYaw(playerPivot) + 1
      TurnEntity playerPivot, 0, 1/player\inertiaRating, 0
    ElseIf EntityYaw(cameraPivot) < EntityYaw(playerPivot) - 1
       TurnEntity playerPivot, 0, -1/player\inertiaRating, 0
    EndIf

  ElseIf EntityYaw(cameraPivot) >= 0 And EntityYaw(playerPivot) < 0
    If  EntityYaw(cameraPivot) - EntityYaw(playerPivot) > 180
      TurnEntity playerPivot, 0, -1/player\inertiaRating, 0
    Else
       TurnEntity playerPivot, 0, 1/player\inertiaRating, 0
    EndIf

  ElseIf EntityYaw(cameraPivot) < 0 And EntityYaw(playerPivot) >= 0
    If EntityYaw(playerPivot) - EntityYaw(cameraPivot) > 180
      TurnEntity playerPivot, 0, 1/player\inertiaRating, 0
    Else
       TurnEntity playerPivot, 0, -1/player\inertiaRating, 0
    EndIf

  EndIf

  If EntityPitch(playerPivot) > EntityPitch(cameraPivot) + 1
    TurnEntity playerPivot, -1/player\inertiaRating, 0, 0

  ElseIf EntityPitch(playerPivot) < EntityPitch(cameraPivot) - 1
    TurnEntity playerPivot, 1/player\inertiaRating, 0, 0
  EndIf

Return





.Weapons

  For i = 0 To 9999
    If laserArray(i)\status = "Alive"
     TranslateEntity laserArray(i)\pivot, -laserArray(i)\speed*Sin(EntityYaw(laserArray(i)\pivot)), -laserArray(i)\speed*Sin(EntityPitch(laserArray(i)\pivot)), laserArray(i)\speed*Cos(EntityYaw(laserArray(i)\pivot))

     laserArray(i)\x# = EntityX(laserArray(i)\pivot, True)
     laserArray(i)\y# = EntityY(laserArray(i)\pivot, True)
     laserArray(i)\z# = EntityZ(laserArray(i)\pivot, True)	
     laserArray(i)\x2# = EntityX(camera, True)
     laserArray(i)\y2# = EntityY(camera, True)
     laserArray(i)\z2# = EntityZ(camera, True)
	
	 laserArray(i)\cx# = laserArray(i)\x# - laserArray(i)\x2#
	 laserArray(i)\cy# = laserArray(i)\y# - laserArray(i)\y2#
	 laserArray(i)\cz# = laserArray(i)\z# - laserArray(i)\z2#
	
	 TFormVector 0,0,0, laserArray(i)\pivot,0 
       laserArray(i)\tx# = TFormedX()
	 laserArray(i)\ty# = TFormedY()
	 laserArray(i)\tz# = TFormedZ()	
	
	
	
	 laserArray(i)\vx# =  laserArray(i)\cy# * laserArray(i)\tz# - laserArray(i)\cz# * laserArray(i)\ty# 
	 laserArray(i)\vy# =  laserArray(i)\cz# * laserArray(i)\tx# - laserArray(i)\cx# * laserArray(i)\tz#
	 laserArray(i)\vz# =  laserArray(i)\cx# * laserArray(i)\ty# - laserArray(i)\cy# * laserArray(i)\tx#	
	
	AlignToVector(laserArray(i)\sprite, laserArray(i)\vx#, laserArray(i)\vy#, laserArray(i)\vz#, 1)

	AlignToVector(laserArray(i)\sprite, laserArray(i)\tx#, laserArray(i)\ty#, laserArray(i)\tz#, 2)
	
   EndIf
 Next

Return





.playerPrimaryWeapons
  i = 0
  Repeat
    If laserArray(i)\status = "Dead"

      ; Speed and other variables should be set here, determined by what weapon is firing.
      laserArray(i)\status = "Alive"
      laserArray(i)\speed = 0.1
      
      laserArray(i)\pivot = CreatePivot()
      PositionEntity laserArray(i)\pivot, EntityX(masterPivot), EntityY(masterPivot), EntityZ(masterPivot)
      RotateEntity laserArray(i)\pivot, EntityPitch(playerPivot), EntityYaw(playerPivot), 0


      ;Set Up Laser Sprite
      laserArray(i)\sprite = CopyEntity(BlueLaserSprite)
      SpriteViewMode laserArray(i)\sprite, 4
      ScaleSprite laserArray(i)\sprite, 1, 10
      EntityFX laserArray(i)\sprite, 17
      EntityParent laserArray(i)\sprite, laserArray(i)\pivot, False

      Exit

    Else
      i = i + 1
    EndIf

  Forever
  i = 0
Return










.cameraRotate  
  ; zoom camera in
  If KeyDown(78)
    TranslateEntity camera, 0, 0, 0.1
  EndIf

  ; zoom camera out
  If KeyDown(74)
    TranslateEntity camera, 0, 0, -0.1
  EndIf

  ; Ensure that the mouse never leaves the screen bounds.
  If ( MouseX() > 1200 ) Or ( MouseX() < 50 ) Or ( MouseY() > 1000 ) Or ( MouseY() < 50 ) Then
    MoveMouse 640, 512
  EndIf
  
  ; Turn cameraPivot, thus making camera spin around it. Note that the vertical speed is set
  ; to be less than the horizontal speed.
  TurnEntity cameraPivot, MouseYSpeed() / 1.5, -MouseXSpeed(), 0
  
  ; Always keep cameraPivot's roll 0 wrt the horizontal plane.
  RotateEntity cameraPivot, EntityPitch(cameraPivot), EntityYaw(cameraPivot), 0
Return





Defoc8(Posted 2006) [#13]
ok heres my code for creating beams..
- note that this version alters the verts per frame...


Graphics3D(640,480,32,2)
cam=CreateCamera()
CameraRange(cam,1,1000)
PositionEntity(cam,0,0,-5)



ray.gfx_ray=gfx_createray(0.5,255,0,0,0.7) ;create our ray..

s=CreateSphere(8)
PositionEntity(s,10,0,100)

While Not KeyHit(1)
 Cls()
 PositionEntity(cam,EntityX(cam,True)+MouseXSpeed()*0.1,EntityY(cam,True)+MouseYSpeed()*0.1,0)

 MoveMouse(320,240)

  gfx_castray(ray,cam,10,0,100,-10,0,0) ;rayupdate

 UpdateWorld()
 RenderWorld()
 Flip()
Wend
End


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;RAYCAST GFX

Type gfx_ray
 Field mesh
 Field surf
 Field rad#
End Type

;GFX_CREATERAY()
;creates the basic ray object..this object can be textured, but defaults
;to a red fullbright ray..
Function gfx_createray.gfx_ray(rad#=1,r=255,g=0,b=0,a#=1.0)
 ray.gfx_ray=New gfx_ray
 ray\mesh=CreateMesh()
 ray\surf=CreateSurface(ray\mesh)
  AddVertex(ray\surf,0,0,0,0,1)  ;0 BL = bottom left
  AddVertex(ray\surf,0,0,0,0,0)  ;1 TL
  AddVertex(ray\surf,0,0,0,1,1)  ;2 BR
  AddVertex(ray\surf,0,0,0,1,0)  ;3 TR
   AddTriangle(ray\surf,0,1,2)
   AddTriangle(ray\surf,3,2,1)
 EntityColor(ray\mesh,r,g,b)
 EntityAlpha(ray\mesh,a)
 EntityFX(ray\mesh,1)
 ray\rad=rad
 Return ray
End Function

;GFX_CASTRAY()
;Sets rays vertices..
; - ray = previously created ray object.
; - viewer = should be a camera entity..or the object the camera
;            is mounted to..
; - x1,y1,z1 = startpoint of ray - typically some kind of emitter
; - x2,y2,z2 = end point of ray..

Function gfx_castray(ray.gfx_ray,viewer,x1#,y1#,z1#,x2#,y2#,z2#)
 vx#=EntityX(viewer,True)
 vy#=EntityY(viewer,True)
 vz#=EntityZ(viewer,True)
  vx=vx-x1
  vy=vy-y1
  vz=vz-z1
 x3#=x2-x1
 y3#=y2-y1
 z3#=z2-z1
 cx1#=vy*z3-vz*y3
 cy1#=vz*x3-vx*z3
 cz1#=vx*y3-vy*x3
 clen#=Sqr(cx1*cx1+cy1*cy1+cz1*cz1)
  cx1=(cx1/clen)*ray\rad
  cy1=(cy1/clen)*ray\rad
  cz1=(cz1/clen)*ray\rad
 cx2#=-cx1
 cy2#=-cy1
 cz3#=-cz1
  VertexCoords(ray\surf,0,x1+cx1,y1+cy1,z1+cz1)
  VertexCoords(ray\surf,1,x1+cx2,y1+cy2,z1+cz2)
  VertexCoords(ray\surf,2,x2+cx1,y2+cy1,z2+cz1)
  VertexCoords(ray\surf,3,x2+cx2,y2+cy2,z2+cz2)
End Function