Tip; HOWTO get a reliable global orientation of any 3D object

Everything related to 3D programming
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Tip; HOWTO get a reliable global orientation of any 3D object

Post by Psychophanta »

Left mouse button to translate objects (arrows in this example)
Middle mouse button to rotate objects (arrows in this example)
Left Control key and move mouse to orbitate camera view over the observed center.
Sorry for some comments in spanish in the code.

Code: Select all

ExamineDesktops()
Global bitplanes.a=DesktopDepth(0),FRX.u=DesktopWidth(0),FRY.u=DesktopHeight(0),RX.u=FRX,RY.u=FRY,FrecuenciadeMuestreo.a=60
If FRX<1280 Or FRY<720:RX=FRX*2/3:RY=FRY*2/3:Else:RX=1280:RY=720:EndIf
InitEngine3D(#PB_Engine3D_NoLog,#PB_Compiler_Home+"Compilers\Engine3d.dll")
If InitMouse()=0 Or InitSprite()=0 Or InitKeyboard()=0:MessageRequester("Error","Can't open DirectX",0):End:EndIf
#ventana=1
OpenWindow(#ventana,0,0,RX,RY,Titulo$,#PB_Window_BorderLess|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(#ventana),0,0,RX,RY,1,0,0,#PB_Screen_WaitSynchronization)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples\3D\Data\fonts",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples/3d/Data/Textures",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples\3D\Data\GUI",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples/3d/Data/Packs/desert.zip",#PB_3DArchive_Zip)
Parse3DScripts()
SetGUITheme3D("","DejaVuSans-10"):#TextoInfoObjeto=0
Enumeration Luces
  #Luz
EndEnumeration
Enumeration Camaras
  #Camara
EndEnumeration
Enumeration Texturas
  #texturacubo1
EndEnumeration
Enumeration Nodos
  #pivotcamara
EndEnumeration
Enumeration Entidades
  #arrowR
  #arrowG
  #arrowB
EndEnumeration
Enumeration Texto3D
  #texto1=40
EndEnumeration
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
Macro ProductoVectorial(in1,in2,out,in1x=x,in1y=y,in1z=z,in2x=x,in2y=y,in2z=z,outx=x,outy=y,outz=z); <- Calculates the vectorial product of two 3D vectors. Just modify this procedure to get the vectorial product for 4D, 5D, 6D or any dimension you need.
  out#\outx#=in1#\in1y#*in2#\in2z#-in1#\in1z#*in2#\in2y#
  out#\outy#=in1#\in1z#*in2#\in2x#-in1#\in1x#*in2#\in2z#
  out#\outz#=in1#\in1x#*in2#\in2y#-in1#\in1y#*in2#\in2x#
EndMacro
Procedure AnguloFormadoPor2Vectores(*in1.Vector3D,*in2.Vector3D,*out.Vector3D)
  Protected.Vector3D v1,v2:CopyMemory(*in1,@v1,SizeOf(Vector3D)):CopyMemory(*in2,@v2,SizeOf(Vector3D))
  ProductoVectorial(*in1,*in2,*out):*out\m=getmodulo(*out)
  v1\m=getmodulo(v1):v2\m=getmodulo(v2)
  If *out\m=0.0
    If v1\m=0.0 Or v2\m=0.0:FillMemory(*out,SizeOf(Vector3D),0,#PB_Byte):ProcedureReturn:EndIf
    *out\m=1.0
  EndIf
  v1\x/v1\m:v1\y/v1\m:v1\z/v1\m
  v2\x/v2\m:v2\y/v2\m:v2\z/v2\m
  v1\x-v2\x:v1\y-v2\y:v1\z-v2\z:v1\m=getmodulo(v1)
  v2\m=2*ASin(v1\m/2)
  *out\x*v2\m/*out\m:*out\y*v2\m/*out\m:*out\z*v2\m/*out\m
  *out\m=v2\m
EndProcedure
Procedure.b Rotar_Vector3D_por_adicion_Angular(*fi.Vector3D,*R0.Vector3D)
  ;Esta funcion halla un vector resultado de una rotacion en el espacio de otro vector inicial.
  ;Esta funcion admite entonces, como parametros de entrada, 2 vectores:
  ; - 'Vector radio' ( *R0-> ) que se desea rotar. Este vector tiene direccion no colineal con el eje de rotación.
  ; - 'Vector angulo' ( *fi-> 'velocidad angular'-> * 'tiempo'), es el angulo en el que se rota el 'Vector radio' dado.
  ;     Su modulo indica el numero de radianes a rotar, su direccion indica el angulo en el espacio en el que se rota (eje de rotación)
  ;     su sentido indica el sentido de la rotacion
  ;NOTA: la funcion extrae el vector velocidad rectilinea y el nuevo vector radio.
  ;       se devuelve nuevo radio en el mismo parametro de entrada ( *R0-> )
  ; El resultado es:
  ; Proyección de *R0-> sobre *fi-> MÁS proyección ortogonal de *R0-> sobre *fi-> por el Cos(|fi->|) MÁS módulo de la proyección ortogonal de *R0-> sobre *fi-> por el Sen(|fi->|) por u^,
  ; siendo u-> = *fi-> X *R0-> .
  
  Protected Rt.Vector3D,u.Vector3D,P0.Vector3D
  *fi\m=ProductoEscalar(*fi,*fi)
  If *fi\m
    u\m=ProductoEscalar(*R0,*fi)/*fi\m; <- aqui lo uso como variable comodin
    *fi\m=Sqr(*fi\m)
    ;Rt-> = Proyeccion de *R0-> sobre *fi->:
    Rt\x=u\m**fi\x
    Rt\y=u\m**fi\y
    Rt\z=u\m**fi\z
    ;P0-> = proyeccion ortogonal de *R0-> sobre *fi->:
    P0\x=*R0\x-Rt\x
    P0\y=*R0\y-Rt\y
    P0\z=*R0\z-Rt\z
    P0\m=getmodulo(P0)
    If P0\m=0.0; <= no hay giro ya que *R0-> y *fi-> son colineales. Pero hay "torsion" vectorial:
      ;Esta "torsion" significa que el 'Vector radio' ( *R0-> ) aumenta su amplitud en la medida de la amplitud del 'Vector angulo' ( *fi-> )
      *R0\x+*fi\x
      *R0\y+*fi\y
      *R0\z+*fi\z
      ProcedureReturn -1
    EndIf
    ;Calcular el producto vectorial: u-> = *fi-> X *R0-> (o por P0-> daría igual)
    u\x=*fi\y**R0\z-*fi\z**R0\y
    u\y=*fi\z**R0\x-*fi\x**R0\z
    u\z=*fi\x**R0\y-*fi\y**R0\x
    ;ahora obtener *R0-> = (Proyeccion de *R0-> sobre *fi->)-> + (cos(|*fi->|)·P0-> + |P0->|/|u->|·sin(|*fi->|)·u->)->:
    *R0\x=Rt\x
    *R0\y=Rt\y
    *R0\z=Rt\z
    Rt\x=Cos(*fi\m):Rt\y=Sin(*fi\m)
    u\m=getmodulo(u)
    P0\m*Rt\y/u\m
    *R0\x+Rt\x*P0\x+P0\m*u\x
    *R0\y+Rt\x*P0\y+P0\m*u\y
    *R0\z+Rt\x*P0\z+P0\m*u\z
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure
Procedure.b MouseButtonEdgeDetection(boton.b,estado.b)
  Static mb.b:Protected i.b=1<<boton
  If estado;<- if current key status is PUSHED
    If mb&i=0:mb|i:ProcedureReturn 1:EndIf;<- if previous key status was NOT PUSHED, then assign previous state to current one, and EXIT.
  ElseIf mb&i;<- else (if previous key status was PUSHED and current key status is NOT PUSHED):
    mb!i:ProcedureReturn -1;<- set previous key status to NOT PUSHED.
  EndIf
  ProcedureReturn 0
EndProcedure
Procedure.b KeyEdgeDetection(tecla.a,estado.b)
  Static pka.a
  If estado;<-if current key status is PUSHED
    If pka=0:pka=tecla:ProcedureReturn 1:EndIf;<-if previous key status was NOT PUSHED, then assign previous state to current one, and EXIT.
  ElseIf pka=tecla;<-else (if previous key status was PUSHED and current key status is NOT PUSHED):
    pka=0:ProcedureReturn -1;<-set previous key status to NOT PUSHED.
  EndIf
  ProcedureReturn 0
EndProcedure
Procedure AddMesh(mallaorigen.i,mallaobtenida.i,liberar.b=1,color.l=$FFFFFFFF)
  Protected Dim mallaorigenDataV.MeshVertex(0),Dim mallaorigenDataF.MeshFace(0),Dim mallaobtenidaDataV.MeshVertex(0),Dim mallaobtenidaDataF.MeshFace(0),i.i,maxindex.i
  GetMeshData(mallaorigen.i,0,mallaorigenDataV(),#PB_Mesh_Vertex|#PB_Mesh_UVCoordinate| #PB_Mesh_Normal|#PB_Mesh_Color,0,MeshVertexCount(mallaorigen.i,0)-1)
  GetMeshData(mallaorigen.i,0,mallaorigenDataF(),#PB_Mesh_Face,0,MeshIndexCount(mallaorigen.i,0)-1)
  GetMeshData(mallaobtenida.i,0,mallaobtenidaDataV(),#PB_Mesh_Vertex|#PB_Mesh_UVCoordinate|#PB_Mesh_Normal|#PB_Mesh_Color,0,MeshVertexCount(mallaobtenida.i,0)-1)
  GetMeshData(mallaobtenida.i,0,mallaobtenidaDataF(),#PB_Mesh_Face,0,MeshIndexCount(mallaobtenida.i,0)-1)
  FreeMesh(mallaobtenida.i)
  CreateMesh(mallaobtenida.i,#PB_Mesh_TriangleList,#PB_Mesh_Static)
  For i=0 To ArraySize(mallaobtenidaDataV())
    With mallaobtenidaDataV(i)
    MeshVertex(\x,\y,\z,\u,\v,color.l,\NormalX,\NormalY,\NormalZ)
    EndWith
  Next
  For i=0 To ArraySize(mallaorigenDataV())
    With mallaorigenDataV(i)
    MeshVertex(\x,\y,\z,\u,\v,color.l,\NormalX,\NormalY,\NormalZ)
    EndWith
  Next
  For i=0 To ArraySize(mallaobtenidaDataF()) Step 3
    MeshFace(mallaobtenidaDataF(i)\Index,mallaobtenidaDataF(i+1)\Index,mallaobtenidaDataF(i+2)\Index)
    If mallaobtenidaDataF(i)\Index>maxindex:maxindex=mallaobtenidaDataF(i)\Index:EndIf
    If mallaobtenidaDataF(i+1)\Index>maxindex:maxindex=mallaobtenidaDataF(i+1)\Index:EndIf
    If mallaobtenidaDataF(i+2)\Index>maxindex:maxindex=mallaobtenidaDataF(i+2)\Index:EndIf
  Next
  maxindex+1
  For i=0 To ArraySize(mallaorigenDataF()) Step 3
    MeshFace(mallaorigenDataF(i)\Index+maxindex,mallaorigenDataF(i+1)\Index+maxindex,mallaorigenDataF(i+2)\Index+maxindex)
  Next
  FinishMesh(1)
  NormalizeMesh(mallaobtenida.i)
  UpdateMeshBoundingBox(mallaobtenida.i)
  If liberar.b:FreeMesh(mallaorigen.i):EndIf
EndProcedure
Procedure.i arrow(arrow.i,color.l=$00FBFD49,centro.f=0.5,grosor.f=1,longitud.f=1,letra$="",tipoletra$="",PosText.f=0.5,ResizeTextX.f=10,ResizeTextY.f=16,ResizeTextZ.f=1/30)
  ;'grosor.f' es el diametro de la base del cilindro, esto es, su grosor
  Protected n.f=0.2,g_b.f=0.5232; <- ambos valores deben ser entre 0 y 1. 'g_b.f' es la relación entre el diametro del cilindro y el del cono
  Protected b.f=grosor/g_b; <- 'b.f' es el diametro de la base del cono
  Protected a.f=1.65*b; <- altura cono = relación de aspecto del cono * diametro de su base
  Protected d.f=a.f*(1+n*(g_b-1)); <- distancia entre el vértice del cono y la base del cilindro más cercana
  CreateCylinder(9991,grosor/2,longitud-d,3,1,1)
  CreateCone(9992,b/2,a,3,1)
  CreateTexture(9991,32,32)
  StartDrawing(TextureOutput(9991))
  Box(0,0,32,32,color.l)
  StopDrawing()
  CreateMaterial(9991,TextureID(9991))
  SetMaterialColor(9991,#PB_Material_AmbientColor,color.l)
  TransformMesh(9992,0,(longitud+d-a)/2,0,1,1,1,0,0,0,0):UpdateMeshBoundingBox(9992)
  AddMesh(9992,9991)
  TransformMesh(9991,0,-(centro*longitud+(d-longitud)/2),0,1,1,1,0,0,0,0):UpdateMeshBoundingBox(9991)
  If arrow.i=#PB_Any
    arrow.i=CreateEntity(#PB_Any,MeshID(9991),MaterialID(9991),0,0,0)
  Else
    CreateEntity(arrow.i,MeshID(9991),MaterialID(9991),0,0,0)
  EndIf
  If letra$
    CreateText3D(arrow.i,letra$,tipoletra$,1,RGBA(Red(color),Green(color),Blue(color),240))
    Text3DAlignment(arrow.i,#PB_Text3D_HorizontallyCentered|#PB_Text3D_Top)
    ScaleText3D(arrow.i,grosor*ResizeTextX,grosor*ResizeTextY,longitud*ResizeTextZ,#PB_Relative)
    AttachEntityObject(arrow.i,"",Text3DID(arrow.i))
    MoveText3D(arrow.i,0,-longitud.f*(centro.f-PosText.f),0,#PB_Local)
  EndIf
  FreeMesh(9991)
  FreeMaterial(9991)
  FreeTexture(9991)
  ProcedureReturn arrow.i
EndProcedure
Macro AnimarGiroenPropioEjeXYZ(rot,tipoobjeto,objeto,grados,veloc=5)
  seno2.d=Pow(Sin(Animaciondiferencial.d),2)
;   seno2.d=1-Abs(Cos(Animaciondiferencial.d)); con este va pero el paso no es de #PI/(grados#*2/veloc#). Interesante estudiar esto matemáticamente.
  Animaciondiferencial.d+#PI/(grados#*2/veloc#)
  If Abs(Animaciondiferencial.d)>=#PI:Animaciondiferencial.d=0:AnimacionPivotCamara.b=0
  Else:rot#(tipoobjeto#ID(objeto#),Sign(grados#)*veloc#*seno2.d,#PB_Local|#PB_Relative)
  EndIf
EndMacro
Macro OrbitarObjeto1SobreObjeto0(tecla=LeftControl,tipo1=Camera,objeto1=#Camara,tipo0=Node,objeto0=#Pivotcamara); <- el 'objeto1' orbita sobre el 'objeto0', y este debe ser nodo de 'objeto1'
  If AnimacionPivotCamara.b
    Select TipodeGiro.b
    Case 1; pitch 90 grados
      AnimarGiroenPropioEjeXYZ(Pitch,tipo0#,objeto0#,Gradosdegiro.d)
    Case 2; pitch -90 grados
      AnimarGiroenPropioEjeXYZ(Pitch,tipo0#,objeto0#,Gradosdegiro.d)
    Case 3; yaw 90 grados
      AnimarGiroenPropioEjeXYZ(Yaw,tipo0#,objeto0#,Gradosdegiro.d)
    Case 4; yaw -90 grados
      AnimarGiroenPropioEjeXYZ(Yaw,tipo0#,objeto0#,Gradosdegiro.d)
    Case 5; roll 90 grados
      AnimarGiroenPropioEjeXYZ(Roll,tipo0#,objeto0#,Gradosdegiro.d)
    Case 6; roll -90 grados
      AnimarGiroenPropioEjeXYZ(Roll,tipo0#,objeto0#,Gradosdegiro.d)
    EndSelect
  Else
    If KeyboardPushed(#PB_Key_Pad0)
      Rotate#tipo0#(objeto0#,0,0,0,#PB_Absolute)
      Move#tipo1#(objeto1#,0,0,9,#PB_Absolute)
    EndIf
    estadotecla.b=KeyboardPushed(#PB_Key_#tecla#):estadoteclaf.b=KeyEdgeDetection(#PB_Key_#tecla#,estadotecla.b)
    If estadoteclaf.b>0; <- inicia control camara
      pasocam.f=0.01:pasocamincr.f=0.001
      ShowGUI(222,0,#camara,1):CursorX0.f=CursorX.f:CursorY0.f=CursorY.f
    ElseIf estadoteclaf.b<0; <- termina control camara
      ShowGUI(222,1,#camara,1)
    ElseIf estadotecla.b; <- mover el punto de vista
      MouseLocate(CursorX0.f,CursorY0.f)
      ;para desplazar la camara hacia delante, atras, arriba, abajo, izq o der
      If DELTA\m
        If mmb.b
          Move#tipo1#(objeto1#,DELTA\x/40,-DELTA\y/40,0,#PB_Local)
        Else
          Rotate#tipo0#(objeto0#,-DELTA\y/10,-DELTA\x/10,0,#PB_Relative)
          If DELTA\z
            Move#tipo1#(objeto1#,0,0,-DELTA\z,#PB_Local)
          EndIf
        EndIf
      ElseIf KeyboardPushed(#PB_Key_Add)
        Move#tipo1#(objeto1#,0,0,-pasocam,#PB_Local)
        pasocam+pasocamincr
      ElseIf KeyboardPushed(#PB_Key_Subtract)
        Move#tipo1#(objeto1#,0,0,pasocam,#PB_Local)
        pasocam+pasocamincr
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Pad8)
      If KeyboardPushed(#PB_Key_Pad5)
        Gradosdegiro.d=-90
        AnimacionPivotCamara.b=1:TipodeGiro.b=1
      Else
        Pitch(tipo0#ID(objeto0#),-0.5,#PB_Local|#PB_Relative)
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Pad2)
      If KeyboardPushed(#PB_Key_Pad5)
        Gradosdegiro.d=90
        AnimacionPivotCamara.b=1:TipodeGiro.b=2
      Else
        Pitch(tipo0#ID(objeto0#),0.5,#PB_Local|#PB_Relative)
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Pad4)
      If KeyboardPushed(#PB_Key_Pad5)
        Gradosdegiro.d=-90
        AnimacionPivotCamara.b=1:TipodeGiro.b=3
      Else
        Yaw(tipo0#ID(objeto0#),-0.5,#PB_Local|#PB_Relative)
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Pad6)
      If KeyboardPushed(#PB_Key_Pad5)
        Gradosdegiro.d=90
        AnimacionPivotCamara.b=1:TipodeGiro.b=4
      Else
        Yaw(tipo0#ID(objeto0#),0.5,#PB_Local|#PB_Relative)
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Pad7)
      If KeyboardPushed(#PB_Key_Pad5)
        Gradosdegiro.d=-90
        AnimacionPivotCamara.b=1:TipodeGiro.b=5
      Else
        Roll(tipo0#ID(objeto0#),-0.5,#PB_Local|#PB_Relative)
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Pad9)
      If KeyboardPushed(#PB_Key_Pad5)
        Gradosdegiro.d=90
        AnimacionPivotCamara.b=1:TipodeGiro.b=6
      Else
        Roll(tipo0#ID(objeto0#),0.5,#PB_Local|#PB_Relative)
      EndIf
    EndIf
  EndIf
EndMacro
Macro desplazardesdepuntodevista(entidad)
  ConvertLocalToWorldPosition(CameraID(#camara),THETA\x,-THETA\y,THETA\z)
  THETA\x=GetX():THETA\y=GetY():THETA\z=GetZ():THETA\m=getmodulo(THETA)
  MoveEntity(entidad#,THETA\x,THETA\y,THETA\z,#PB_World|#PB_Relative)
EndMacro
Macro rotardesdepuntodevista(entidad)
  Swap THETA\x,THETA\y
  ConvertLocalToWorldPosition(CameraID(#camara),THETA\x,THETA\y,THETA\z)
  THETA\x=GetX():THETA\y=GetY():THETA\z=GetZ():THETA\m=getmodulo(THETA)
  EntityFixedYawAxis(entidad#,1,THETA\x/THETA\m,THETA\y/THETA\m,THETA\z/THETA\m); <- esta funcion interpreta el eje como local
  Yaw(EntityID(entidad#),Degree(THETA\m),#PB_World|#PB_Relative)
  ;EntityFixedYawAxis(entidad#,0)
EndMacro
Global.Vector3D comodin  ; comodin para todo
Global.Vector3D DELTA,THETA; para puntero ratón en su uso 2D
Global.D3DXVECTOR3 pick,pickv,pos; <- para usar puntero del ratón para referir elementos 3D
Global.Vector3D eje,ele,ene; <- para linea ortogonal 3D
Global EntidadSeleccionada.i

Macro orientacionyangulos()
  ; 'fi->' es el ángulo de inclinación de un objeto 3D con respecto a la 'y' global.
  ; Tras llamar a la función FetchOrientation(), su módulo es |fi->| = 2·ACos(GetW()) , y sus componentes:
  ; fi\x = GetX()/Sin(|fi->|/2) * |fi->| ( o bien fi\x = GetX()/Sqr(1-GetW()^2) * |fi->| )
  ; fi\y = GetY()/Sin(|fi->|/2) * |fi->| ( o bien fi\y = GetY()/Sqr(1-GetW()^2) * |fi->| )
  ; fi\z = GetZ()/Sin(|fi->|/2) * |fi->| ( o bien fi\z = GetZ()/Sqr(1-GetW()^2) * |fi->| )
  ; 'fi-^' es el vector unidad de 'fi->' y por tanto tiene por componentes ( fi\x/|fi->|, fi\y/|fi->|, fi\z/|fi->| )
  fiarrowR.Vector3D
  fiarrowG.Vector3D
  fiarrowB.Vector3D
  FillMemory(@arrowR,SizeOf(Vector3D)):arrowR\y=1
  FillMemory(@arrowG,SizeOf(Vector3D)):arrowG\y=1
  FillMemory(@arrowB,SizeOf(Vector3D)):arrowB\y=1
  FetchOrientation(EntityID(#arrowR),#PB_Absolute)
  fiarrowR\m=2*ACos(GetW())
  If fiarrowR\m
    ww.f=Sin(fiarrowR\m/2)
    fiarrowR\x=GetX():fiarrowR\y=GetY():fiarrowR\z=GetZ()
    fiarrowR\x*fiarrowR\m/ww:fiarrowR\y*fiarrowR\m/ww:fiarrowR\z*fiarrowR\m/ww
    Rotar_Vector3D_por_adicion_Angular(@fiarrowR,@arrowR)
  Else
    fiarrowR\x=0:fiarrowR\y=0:fiarrowR\z=0
  EndIf
  FetchOrientation(EntityID(#arrowG),#PB_Absolute)
  fiarrowG\m=2*ACos(GetW())
  If fiarrowG\m
    ww.f=Sin(fiarrowG\m/2)
    fiarrowG\x=GetX()*fiarrowG\m/ww:fiarrowG\y=GetY()*fiarrowG\m/ww:fiarrowG\z=GetZ()*fiarrowG\m/ww
    Rotar_Vector3D_por_adicion_Angular(@fiarrowG,@arrowG)
  Else
    fiarrowG\x=0:fiarrowG\y=0:fiarrowG\z=0
  EndIf
  FetchOrientation(EntityID(#arrowB),#PB_Absolute)
  fiarrowB\m=2*ACos(GetW())
  If fiarrowB\m
    ww.f=Sin(fiarrowB\m/2)
    fiarrowB\x=GetX()*fiarrowB\m/ww:fiarrowB\y=GetY()*fiarrowB\m/ww:fiarrowB\z=GetZ()*fiarrowB\m/ww
    Rotar_Vector3D_por_adicion_Angular(@fiarrowB,@arrowB)
  Else
    fiarrowB\x=0:fiarrowB\y=0:fiarrowB\z=0
  EndIf
;   flechaR\x=EntityDirectionX(#flechaR):flechaR\y=EntityDirectionY(#flechaR):flechaR\z=EntityDirectionZ(#flechaR); <- resultados incorrectos
;   flechaG\x=EntityDirectionX(#flechaG):flechaG\y=EntityDirectionY(#flechaG):flechaG\z=EntityDirectionZ(#flechaG); <- resultados incorrectos
;   flechaB\x=EntityDirectionX(#flechaB):flechaB\y=EntityDirectionY(#flechaB):flechaB\z=EntityDirectionZ(#flechaB); <- resultados incorrectos
  AnguloFormadoPor2Vectores(arrowR,arrowG,comodin)
  Text3DCaption(#texto1,"Global Orientation of R:    "+StrF(arrowR\x,2)+","+StrF(arrowR\y,2)+","+StrF(arrowR\z,2)+#LFCR$+
                        "Global Orientation of G:    "+StrF(arrowG\x,2)+","+StrF(arrowG\y,2)+","+StrF(arrowG\z,2)+#LFCR$+
                        "Global Orientation of B:    "+StrF(arrowB\x,2)+","+StrF(arrowB\y,2)+","+StrF(arrowB\z,2)+#LFCR$+
                        "Total angle between R and G:    "+StrF(Degree(comodin\m),2)+"º")
EndMacro
CreateLight(#luz,$EEEEEE,4,4,2,#PB_Light_Point):SetLightColor(#luz,#PB_Light_DiffuseColor,$EEEEEE):MoveLight(#luz,4,4,2,#PB_Absolute)
CreateCamera(#camara,0,0,100,100):CreateNode(#pivotcamara,0,0,0):AttachNodeObject(#pivotcamara,CameraID(#camara)):CameraRange(#camara,0.1,1E4):MoveCamera(#camara,0,0,9,#PB_Absolute)
SkyBox("desert07.jpg")
;
arrowR.Vector3D:arrowG.Vector3D:arrowB.Vector3D
FillMemory(@arrowR,SizeOf(Vector3D)):arrowR\x=1
FillMemory(@arrowG,SizeOf(Vector3D)):arrowG\y=1
FillMemory(@arrowB,SizeOf(Vector3D)):arrowB\z=-1
arrow(#arrowR,$AA7A8BF9,0,0.075,2,"R","StarWars",0.5,2,2.25,1/30):EntityDirection(#arrowR,arrowR\x,arrowR\y,arrowR\z,#PB_Absolute|#PB_World,#PB_Vector_Y)
arrow(#arrowG,$AAAAF9BB,0,0.075,2,"G","StarWars",0.5,2,2.25,1/30):EntityDirection(#arrowG,arrowG\x,arrowG\y,arrowG\z,#PB_Absolute|#PB_World,#PB_Vector_Y)
arrow(#arrowB,$AAFEAAA3,0,0.075,2,"B","StarWars",0.5,2,2.25,1/30):EntityDirection(#arrowB,arrowB\x,arrowB\y,arrowB\z,#PB_Absolute|#PB_World,#PB_Vector_Y)
CreateText3D(#texto1,"epale!","",1,$DDDDDDDD)
Text3DAlignment(#texto1,#PB_Text3D_HorizontallyCentered|#PB_Text3D_Top)
ScaleText3D(#texto1,0.3,0.4,0.1,#PB_Relative)
AttachNodeObject(#Pivotcamara,Text3DID(#texto1))
MoveText3D(#texto1,-3,2,0,#PB_Absolute|#PB_World)
orientacionyangulos()
EntidadSeleccionada.i=-1
ShowGUI(222,1,#camara,1)
Repeat
  Repeat:evento.i=WindowEvent():Until evento=#PB_Event_None
  ExamineMouse():ExamineKeyboard()
  CursorX.f=MouseX():CursorY.f=MouseY():lmb.b=MouseButton(#PB_MouseButton_Left):rmb.b=MouseButton(#PB_MouseButton_Right):mmb.b=MouseButton(#PB_MouseButton_Middle)
  DELTA\x=MouseDeltaX():DELTA\y=MouseDeltaY():DELTA\z=MouseWheel():DELTA\m=getmodulo(DELTA)
  wCursorX.f=WindowMouseX(#ventana):wCursorY.f=WindowMouseY(#ventana)
  OrbitarObjeto1SobreObjeto0(LeftControl,Camera,#camara,Node,#Pivotcamara)
  InputEvent3D(CursorX.f,CursorY.f,lmb.b)
  lmbe.b=MouseButtonEdgeDetection(#PB_MouseButton_Left,lmb)
  mmbe.b=MouseButtonEdgeDetection(#PB_MouseButton_Middle,mmb)
  If lmbe.b=1 Or mmbe.b=1
    ShowGUI(222,0,#camara,1)
    EntidadSeleccionada.i=MouseRayCast(#camara,CursorX,CursorY,-1)
    Select EntidadSeleccionada.i
    Case #arrowR:EntidadSeleccionada$="arrowR"
    Case #arrowG:EntidadSeleccionada$="arrowG"
    Case #arrowB:EntidadSeleccionada$="arrowB"
    Default:EntidadSeleccionada$=""
    EndSelect
    If EntidadSeleccionada$
      anchuratexto.u=Len(EntidadSeleccionada$)*14
      pick\x=PickX():pick\y=PickY():pick\z=PickZ()
      pos\x=EntityX(EntidadSeleccionada,#PB_Absolute):pos\y=EntityY(EntidadSeleccionada,#PB_Absolute):pos\z=EntityZ(EntidadSeleccionada,#PB_Absolute)
      pick=pos
      OpenWindow3D(#TextoInfoObjeto,CameraProjectionX(#camara,pick\x,pick\y,pick\z),CameraProjectionY(#camara,pick\x,pick\y,pick\z),anchuratexto.u,32,"detalles objeto",#PB_Window3D_SizeGadget|#PB_Window3D_BorderLess)
      TextGadget3D(#TextoInfoObjeto,0,-1,anchuratexto.u,32,EntidadSeleccionada$)
    EndIf
  ElseIf lmbe.b=-1 Or mmbe.b=-1
    ShowGUI(222,1,#camara,1)
    If EntidadSeleccionada$
      pos\x=EntityX(EntidadSeleccionada,#PB_Absolute):pos\y=EntityY(EntidadSeleccionada,#PB_Absolute):pos\z=EntityZ(EntidadSeleccionada,#PB_Absolute)
      MouseLocate(CameraProjectionX(#camara,pos\x,pos\y,pos\z),CameraProjectionY(#camara,pos\x,pos\y,pos\z))
      If IsWindow3D(#TextoInfoObjeto)
        FreeGadget3D(#PB_All)
        CloseWindow3D(#TextoInfoObjeto)
      EndIf
      EntidadSeleccionada$=""
    EndIf
  EndIf
  If DELTA\m And EntidadSeleccionada$ And IsWindow3D(#TextoInfoObjeto)
    THETA=DELTA:THETA\x/100:THETA\y/100:THETA\z/20:THETA\m=getmodulo(THETA)
    If lmb.b; mover
      pos\x=EntityX(EntidadSeleccionada,#PB_Absolute):pos\y=EntityY(EntidadSeleccionada,#PB_Absolute):pos\z=EntityZ(EntidadSeleccionada,#PB_Absolute)
      pick\x=CameraProjectionX(#camara,pos\x,pos\y,pos\z);+pickv\x
      pick\y=CameraProjectionY(#camara,pos\x,pos\y,pos\z);+pickv\y
      ResizeWindow3D(#TextoInfoObjeto,pick\x,pick\y,anchuratexto.u,#PB_Ignore)
      desplazardesdepuntodevista(EntidadSeleccionada); <- mover
    ElseIf mmb.b; rotar
      rotardesdepuntodevista(EntidadSeleccionada)
      orientacionyangulos()
    EndIf
  EndIf
  TimeSinceLastFrame.i=RenderWorld(50)
  FlipBuffers()
;   StartDrawing(WindowOutput(#ventana))
;   DrawText(0,RY-80,"res: "+StrU(RX)+","+StrU(RY))
;   DrawText(0,RY-60,"scr: "+StrF(CursorX,2)+","+StrF(CursorY,2))
;   DrawText(0,RY-40,"win: "+StrF(wCursorX,2)+","+StrF(wCursorY,2))
;   StopDrawing()
  Delay(6)
Until KeyboardPushed(#PB_Key_Escape)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
minimy
Enthusiast
Enthusiast
Posts: 619
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: Tip; HOWTO get a reliable global orientation of any 3D object

Post by minimy »

Hello Psycophanta, interesting, thanks for share!
And thanks for spanish comments! Ole, ole y ole! :lol:
If translation=Error: reply="Sorry, Im Spanish": Endif
SMaag
Enthusiast
Enthusiast
Posts: 325
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Tip; HOWTO get a reliable global orientation of any 3D object

Post by SMaag »

I see, more and more people start with 3D programming. And all will come to the point, they need
3D Vector arithmetic.
For optimizing that issue I startet some Vector Module projects which wraps the Vector and Matrix operation for
3D calculations. I programmed nearly all functions in classic PB code and SSE optimized versions in Assembler-
It's not ready developped yet. But there is a lot of documentaion of the basic knowledge.
I hope some of you will try to use this Modules to see what is not working and to make it better!

here the Float basec Vector Modul
https://github.com/Maagic7/PureBasicFra ... VECTORd.pb

here the same for doubles
https://github.com/Maagic7/PureBasicFra ... VECTORd.pb

To run it, you need more modules what are part of my PB Framwork. Download it from the same location!
Post Reply