- To give some clearification thinks to take in account related to orientation of 3D objects in the 3D world.
- To correct the document about 'EntityDirectionX/Y/Z()' functions OR to provide these functions with same posibilities than the 'EntityDirection()' (see below).
In the current PB version 6.11LTS we have a powerful function called 'EntityDirection()' , which allows us to give a 3D world vector to make an entity to point to. It just does what EntityLookAt() does, but in a different posibilities. There is also 'SetOrientation()' and 'FetchOrientation()', which can be used to orientate objects too, but these ones belong to the 'Engine3D' library and with the so called 'quaternions'.
Next tip uses all those ways to orientate in space and can be useful to take a look to understand how those functions work.
When dealing with objects orientation in a 3D world we need only two vectors to take in account as parameters:
(0) a global 3D vector to which co-lineate the object.
(1) the local vector of the object we want to co-lineate.
NOTICE all vectors for orientation purposes should be normalized, i.e.: Sqr(x*x + y*y + z*z) = 1.0
NOTICE and take in account that after 'CreateEntity()', 'CreateNode()', 'CreateCamera()', etc. ,
by default, the object vector orientation in the world is such as its local 'y' is co-lineated with the global (0,+1,0), and that's why by default,
the entity yaw axis is (0,+1,0); you can modify this axis everytime, with 'EntityFixedYawAxis()', so the object can be "yawed" around the given arbitration axis.
For the doc manual there should be interesting to complete it for the 'EntityDirectionX/Y/Z()' functions, because these ones have not the options 'EntityDirection()' has, which are:
The fact is that 'EntityDirectionX/Y/Z()' are forced its local to '#PB_Vector_Z', with no possibility to change it.#PB_Vector_X
#PB_Vector_Y
#PB_Vector_Z
#PB_Vector_NegativeX
#PB_Vector_NegativeY
#PB_Vector_NegativeZ
So, the manual should say:
Description
Get the 'x/y/z' direction of the entity referred to its local '#PB_Vector_Z'.
Code: Select all
InitEngine3D(#PB_Engine3D_NoLog,#PB_Compiler_Home+"Compilers\Engine3d.dll")
InitSprite():InitKeyboard():InitMouse()
OpenWindow(0,0,0,800,600,"v",#PB_Window_BorderLess|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,800,600,1,0,0,#PB_Screen_WaitSynchronization)
Add3DArchive(#PB_Compiler_Home+"Examples\3D\Data\fonts",#PB_3DArchive_FileSystem)
Parse3DScripts()
#el=0
CreateCamera(0,0,0,100,100)
CreateNode(0):AttachNodeObject(0,CameraID(0)):MoveNode(0,0,0,10,#PB_Absolute)
CreateIcoSphere(1,0.2)
CreateCone(0,1,2,4,1)
CreateMaterial(1,0,$28BBEF):SetMaterialColor(1,#PB_Material_DiffuseColor,$28BBEF)
CreateMaterial(0,0,$BB28EF):SetMaterialColor(0,#PB_Material_DiffuseColor,$BB28EF)
CreateEntity(1,MeshID(1),MaterialID(1),0,2,0)
CreateEntity(0,MeshID(0),MaterialID(0))
CreateText3D(0,"epale!","",1,$DDDDDDDD)
Text3DAlignment(0,#PB_Text3D_HorizontallyCentered|#PB_Text3D_Top)
ScaleText3D(0,0.3681,0.621,0.01,#PB_Relative)
AttachNodeObject(0,Text3DID(0))
MoveText3D(0,0,2,-10,#PB_Absolute|#PB_World)
CreateLight(0,$EEEEEE,4,4,2,#PB_Light_Point):SetLightColor(0,#PB_Light_DiffuseColor,$EEEEEE):MoveLight(0,4,4,2,#PB_Absolute)
Structure D3DXVECTOR3
x.f
y.f
z.f
EndStructure
Structure Vector3D Extends D3DXVECTOR3
m.f;<-length(modulo)
EndStructure
vector.Vector3D
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
Macro GetOrientacion(entidad)
; El vector 'fi->' señala el eje sobre el que se establece el ángulo 'fi\m', que 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->| )
entidad#\x=0.0:entidad#\y=1.0:entidad#\z=0.0:entidad#\m=1.0
fi#entidad#.Vector3D
FetchOrientation(EntityID(#entidad#),#PB_Absolute)
fi#entidad#\m=2*ACos(GetW())
If fi#entidad#\m
var.f=fi#entidad#\m/Sin(fi#entidad#\m/2)
fi#entidad#\x=GetX()*var:fi#entidad#\y=GetY()*var:fi#entidad#\z=GetZ()*var
Rotar_Vector3D_por_adicion_Angular(@fi#entidad#,@entidad#)
Else
fi#entidad#\x=0:fi#entidad#\y=0:fi#entidad#\z=0
EndIf
EndMacro
Macro SetOrientacion(entidad)
; El vector 'fi->' señala el eje sobre el que se establece el ángulo 'fi\m', que es el ángulo de inclinación de un objeto 3D con respecto a la 'y' global.
; El vector entrado como parámetro no es 'fi->', sino que 'fi->' es el ángulo formado por (0,1,0) y 'entidad->':
fi#entidad#.Vector3D
vector\x=0.0:vector\y=1.0:vector\z=0.0:vector\m=1.0
AnguloFormadoPor2Vectores(vector,entidad#,fi#entidad#)
; Las 4 variables que hay que entregar a la función 'SetOrientation()' son:
; X = fi\x*Sin(fi\m/2)/fi\m
; Y = fi\y*Sin(fi\m/2)/fi\m
; Z = fi\z*Sin(fi\m/2)/fi\m
; W = Cos(fi\m/2)
If fi#entidad#\m>1E-5
var.f=Sin(fi#entidad#\m/2)/fi#entidad#\m
Else
var.f=0.0
EndIf
SetOrientation(EntityID(#entidad#),fi#entidad#\x*var,fi#entidad#\y*var,fi#entidad#\z*var,Cos(fi#entidad#\m/2))
EndMacro
Macro ponermodo()
el\m=getmodulo(el):el\x/el\m:el\y/el\m:el\z/el\m
MoveEntity(1,2*el\x,2*el\y,2*el\z,#PB_World|#PB_Absolute)
mensaje$=""
Select modo.a
Case 1:EntityDirection(0,el\x,el\y,el\z,#PB_World,#PB_Vector_Y):mensaje$="modo EntityDirection"+#LFCR$
Case 2:EntityLookAt(0,el\x,el\y,el\z,0,1,0):mensaje$="modo EntityLookAt"+#LFCR$
Case 0:SetOrientacion(el):mensaje$="modo My SetOrientacion"+#LFCR$
EndSelect
GetOrientacion(el)
mensaje$+
"EntityDirectionX/Y/Z: "+StrF(EntityDirectionX(0),2)+","+StrF(EntityDirectionY(0),2)+","+StrF(EntityDirectionZ(0),2)+#LFCR$+
"My GetOrientacion: "+StrF(el\x,2)+","+StrF(el\y,2)+","+StrF(el\z,2)
Text3DCaption(0,mensaje$)
EndMacro
el.Vector3D
el\x=0:el\y=1:el\z=0:el\m=1
Repeat
Repeat:Eventodeventana.i=WindowEvent():Until Eventodeventana=0
ExamineKeyboard()
If KeyboardReleased(#PB_Key_F1):modo.a=1
ElseIf KeyboardReleased(#PB_Key_F2):modo.a=2
ElseIf KeyboardReleased(#PB_Key_F3):modo.a=0
ElseIf KeyboardReleased(#PB_Key_Up):el\y+0.1
ElseIf KeyboardReleased(#PB_Key_Down):el\y-0.1
ElseIf KeyboardReleased(#PB_Key_Left):el\x-0.1
ElseIf KeyboardReleased(#PB_Key_Right):el\x+0.1
ElseIf KeyboardReleased(#PB_Key_PageUp):el\z+0.1
ElseIf KeyboardReleased(#PB_Key_PageDown):el\z-0.1
EndIf
ponermodo()
RenderWorld()
FlipBuffers():Delay(16)
Until KeyboardPushed(#PB_Key_Escape)