Page 1 of 2

3D challenge for a special rotation

Posted: Tue Mar 05, 2019 3:28 pm
by Psychophanta
Purpose of a 3D challenge.
Just get the executeable (put first the 'Engine3D.dll' in the system directory or in the same dir than the executeable)

After run it, you can see an object (Entity) which can be rotated using mouse movements, and the rotation of the entity is such that it rotates in the same direction as the mouse movements.

Now, while pushing left-control key and moving mouse, the camera orbitates around the object in the world.

Again, pop the left-control key and you can see ALWAYS the object rotates in the same direction as the mouse movements, nevertheless the camera looking vector is.

The issue seems trivial. So, I don't give you any code, just try to do with your own code; will see the triviality of it :twisted:

By the way, I have not seen any 3D CAD-CAM program which do that: at least Catia, Solidworks, Inventor, Cinema4D, Blender, Rhinoceros, Sketchup, AutoCAD do not it. Why? I don't know.
windows 32bit : https://www.dropbox.com/s/hels4zqy29y16 ... tation.exe
windows 64bit : https://www.dropbox.com/s/55ru9ynhm9376 ... nwin64.exe

Re: 3D challenge for a special rotation

Posted: Tue Mar 05, 2019 7:58 pm
by TI-994A
Just for the fun of it, my very first 3D code, cobbled together from the samples.

Code: Select all

Define keyX.f, mouseX.f, wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered,
       keys$ = "Mouse & Left/Right Arrows to move - Spacebar to stop - ESC to quit"

If InitEngine3D() And InitSprite() And InitKeyboard() And InitMouse() And
   OpenWindow(0, 0, 0, 800, 600, "3D Challenge - " + keys$, wFlags) And
   OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0)    
  
  KeyboardMode(#PB_Keyboard_International) 
  
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Packs/desert.zip", #PB_3DArchive_Zip)            
  
  CreateSphere(0, 9)
  CreateMaterial(0, TextureID(LoadTexture(#PB_Any, "glass.png")))            
  CreateEntity(0, MeshID(0), MaterialID(0), 0, 0, -10)
  CreateLight(0, RGB(150, 200, 200), 200, 200, 200)
  AmbientColor(RGB(220, 30, 30))      
  SkyBox("desert07.jpg")
  CreateCamera(0, 0, 0, 100, 100)
  MoveCamera(0, 0, 0, 50, #PB_Absolute)
  
  Repeat
    
    Repeat
      event = WindowEvent()
      Select event
        Case #PB_Event_CloseWindow
          appQuit = 1
      EndSelect      
    Until event = 0
        
    If ExamineMouse()            
      lastMouseX = mouseX
      mouseX = -MouseDeltaX() * 0.5 * 0.05
      If mouseX <> lastMouseX
        keyX = 0
        MoveCamera(0, mouseX, 0, 0)
        RotateCamera(0, 0, mouseX, 0, #PB_Relative) 
      EndIf      
    EndIf
    
    If ExamineKeyboard()        
      If KeyboardPushed(#PB_Key_Left)
        keyX = -0.5
      ElseIf KeyboardPushed(#PB_Key_Right)
        keyX = 0.5
      ElseIf KeyboardPushed(#PB_Key_Space)
        keyX = 0
      ElseIf KeyboardPushed(#PB_Key_Escape)
        appQuit = 1
      EndIf          
      MoveCamera(0, keyX, 0, 0)
      RotateCamera(0, 0, keyX, 0, #PB_Relative)              
    EndIf    
    
    RenderWorld()
    FlipBuffers()
    
  Until appQuit      
EndIf
Educational, to say the least; but most of all, fun! :lol:

Re: 3D challenge for a special rotation

Posted: Wed Mar 06, 2019 11:05 am
by Psychophanta
Welcome to 3D world !
Walk more inside and then will see 3D programming is not much to do with other programming. :wink:

Re: 3D challenge for a special rotation

Posted: Wed Mar 06, 2019 11:24 am
by TI-994A
Psychophanta wrote:...3D programming is not much to do with other programming. :wink:
Very true. Everything's handled by the rendering engine; we're basically scripting. Testing out the various examples in the 3D folder was a real eye-opener; demystifying!

Re: 3D challenge for a special rotation

Posted: Wed Mar 06, 2019 2:26 pm
by TI-994A
ymerdy wrote:I have copied the Engine3D.dll in the same dir than the executable, and I still have the message "the 3D engine can't be initialized".
Which example are you trying to run? And does it work in the PureBasic IDE?

Re: 3D challenge for a special rotation

Posted: Wed Mar 06, 2019 5:10 pm
by Psychophanta
ymerdy wrote:Hello,

I have copied the Engine3D.dll in the same dir than the executable, and I still have the message "the 3D engine can't be initialized".
Must be the 'Engine3D.dll' file you find inside "C:\programfiles\PureBasic5.70\Compilers".
'Engine3D.dll' 5.70 PB version.

Re: 3D challenge for a special rotation

Posted: Thu Mar 07, 2019 6:50 pm
by Psychophanta
ymerdy wrote:Hello,

yes, that's what I did, I copied the dll from PB 5.70 version, but the exe don't start...
That is very strange, but sure there is something wrong, i can not help you, sorry.

Re: 3D challenge for a special rotation

Posted: Fri Mar 08, 2019 12:02 pm
by djes
Psychophanta wrote:
ymerdy wrote:Hello,

yes, that's what I did, I copied the dll from PB 5.70 version, but the exe don't start...
That is very strange, but sure there is something wrong, i can not help you, sorry.
Needs x86 version, not x64.

Re: 3D challenge for a special rotation

Posted: Mon Mar 11, 2019 2:53 pm
by NicTheQuick
Why are they still people using the 32 bit versions? This is old stuff, use it only if there is no other way.

Re: 3D challenge for a special rotation

Posted: Mon Mar 11, 2019 8:31 pm
by Psychophanta
NicTheQuick wrote:Why are they still people using the 32 bit versions? This is old stuff, use it only if there is no other way.
:lol:
Sorry, I work with linux 64bit and XP 32bit.
XP is much faster than 7, 8.1 and 10. I don't support a OS slower than myself.
That IS a true, so my OS is XP and linux, because i use computer to produce.

But you are right, most people use 64bit. So uploaded win64 bit in first post.

Re: 3D challenge for a special rotation

Posted: Tue Mar 12, 2019 12:53 am
by NicTheQuick
If you are still using XP you've got much more problems than a slow machine. Kill it with fire, upgrade to Windows 7 or 10 or delete it completely to switch to Linux. But don't use operating systems with security holes and old encryption techniques in combination with internet. As a programmer you should know what that means. Hopefully...

Re: 3D challenge for a special rotation

Posted: Tue Mar 12, 2019 1:22 pm
by Psychophanta
NicTheQuick wrote:If you are still using XP you've got much more problems than a slow machine. Kill it with fire, upgrade to Windows 7 or 10 or delete it completely to switch to Linux. But don't use operating systems with security holes and old encryption techniques in combination with internet. As a programmer you should know what that means. Hopefully...
This is full off topic.
Well I use it since 2003, with no antivirus never, with no problems.

Windows 7, 8 and 10 are virus itselves, and a undefined amount of lacks , slowing , and problems.
The first thing i got very scared was this simple example:
In a spanish installation of 7, 8, 8.1, or 10, in C: (system partition) there is not appear a folder named "Program files", however system does not allow to create a folder named "Program files".
This fact is just a sympthom the entire system IS A VIRUS.

Re: 3D challenge for a special rotation

Posted: Tue Mar 12, 2019 1:41 pm
by TI-994A
NicTheQuick wrote:...don't use operating systems with security holes...
> Windows 10 Vulnerabilities

Re: 3D challenge for a special rotation

Posted: Fri Mar 15, 2019 6:07 pm
by DK_PETER
TI-994A wrote:
NicTheQuick wrote:...don't use operating systems with security holes...
> Windows 10 Vulnerabilities
@TI-994A
Your vulnerabilities list is really outdated.
Several patches has been released which makes your list redundant. :wink:

@NicTheQuick
Security holes exists in almost all operating systems..."Almost" every time they plug a security hole - a new unforeseen 'gravelpit' or another exploitation digs forth a new security hole.
Linux and Mac OS are no exception to the rule.
https://www.cvedetails.com/vulnerabilit ... -Os-X.html
https://www.cvedetails.com/vulnerabilit ... ernel.html

Anyway...If a specific OS serves you well...Then use it. 8)

Re: 3D challenge for a special rotation

Posted: Mon Sep 18, 2023 4:14 pm
by Psychophanta
This is a tip to do (and explain) the main of this forum thread:

Code: Select all

InitEngine3D()
InitSprite():InitKeyboard():InitMouse()
OpenWindow(0,0,0,800,600,"tip",#PB_Window_BorderLess|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0,#PB_Screen_WaitSynchronization)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/fonts", #PB_3DArchive_FileSystem)
Parse3DScripts()
CreateLight(0,$EEEEEE,4,4,2,#PB_Light_Point)
CreateCamera(0,0,0,100,100):CameraProjectionMode(0,#PB_Camera_Perspective)
MoveCamera(0,0,0,3,#PB_Absolute)
CreateMaterial(0,0,$33EEEE)
CreateMaterial(1,LoadTexture(1,"soil_wall.jpg"))

CreateCylinder(0,0.025,2):TransformMesh(0,0,0,0,1,1,1,90,0,0)
CreateText3D(0,"incl","",0.2,$8899FAFA):MoveText3D(0,-1.2,0,0)
CreateCube(1,0.5)
CreateEntity(0,MeshID(0),MaterialID(0),0,0,0):RotateEntity(0,90,0,0)
CreateEntity(1,MeshID(1),MaterialID(1),0,0,0)

Structure D3DXVECTOR3
  x.f
  y.f
  z.f
EndStructure
Structure Vector3D Extends D3DXVECTOR3
  m.f;<-length(modulo)
EndStructure

Macro RotarSobreEjeGlobalArbitrario(objeto,ejeglobal,angulo); <- rota una entidad alrededor de un eje arbitrario global dado.
  provis.Vector3D
  ConvertWorldToLocalPosition(EntityID(objeto#),ejeglobal#\x+EntityX(objeto#),ejeglobal#\y+EntityY(objeto#),ejeglobal#\z+EntityZ(objeto#)); <- convierte una posición referenciada en la base global de coordenadas hacia una posición referenciada en la base local del objeto
  provis\x=GetX():provis\y=GetY():provis\z=GetZ():provis\m=Sqr(Pow(provis\x,2)+Pow(provis\y,2)+Pow(provis\z,2))
  If provis\m>0.000001
    EntityFixedYawAxis(objeto#,1,provis\x/provis\m,provis\y/provis\m,provis\z/provis\m); <- esta funcion interpreta el eje como local, asi que hay que transformar un vector de global a local
    Yaw(EntityID(objeto#),Degree(angulo#),#PB_Local|#PB_Relative)
    EntityFixedYawAxis(objeto#,0)
  EndIf
EndMacro

v.Vector3D
Repeat
  While WindowEvent():Wend
  ExamineMouse():ExamineKeyboard()
  CursorX.f=MouseX():CursorY.f=MouseY():lmb.b=MouseButton(#PB_MouseButton_Left):rmb.b=MouseButton(#PB_MouseButton_Right)
  mdx.f=MouseDeltaX()/20:mdy.f=MouseDeltaY()/20:mdz.f=MouseWheel()*5
  If rmb
    RotarSobreEjeGlobalArbitrario(1,v,mdx/20)
  Else
    RotateEntity(0,mdy,-mdx,mdz,#PB_Relative)
    v\x=EntityDirectionX(0)
    v\y=EntityDirectionY(0)
    v\z=EntityDirectionZ(0)
    Text3DCaption(0,StrF(w,2)+","+StrF(v\x,2)+","+StrF(v\y,2)+","+StrF(v\z,2))
  EndIf
  RenderWorld()
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
And this is the base program i made in the date commented at head of the code:

Code: Select all

; Rota una entidad alrededor de un eje global dado. Hecho con PB nativo en Febrero 2019.
;/ inits
Global pantallacompleta.b=0,Titulo$="Rota una entidad alrededor de un eje global dado. Hecho con PB nativo en Febrero 2019"
If ExamineDesktops()=0:End:EndIf
Global bitplanes.a=DesktopDepth(0),FRX.u=DesktopWidth(0),FRY.u=DesktopHeight(0),RX.u=FRX,RY.u=FRY,FrecuenciadeMuestreo.u=60
If FRX<1280 Or FRY<720:RX=FRX*2/3:RY=FRY*2/3:Else:RX=1280:RY=720:EndIf
If InitEngine3D(#PB_Engine3D_NoLog,#PB_Compiler_Home+"Compilers\Engine3d.dll")=0
  MessageRequester("Error","The 3D Engine can't be initialized",0):End
EndIf
InitSprite():InitKeyboard():InitMouse()
OpenWindow(0,0,0,RX,RY,Titulo$,#PB_Window_BorderLess|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,RX,RY,1,0,0,#PB_Screen_WaitSynchronization)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Packs/skybox.zip",#PB_3DArchive_Zip)
Enumeration; Camaras
  #Camara
EndEnumeration
Enumeration; Luces
  #Luz
EndEnumeration
Enumeration; Texturas
  #Textura
EndEnumeration
Enumeration; Materiales
  #Material
EndEnumeration
Enumeration; Mallas
  #Objectmalla
EndEnumeration
Enumeration; Entidades
  #Object
EndEnumeration
Enumeration; Nodos
  #Pivotcamara
EndEnumeration
;\
Structure D3DXVECTOR3
  x.f
  y.f
  z.f
EndStructure
Structure Vector3D Extends D3DXVECTOR3
  m.f;<-length(modulo)
EndStructure
Structure BaseVectorial
  i.D3DXVECTOR3
  j.D3DXVECTOR3
  k.D3DXVECTOR3
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.b KeyEdgeDetection(key.a)
  Static pka.a
  If KeyboardPushed(key);<-if current key status is PUSHED
    If pka=0:pka=key:ProcedureReturn 1:EndIf;<-if previous key status was NOT PUSHED, then assign previous state to current one, and EXIT.
  ElseIf pka=key;<-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
Macro TeclaControldecamara(tecla=LeftControl)
  If KeyEdgeDetection(#PB_Key_#tecla#); <- inicia control camara
    pasocam.f=0.01:pasocamincr.f=0.001
  ElseIf KeyboardReleased(#PB_Key_#tecla#)
  ElseIf KeyboardPushed(#PB_Key_#tecla#); <- mover el punto de vista
    ;para desplazar la camara hacia delante, atras, arriba, abajo, izq o der
    If mdx Or mdy Or mdz
      If mmb.b
        MoveNode(#Pivotcamara,mdx,-mdy,0,#PB_Local); o MoveCamera(#Camara,mdx,-mdy,0,#PB_Local) o MoveCamera(#Camara,mdx,-mdy,0,#PB_Relative)
      Else
        RotateNode(#Pivotcamara,-mdy*60,-mdx*60,0,#PB_Relative)
        If mdz
          MoveCamera(#Camara,0,0,-mdz,#PB_Relative)
        EndIf
      EndIf
    ElseIf KeyboardPushed(#PB_Key_Add)
      MoveCamera(#Camara,0,0,-pasocam,#PB_Relative)
      pasocam+pasocamincr
    ElseIf KeyboardPushed(#PB_Key_Subtract)
      MoveCamera(#Camara,0,0,pasocam,#PB_Relative)
      pasocam+pasocamincr
    ElseIf KeyboardPushed(#PB_Key_Pad8)
      MoveCamera(#Camara,0,pasocam,0,#PB_Relative)
      pasocam+pasocamincr
    ElseIf KeyboardPushed(#PB_Key_Pad2)
      MoveCamera(#Camara,0,-pasocam,0,#PB_Relative)
      pasocam+pasocamincr
    ElseIf KeyboardPushed(#PB_Key_Pad6)
      MoveCamera(#Camara,pasocam,0,0,#PB_Relative)
      pasocam+pasocamincr
    ElseIf KeyboardPushed(#PB_Key_Pad4)
      MoveCamera(#Camara,-pasocam,0,0,#PB_Relative)
      pasocam+pasocamincr
    ElseIf KeyboardPushed(#PB_Key_Pad1)
      RotateNode(#Pivotcamara,0,-0.5,0,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_Pad7)
      RotateNode(#Pivotcamara,0,0.5,0,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_Pad3) Or lmb.b
      RotateNode(#Pivotcamara,0,0,-0.5,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_Pad9) Or rmb.b
      RotateNode(#Pivotcamara,0,0,0.5,#PB_Relative)
    EndIf
EndMacro
Macro resetear
  RotateNode(#Pivotcamara,0,0,0,#PB_Absolute)
  MoveCamera(#Camara,0,0,6,#PB_Absolute)
EndMacro
SkyBox("stevecube.jpg")
CreateLight(#luz,$EEEEEE,4,4,2,#PB_Light_Point)
CreateCamera(#Camara,0,0,100,100):CreateNode(#Pivotcamara,0,0,0):AttachNodeObject(#Pivotcamara,CameraID(#Camara)):CameraRange(#Camara,0.1,10000):CameraBackColor(#Camara,$181911)
MoveCamera(#Camara,0,0,6,#PB_Absolute)
If CreateTexture(#Textura,32,32)
  Font.i=LoadFont(#PB_Any,"Arial",8)
  StartDrawing(TextureOutput(#Textura))
  Box(0,0,16,16,RGB(255,0,0))
  Box(16,0,16,16,RGB(0,255,0))
  Box(0,16,16,16,RGB(0,0,255))
  Box(16,16,16,16,RGB(255,255,0))
  DrawingFont(FontID(Font))
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(6,2,"hola",RGB(0,0,0))
  DrawText(1,14,"mundo",RGB(0,0,0))
  StopDrawing()
EndIf
CreateMaterial(#material,TextureID(#textura))
CreateCube(#Objectmalla,1)
CreateEntity(#Object,MeshID(#Objectmalla),MaterialID(#material),0,0.1581,0);:RotateEntity(#Object,1,20,3)
Macro ObtenerEjeLocalJdeunObjeto(tipo,objeto,vectorY)
  Pitch(tipo#ID(objeto#),90.0,#PB_Local|#PB_Relative)
  vectorY#\x=tipo#DirectionX(objeto#):vectorY#\y=tipo#DirectionY(objeto#):vectorY#\z=tipo#DirectionZ(objeto#)
  Pitch(tipo#ID(objeto#),270.0,#PB_Local|#PB_Relative)
EndMacro
Macro ObtenerBasedeOrientaciondeunObjeto(tipo,objeto,Base); <- el 'tipo' puede ser 'Camera', 'Entity' o 'Light'. 'Base' es del tipo .BaseVectorial
  ;Si se traza un segmento rectilineo desde un punto dado en el espacio ('objeto') hasta el centroide de un cuerpo dado ('objeto'), este segmento determina un plano normal a él, el cual contiene el centroide de 'objeto'.
  ;Lo que hace esta función es rotar 'objeto' alrededor de un eje dado ('fi->') referenciado a una base global de coordenadas.
  ;Dado que el 'objeto' tiene una orientación propia arbitraria, se necesita la base de coordenadas de este 'objeto' respecto a la base de referencia global.
  ;El eje alrededor del cual rota el 'objeto', así como la cantidad angular a rotar, está determinada por un vector angulo dado ('fi->'), o bien, un vector unidad más un valor escalar angular dados.
  ;Para rotar el 'objeto' con referencia a ese plano, el vector 'fi->' hay que referenciarlo a la base de orientación de 'objeto'
  ;Tenemos entonces 3 elementos de entrada a la funcion:
  ;1- un cuerpo en el espacio
  ;2- un punto en el espacio no coincidente con el centroide del cuerpo
  ;3- un vector angulo, o bien, un vector unidad más un valor escalar angular.
  ;'objeto' es la entidad o nodo de la cual debemos conocer su base de coordenadas, es decir su orientación propia 'x', 'y', y 'z' con respecto a la base global.
  ;'fi->' es el vector, dado en coordenadas globales, que hay que referenciar a coordenadas de 'objeto'
  ;'Base#.BaseVectorial\i->' será el vector 'i' de la base de orientación de 'objeto' con respecto al sistema global
  ;'Base#.BaseVectorial\j->' será el vector 'j' de la base de orientación de 'objeto' con respecto al sistema global
  ;'Base#.BaseVectorial\k->' será el vector 'k' de la base de orientación de 'objeto' con respecto al sistema global
  ;Para obtener la base de coordenadas de 'objeto':
  ;Dado que EntityRoll(objeto#,#PB_Absolute|#PB_Engine3D_Raw) nos da el angulo en que Base#\z-> es torsionado, entonces Base#\y-> y Base#\x-> los podremos conocer. Pero de momento no se como, así que hago esto:
  ;giro 'objeto' -90 grados sobre su propio eje 'y' para obtener su eje 'x' , y luego la dejo como estaba:
  Base#\k\x=tipo#DirectionX(objeto#):Base#\k\y=tipo#DirectionY(objeto#):Base#\k\z=tipo#DirectionZ(objeto#)
  ObtenerEjeLocalJdeunObjeto(tipo#,objeto#,Base#\j)
  ProductoVectorial(Base#\k,Base#\j,Base#\i)
  ;Ya tenemos la triada de vectores correspondientes a las base del objeto 'objeto' (Base#\i-> , Base#\j-> y Base#\k-> )
EndMacro
Macro ObtenerVectorReferidoaBasedeCoordenadasDada(Base,fi,local)
  ;Para obtener el vector 'fi' referenciado a esa 'Base':
  local#\x=Base#\i\x*fi#\x+Base#\j\x*fi#\y+Base#\k\x*fi#\z
  local#\y=Base#\i\y*fi#\x+Base#\j\y*fi#\y+Base#\k\y*fi#\z
  local#\z=Base#\i\z*fi#\x+Base#\j\z*fi#\y+Base#\k\z*fi#\z
EndMacro
Macro RotarSobreEjeGlobalArbitrario(objeto,ejeglobal,angulo); <- rota una entidad alrededor de un eje arbitrario global dado.
  provis.Vector3D
  ConvertWorldToLocalPosition(EntityID(objeto#),ejeglobal#\x+EntityX(objeto#),ejeglobal#\y+EntityY(objeto#),ejeglobal#\z+EntityZ(objeto#)); <- convierte una posición referenciada en la base global de coordenadas hacia una posición referenciada en la base local del objeto
  provis\x=GetX():provis\y=GetY():provis\z=GetZ():provis\m=getmodulo(provis)
  If provis\m>0.000001
    EntityFixedYawAxis(objeto#,1,provis\x/provis\m,provis\y/provis\m,provis\z/provis\m); <- esta funcion interpreta el eje como local, asi que hay que transformar un vector de global a local
    Yaw(EntityID(objeto#),Degree(angulo#),#PB_Local|#PB_Relative)
    EntityFixedYawAxis(objeto#,0)
  EndIf
EndMacro
Macro RotarObjetoSobreEjeReferidoaBaseDada(objetoarotar,tipodeobjeto,objeto,vector,angulo); el plano lo establece la base de coordenadas del objeto 'ojo'
  ObtenerBasedeOrientaciondeunObjeto(tipodeobjeto#,objeto#,base.BaseVectorial); <- obtener la base de coordenadas de un objeto
  ObtenerVectorReferidoaBasedeCoordenadasDada(base.BaseVectorial,vector#,eje.Vector3D); <- obtener el vector 'eje', referenciado en la base de coordenadas de 'ojo'.
  RotarSobreEjeGlobalArbitrario(objetoarotar#,eje.Vector3D,angulo#); <- rotar el objeto sobre ese 'eje'
EndMacro
Macro RotarObjetoSobreEjeReferidoaBaseDada1(objetoarotar,tipodeobjeto,objeto,vector,angulo); Pendiente de hacer: con cuaternios, simplificando lo más posible
      ;El cuaternio son 4 escalares: x=a*Sin(fi/2), y=b*Sin(fi/2), z=c*Sin(fi/2), w=Cos(fi/2)
      ;Donde (a,b,c) es el vector unitario sobre el que rota y 'fi' es la magnitud a rotar
      ;Obtenemos el cuaternio:
      qcam.Vector4
      FetchOrientation(CameraID(#Camara),#PB_Absolute):qcam\x=GetX():qcam\y=GetY():qcam\z=GetZ():qcam\w=GetW()
      ficam.f=2*ACos(qcam\w); <- esto es la 'fi', que es la inclinacion respecto al eje 'y' global
      If Abs(qcam\w)<1
        acam.f=qcam\x/Sin(ficam/2); <- valor escalar 'x' del vector unitario de la inclinacion respecto al eje 'y' global
        bcam.f=qcam\y/Sin(ficam/2); <- valor escalar 'y' del vector unitario de la inclinacion respecto al eje 'y' global
        ccam.f=qcam\z/Sin(ficam/2); <- valor escalar 'z' del vector unitario de la inclinacion respecto al eje 'y' global
      Else
        acam.f=0
        bcam.f=0
        ccam.f=0
      EndIf
      ; NOTA: (acam,bcam,ccam) ES LA UNIDAD VECTOR-ANGULO DEL CUERPO RESPECTO AL VECTOR GLOBAL (0,1,0), SIENDO 'ficam' LA AMPLITUD DE DICHO ANGULO.
      ;Obtenemos el cuaternio:
      qent.Vector4
      FetchOrientation(EntityID(objeto#),#PB_Absolute):qent\x=GetX():qent\y=GetY():qent\z=GetZ():qent\w=GetW()
      fient.f=2*ACos(qent\w); <- esto es la 'fi', que es la inclinacion respecto al eje 'y' global
      If Abs(qent\w)<1
        aent.f=qent\x/Sin(fient/2); <- valor escalar 'x' del vector unitario de la inclinacion respecto al eje 'y' global
        bent.f=qent\y/Sin(fient/2); <- valor escalar 'y' del vector unitario de la inclinacion respecto al eje 'y' global
        cent.f=qent\z/Sin(fient/2); <- valor escalar 'z' del vector unitario de la inclinacion respecto al eje 'y' global
      Else
        aent.f=0
        bent.f=0
        cent.f=0
      EndIf
      ; NOTA: (aent,bent,cent) ES LA UNIDAD VECTOR-ANGULO DEL CUERPO RESPECTO AL VECTOR GLOBAL (0,1,0), SIENDO 'fient' LA AMPLITUD DE DICHO ANGULO.
      
;       debug acam
;       debug bcam
;       debug ccam
      debug aent
      debug bent
      debug cent

      debug "----------"
      
      ;Introducimos este cuaternio modificado por el valor de 'THETA' al objeto:
      ;fient.f=0
      SetOrientation(EntityID(objeto#),acam.f*Sin(ficam/2),bcam.f*Sin(ficam/2),ccam.f*Sin(ficam/2),Cos(ficam/2))
      
EndMacro
Repeat:While WindowEvent()<>#PB_Event_None:Wend
  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)
  mdx.f=MouseDeltaX()/200:mdy.f=MouseDeltaY()/200:mdz.f=MouseWheel()/20
  TeclaControldecamara(LeftControl)
  ElseIf KeyboardPushed(#PB_Key_F5):resetear
  ElseIf rmb
    MoveEntity(#Object,mdx,-mdy,-mdz,#PB_World|#PB_Relative)
  Else
    THETA.f=Sqr(mdx.f*mdx.f+mdy.f*mdy.f+mdz.f*mdz.f)
    If THETA
      vectordeentrada.Vector3D
      vectordeentrada\x=mdy:vectordeentrada\y=mdx:vectordeentrada\z=mdz:vectordeentrada\m=getmodulo(vectordeentrada)
      RotarObjetoSobreEjeReferidoaBaseDada(#Object,Camera,#Camara,vectordeentrada.Vector3D,THETA)
    EndIf
  EndIf
  TimeSinceLastFrame.i=RenderWorld(50)
  FlipBuffers():Delay(15)
Until KeyboardPushed(#PB_Key_Escape)