2 different ways to turn an entity over XY axes relative to camera view (eye).
(USE: Key_LeftControl to move camera point of view, so you can see the global axises from different points in space. Key_LeftShift to run the method '1)'. No key to run the method '2)'. Key_RightShift to turn the piece over global axises.)
Code: Select all
; Rota una entidad sobre su centro geométrico (rotación intrínseca si ese centro corresponde con su centro de masas). Diciembre 2014
Define .f
MP_Graphics3D(640,480,0,3)
SetWindowTitle(0,"TurnEntity over relative to eye axis")
maincam.i=MP_CreateCamera()
pivotcam.i=MP_CreateMesh():MP_EntitySetParent(maincam,pivotcam,0):MP_PositionEntity(maincam,0,0,-4)
light.i=MP_CreateLight(1)
If CreateImage(0,255,255)
Font.i=LoadFont(#PB_Any,"Arial",138)
StartDrawing(ImageOutput(0))
Box(0, 0, 128, 128,RGB(255,0,0))
Box(128, 0, 128, 128,RGB(0,255,0))
Box(0, 128, 128, 128,RGB(0,0,255))
Box(128, 128, 128, 128,RGB(255,255,0))
DrawingFont(FontID(Font))
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(73,35,"5",RGB(0,0,0))
StopDrawing()
EndIf
Object0.i=MP_CreateSkySphere(20)
; Object0.i=MP_CreateSphere(20)
; Object0.i=MP_CreateCube()
MP_EntitySetTexture(Object0,MP_ImageToTexture(0),0,0)
Structure D3DMATRIX
_11.f : _12.f : _13.f : _14.f
_21.f : _22.f : _23.f : _24.f
_31.f : _32.f : _33.f : _34.f
_41.f : _42.f : _43.f : _44.f
EndStructure
Structure D3DXVECTOR3
x.f
y.f
z.f
EndStructure
Structure Vector3D Extends D3DXVECTOR3
m.f;<-length(modulo)
EndStructure
Macro ProductoEscalar(a,b,ax=x,ay=y,az=z,bx=x,by=y,bz=z)
(a#\ax#*b#\bx#+a#\ay#*b#\by#+a#\az#*b#\bz#)
EndMacro
Macro getmodulo(v,vx=x,vy=y,vz=z)
(Sqr#ProductoEscalar(v#,v#,vx#,vy#,vz#,vx#,vy#,vz#))
EndMacro
Procedure.i Matriz3x3xMatriz3x3(*a.D3DMATRIX,*b.D3DMATRIX,*prod.D3DMATRIX); producto
*prod\_11=*a\_11**b\_11+*a\_12**b\_21+*a\_13**b\_31:*prod\_12=*a\_11**b\_12+*a\_12**b\_22+*a\_13**b\_32:*prod\_13=*a\_11**b\_13+*a\_12**b\_23+*a\_13**b\_33
*prod\_21=*a\_21**b\_11+*a\_22**b\_21+*a\_23**b\_31:*prod\_22=*a\_21**b\_12+*a\_22**b\_22+*a\_23**b\_32:*prod\_23=*a\_21**b\_13+*a\_22**b\_23+*a\_23**b\_33
*prod\_31=*a\_31**b\_11+*a\_32**b\_21+*a\_33**b\_31:*prod\_32=*a\_31**b\_12+*a\_32**b\_22+*a\_33**b\_32:*prod\_33=*a\_31**b\_13+*a\_32**b\_23+*a\_33**b\_33
ProcedureReturn *prod
EndProcedure
Procedure.i Matriz4x4xMatriz4x4(*a.D3DMATRIX,*b.D3DMATRIX,*prod.D3DMATRIX); producto
*prod\_11=*a\_11**b\_11+*a\_12**b\_21+*a\_13**b\_31+*a\_14**b\_41:*prod\_12=*a\_11**b\_12+*a\_12**b\_22+*a\_13**b\_32+*a\_14**b\_42:*prod\_13=*a\_11**b\_13+*a\_12**b\_23+*a\_13**b\_33+*a\_14**b\_43:*prod\_14=*a\_11**b\_14+*a\_12**b\_24+*a\_13**b\_34+*a\_14**b\_44
*prod\_21=*a\_21**b\_11+*a\_22**b\_21+*a\_23**b\_31+*a\_24**b\_41:*prod\_22=*a\_21**b\_12+*a\_22**b\_22+*a\_23**b\_32+*a\_24**b\_42:*prod\_23=*a\_21**b\_13+*a\_22**b\_23+*a\_23**b\_33+*a\_24**b\_43:*prod\_24=*a\_21**b\_14+*a\_22**b\_24+*a\_23**b\_34+*a\_24**b\_44
*prod\_31=*a\_31**b\_11+*a\_32**b\_21+*a\_33**b\_31+*a\_34**b\_41:*prod\_32=*a\_31**b\_12+*a\_32**b\_22+*a\_33**b\_32+*a\_34**b\_42:*prod\_33=*a\_31**b\_13+*a\_32**b\_23+*a\_33**b\_33+*a\_34**b\_43:*prod\_34=*a\_31**b\_14+*a\_32**b\_24+*a\_33**b\_34+*a\_34**b\_44
*prod\_41=*a\_41**b\_11+*a\_42**b\_21+*a\_43**b\_31+*a\_44**b\_41:*prod\_42=*a\_41**b\_12+*a\_42**b\_22+*a\_43**b\_32+*a\_44**b\_42:*prod\_43=*a\_41**b\_13+*a\_42**b\_23+*a\_43**b\_33+*a\_44**b\_43:*prod\_44=*a\_41**b\_14+*a\_42**b\_24+*a\_43**b\_34+*a\_44**b\_44
ProcedureReturn *prod
EndProcedure
Procedure.i flecha(px.f=0,py.f=0,pz.f=0,x.f=1,y.f=0,z.f=0,color.l=$AA66AA,lados.a=8)
Protected mod.f=Sqr(x*x+y*y+z*z),cil.i=MP_CreateCylinder(lados,mod),cono.i=MP_CreateCone(lados,mod/8),ciltexture.i=MP_CreateTextureColor(8,8,color)
MP_ResizeMesh(cil,mod/80,mod/80,mod)
MP_TranslateMesh(cil,0,0,mod/2)
MP_RotateMesh(cono,180,0,180)
MP_ResizeMesh(cono,mod/20,mod/20,mod/10)
MP_TranslateMesh(cono,0,0,mod)
MP_AddMesh(cono,cil):MP_FreeEntity(cono)
MP_EntityLookAt(cil,x+0.000001,y,z,0,0)
MP_PositionEntity(cil,px,py,pz)
MP_EntitySetTexture(cil,ciltexture,0,0)
ProcedureReturn cil
EndProcedure
Procedure.i BaseSistemaCoordenadas(px.f=0,py.f=0,pz.f=0,size.f=1,colorx.l=$EEAA88,colory.l=$22AADD,colorz.l=$AADDAA,lados.a=8)
Protected vx.i=flecha(px,py,pz,size,0,0,colorx,lados)
Protected vy.i=flecha(px,py,pz,0,size,0,colory,lados)
Protected vz.i=flecha(px,py,pz,0,0,size,colorz,lados)
MP_AddMesh(vx.i,vy.i);:MP_FreeEntity(vx.i)
MP_AddMesh(vz.i,vy.i);:MP_FreeEntity(vz.i)
ProcedureReturn vy.i
EndProcedure
Procedure.i Turn_Body_by_Angle_adding(*fi.Vector3D,Body.i,*matriz.D3DMATRIX=0,vx.f=0,vy.f=0,vz.f=0)
;Rotar un entity un ángulo dado *fi.Vector3D:
Protected rot1.D3DMATRIX,rot.D3DMATRIX,cos.f,sin.f,coss.f,ang.Vector3D
*fi\m=getmodulo(*fi)
If *fi\m
If *matriz=0
*matriz=MP_EntityGetMatrix(Body)
EndIf
*matriz\_41+vx:*matriz\_42+vy:*matriz\_43+vz
CopyMemory(*matriz,@rot,SizeOf(D3DMATRIX))
CopyMemory(*fi,@ang,SizeOf(Vector3D))
cos=Cos(ang\m):sin=Sin(ang\m):coss=1-cos
ang\x/ang\m:ang\y/ang\m:ang\z/ang\m
rot1\_11=cos+ang\x*ang\x*coss:rot1\_12=ang\x*ang\y*coss-ang\z*sin:rot1\_13=ang\x*ang\z*coss+ang\y*sin
rot1\_21=ang\y*ang\x*coss+ang\z*sin:rot1\_22=cos+ang\y*ang\y*coss:rot1\_23=ang\y*ang\z*coss-ang\x*sin
rot1\_31=ang\z*ang\x*coss-ang\y*sin:rot1\_32=ang\z*ang\y*coss+ang\x*sin:rot1\_33=cos+ang\z*ang\z*coss
MP_EntitySetMatrix(Body,Matriz3x3xMatriz3x3(*matriz,@rot1,@rot))
ProcedureReturn @rot
EndIf
ProcedureReturn 0
EndProcedure
Procedure.i MatrizRotacionaldeunAngulodadoalrededordeunejedefinidoporunvectorunidad(*u.Vector3D,Body.i,ANG.f,*matriz.D3DMATRIX=0,vx.f=0,vy.f=0,vz.f=0)
Protected rot.D3DMATRIX,rot1.D3DMATRIX
If ANG
If *matriz=0
*matriz=MP_EntityGetMatrix(Body)
EndIf
*matriz\_41+vx:*matriz\_42+vy:*matriz\_43+vz
;Matriz de Rotación de un ángulo dado 'ANG' alrededor de un eje dado definido por el vector unidad (*u\x,*u\y,*u\z)
rot1\_11=Cos(ANG)+*u\x**u\x*(1-Cos(ANG)):rot1\_12=*u\x**u\y*(1-Cos(ANG))-*u\z*Sin(ANG):rot1\_13=*u\x**u\z*(1-Cos(ANG))+*u\y*Sin(ANG)
rot1\_21=*u\y**u\x*(1-Cos(ANG))+*u\z*Sin(ANG):rot1\_22=Cos(ANG)+*u\y**u\y*(1-Cos(ANG)):rot1\_23=*u\y**u\z*(1-Cos(ANG))-*u\x*Sin(ANG)
rot1\_31=*u\z**u\x*(1-Cos(ANG))-*u\y*Sin(ANG):rot1\_32=*u\z**u\y*(1-Cos(ANG))+*u\x*Sin(ANG):rot1\_33=Cos(ANG)+*u\z**u\z*(1-Cos(ANG))
CopyMemory(*matriz,@rot,SizeOf(D3DMATRIX))
MP_EntitySetMatrix(Body,Matriz3x3xMatriz3x3(*matriz,@rot1,@rot))
ProcedureReturn @rot
EndIf
ProcedureReturn 0
EndProcedure
baseglobal.i=BaseSistemaCoordenadas(-1.5,1,0,1)
*rot.D3DMATRIX=MP_EntityGetMatrix(pivotcam)
rot.D3DMATRIX
rot1.D3DMATRIX
rotx.D3DMATRIX
roty.D3DMATRIX
; MP_RotateEntity(Object0,Random(360),Random(360),Random(360),0)
MP_MouseInWindow()
MP_UseCursor(0)
While MP_KeyDown(#PB_Key_Escape)=0 And WindowEvent()<>#PB_Event_CloseWindow
mdx=MP_MouseDeltaX()/200:mdy=MP_MouseDeltaY()/200:mdw=MP_MouseDeltaWheel()/400
If MP_KeyDown(#PB_Key_LeftControl); <- mover el punto de vista
MP_TurnEntity(pivotcam,mdy*60,mdx*60,0,0)
If mdw
MP_EntitySetZ(maincam,MP_EntityGetZ(maincam)+mdw); <- MP_MoveEntity(cam,0,0,mdw)
EndIf
*rot=MP_EntityGetMatrix(pivotcam)
ElseIf MP_KeyDown(#PB_Key_RightShift); <- rotar el objeto sobre eje 'x' global y sobre eje 'y' global
;Para rotar la entidad alrededor del eje, en el plano XY del mundo, que define el desplazamiento del raton
;matriz de rotación sobre eje x del mundo:
rotx\_11=1:rotx\_12=0:rotx\_13=0:rotx\_14=0
rotx\_21=0:rotx\_22=Cos(-mdy):rotx\_23=Sin(-mdy):rotx\_24=0
rotx\_31=0:rotx\_32=-Sin(-mdy):rotx\_33=Cos(-mdy):rotx\_34=0
rotx\_41=0:rotx\_42=0:rotx\_43=0:rotx\_44=1
;matriz de rotación sobre eje y del mundo:
roty\_11=Cos(mdx):roty\_12=0:roty\_13=Sin(mdx):roty\_14=0
roty\_21=0:roty\_22=1:roty\_23=0:roty\_24=0
roty\_31=-Sin(mdx):roty\_32=0:roty\_33=Cos(mdx):roty\_34=0
roty\_41=0:roty\_42=0:roty\_43=0:roty\_44=1
;obtener matriz de rotación sobre eje, en el plano XY del mundo, que define el desplazamiento del raton:
Matriz4x4xMatriz4x4(@rotx,@roty,@rot1); o lo que es lo mismo: Matriz4x4xMatriz4x4(@roty,@rotx,@rot1)
MP_EntitySetMatrix(Object0,Matriz4x4xMatriz4x4(MP_EntityGetMatrix(Object0),@rot1,@rot))
Else; <- rotar el objeto sobre eje 'x' y 'y' relativo al ojo.
;Para rotar la entidad alrededor del eje, en el plano XY del ojo, que define el desplazamiento del raton.
;El tema está en que el raton se mueve en 2 dimensiones, es decir en el plano, entonces de la entrada del raton obtenemos:
;1. de su desplazamiento vertical un vector en dirección X, cuya amplitud y sentido nos indica el ángulo a rotar alrededor de ese eje X
;2. de su desplazamiento horizontal un vector en dirección Y, cuya amplitud y sentido nos indica el ángulo a rotar alrededor de ese eje Y
;Tenemos pues un vector definido por el movimiento del ratón.
;El ojo se puede mover en el espacio del mundo y apuntar la vista hacia cualquier parte,
;por lo que el plano frontal del ojo puede variar y no coincidir con el plano XY del mundo.
;Entonces el vector que obtenemos del movimiento del ratón ha de estar contenido en el plano frontal del ojo.
;Hay que disponer el vector (mdx,mdy,mdz) sobre el plano XY de la base de coordenadas del pivotcam (plano frontal del ojo), no del mundo.
;Para ello, el vector (0,mdx,0) hay que ponerlo sobre el eje Y del plano frontal de ojo
;y el vector (mdy,0,0) hay que ponerlo sobre el eje X del plano frontal de ojo:
;Tenemos en *rot la dirección del eje X, a través del vector X-> del plano frontal del ojo ( *rot\_11,*rot\_12,*rot\_13 )
;y la dirección del eje Y, a través del vector Y-> del plano frontal del ojo ( *rot\_21,*rot\_22,*rot\_23 )
;Por tanto procedemos a obtener ambos vectores unidad:
;el colineal al eje de abscisas en el plano frontal del ojo y el colineal al eje de ordenadas en este plano:
THETA.d=Sqr(mdx*mdx+mdy*mdy)
If THETA>0
ux_m.d=Sqr(*rot\_11**rot\_11+*rot\_12**rot\_12+*rot\_13**rot\_13)
If ux_m>0
;los cosenos directores de un vector cualquiera son las coordenadas escalares de ese mismo vector con módulo unidad, es decir,
;son las proyecciones de ese vector unitario sobre cada uno de los ejes principales
ux_x.d=*rot\_11/ux_m:ux_y.d=*rot\_12/ux_m:ux_z.d=*rot\_13/ux_m; <- son los cosenos directores
;ahora multiplicando este vector unitario, por el modulo de (mdy,0,0) obtenemos ya la componente X pero en el plano frontal del ojo:
ux_x*mdy:ux_y*mdy:ux_z*mdy
EndIf
;Hacemos lo mismo para obtener la componente Y del movimiento del ratón pero en el plano frontal del ojo
uy_m.d=Sqr(*rot\_21**rot\_21+*rot\_22**rot\_22+*rot\_23**rot\_23)
If uy_m>0
;los cosenos directores de un vector cualquiera son las coordenadas escalares de ese mismo vector con módulo unidad, es decir,
;son las proyecciones de ese vector unitario sobre cada uno de los ejes principales
uy_x.d=*rot\_21/uy_m:uy_y.d=*rot\_22/uy_m:uy_z.d=*rot\_23/uy_m; <- son los cosenos directores.
;ahora multiplicando este vector unitario, por el modulo de (0,mdx,0) obtenemos ya la componente X pero en el plano frontal del ojo:
uy_x*mdx:uy_y*mdx:uy_z*mdx
EndIf
;Para obtener el vector que define la recta alrededor de la cual ha de rotar el objeto, basta con sumar esas 2 componentes obtenidas,
;y dado que ambas componentes están contenidas en el plano frontal del ojo, la suma de ambas también lo estará:
u.Vector3D
u\x=ux_x.d+uy_x.d:u\y=ux_y.d+uy_y.d:u\z=ux_z.d+uy_z.d
If MP_KeyDown(#PB_Key_LeftShift)
Turn_Body_by_Angle_adding(@u.Vector3D,Object0.i); <- METODO 1
Else ; METODO 2:
;el módulo del vector original en el plano XY del mundo (THETA) es el mismo al vector rotado al plano XY frontal del ojo, así que: Sqr(u\x*u\x+u\y*u\y+u\z*u\z) = THETA
;Convertimos este vector en unitario:
u\x/THETA:u\y/THETA:u\z/THETA
MatrizRotacionaldeunAngulodadoalrededordeunejedefinidoporunvectorunidad(@u.Vector3D,Object0.i,THETA)
EndIf
EndIf
EndIf
MP_RenderWorld()
MP_Flip():Delay(8)
Wend
Feel free to translate code to other 3D layouts.