Simple function to rotate 3D objects over given axis

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
Psychophanta
Addict
Addict
Posts: 4997
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Simple function to rotate 3D objects over given axis

Post by Psychophanta »

Current function RotateEntity(#Entity, x, y, z [, Mode]) does not accept an axis of the rotation, but 3 angle values: an angle in the 'x' axis, another in the 'y' axis and another in the 'z' axis.
Besides, those axis are not global (world axis), but local to de object.
The angle for de 'x' axis is in fact a vector wich defines an axis of rotation V(x,0,0), where x value is the angular amount to rotate in the pure 'x' axis.
The angle for de 'y' axis is in fact a vector wich defines an axis of rotation V(0,y,0), where y value is the angular amount to rotate in the pure 'y' axis.
The angle for de 'z' axis is in fact a vector wich defines an axis of rotation V(0,0,z), where z value is the angular amount to rotate in the pure 'z' axis.
Those are a pitch , yaw and roll, i.e., the so called Euler values.

EntityDirection() function does not establish a rotation axis for the object, but its 'x', 'y' and 'z' arguments are just the orientation axis for the object, same as LookAt function.

SetOrientation(ObjectID, x, y, z, w) function just the same, it stablish the axis for the orientation, but this one does it via a simple quaternion instead a simple vector.


Lets have defined a free global (world) vector V=(a,b,c).
There is not a native function to rotate it an angle of |V| and over the world axis defined by (a,b,c).

To perform professional and not professional tasks in an easy way i strongly request for a
Simple function which allows to just rotate 3D objects around a given arbitrary world axis.
The format of a function like that can be RotateByAxis(ObjectID, x, y, z [, Mode]), where (x,y,z) is the vector which defines the axis and direction of the angular rotation, and its modulo is the amount of degrees (or radians) to rotate.
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Simple function to rotate 3D objects over given axis

Post by djes »

I second Psychophanta in his demand, even if this feature is often lacking in common 3D tools.

Here's an old matrix code with rotation around a given axis that could give inspiration to the team. I did it because I haven't found such a code anywhere... Not optimised at all, it is a compilation of several matrix codes from different sources and some by me. Feel free to use it, but don't forget to link to this forum, thank you ;)

Code: Select all

;*************************************************************************************************************************************
;* By djes for PureBasic
;* Compilation of several matrix codes
;* from different sources and by myself
;* 18 oct 2006
;* Credits desired, or a link to the forum
;* https://www.purebasic.fr/english/viewtopic.php?f=3&t=72270
;* thank you ;)
;*
;* Note for french readers
;*  pitch : tangage
;*  yaw : cap
;*  roll : roulis
;*************************************************************************************************************************************

Structure matrix
	mat.f[9]
EndStructure

Structure vector
	x.f
	y.f
	z.f
EndStructure

;*************************************************************************************************************************************

Procedure matrix_by_matrix_multiply(*a.matrix, *b.matrix) ; / * Return To a * / 

  Define.matrix tmp

  For i.l = 0 To 2
    For j.l = 0 To 2
      tmp\mat[i + j*3] = *a\mat[i + 0*3] * *b\mat[0 + j*3] + *a\mat[i + 1*3] * *b\mat[1 + j*3] + *a\mat[i + 2*3] * *b\mat[2 + j*3]
    Next
  Next
  For i = 0 To 2
    For j = 0 To 2
      *a\mat[i + j*3] = tmp\mat[i + j*3];
    Next j
  Next i
; / * 3dica : 
;   ¦ a b c ¦   ¦ k l m ¦   ¦ ak + bn + cq al + bo + cr am + bp + cs ¦
;   ¦ d e f ¦ * ¦ n o p ¦ = ¦ dk + en + fq dl + eo + fr dm + ep + fs ¦
;   ¦ h i j ¦   ¦ q r s ¦   ¦ hk + in + jq hl + io + jr hm + ip + js ¦
;* / 
EndProcedure

;*************************************************************************************************************************************

Procedure matrix_copy(*a.matrix, *b.matrix) ; / * Return To a * / 

 For i = 0 To 8
  *a\mat[i] = *b\mat[i]
 Next i

EndProcedure

;*************************************************************************************************************************************

Procedure matrix_by_vector_multiply(*vekto.vector, *result.vector, *mat.matrix)

 vekx.f = *vekto\x
 veky.f = *vekto\y
 vekz.f = *vekto\z

 *result\x = *mat\mat[0] * vekx + *mat\mat[1] * veky + *mat\mat[2] * vekz
 *result\y = *mat\mat[3] * vekx + *mat\mat[4] * veky + *mat\mat[5] * vekz
 *result\z = *mat\mat[6] * vekx + *mat\mat[7] * veky + *mat\mat[8] * vekz

; / *
; 3dica : 
;                ¦ a b c 0 ¦
;   (Xi + Yj + Zk) * ¦ e f g 0 ¦ = (aX + eY + iZ + m)i + (bX + fY + jZ + n)j  + 
;                ¦ i j k 0 ¦   (cX + gY + kZ + o)k
;                ¦ m n o 1 ¦
;* / 
EndProcedure

Macro mac_matrix_by_vector_multiply(vekto, result, matrix)

 result\x = matrix\mat[0] * vekto\x + matrix\mat[1] * vekto\y + matrix\mat[2] * vekto\z
 result\y = matrix\mat[3] * vekto\x + matrix\mat[4] * vekto\y + matrix\mat[5] * vekto\z
 result\z = matrix\mat[6] * vekto\x + matrix\mat[7] * vekto\y + matrix\mat[8] * vekto\z

; / *
; 3dica : 
;                ¦ a b c 0 ¦
;   (Xi + Yj + Zk) * ¦ e f g 0 ¦ = (aX + eY + iZ + m)i + (bX + fY + jZ + n)j  + 
;                ¦ i j k 0 ¦   (cX + gY + kZ + o)k
;                ¦ m n o 1 ¦
;* / 
EndMacro

Procedure matrix_by_vector_multiply_and_perspective(*vekto.vector, *persp.vector, *mat.matrix,screen_dist.f,screen_ppd.f)

 vekx.f = *vekto\x
 veky.f = *vekto\y
 vekz.f = *vekto\z

 x.f = *mat\mat[0] * vekx + *mat\mat[1] * veky + *mat\mat[2] * vekz
 y.f = *mat\mat[3] * vekx + *mat\mat[4] * veky + *mat\mat[5] * vekz
 z.f = *mat\mat[6] * vekx + *mat\mat[7] * veky + *mat\mat[8] * vekz

	*persp\x = screen_x_center + (x*screen_dist) / (screen_ppd + z)
	*persp\y = screen_y_center + (y*screen_dist) / (screen_ppd + z)
;	*persp\x = (x*screen_dist) / (screen_ppd + z)
;	*persp\y = (y*screen_dist) / (screen_ppd + z)
; / *
; 3dica : 
;                ¦ a b c 0 ¦
;   (Xi + Yj + Zk) * ¦ e f g 0 ¦ = (aX + eY + iZ + m)i + (bX + fY + jZ + n)j  + 
;                ¦ i j k 0 ¦   (cX + gY + kZ + o)k
;                ¦ m n o 1 ¦
;* / 
EndProcedure

Macro mac_matrix_by_vector_multiply_and_perspective(vekto, persp, matrix)

	xf.f = matrix\mat[0] * vekto\x + matrix\mat[1] * vekto\y + matrix\mat[2] * vekto\z
	yf.f = matrix\mat[3] * vekto\x + matrix\mat[4] * vekto\y + matrix\mat[5] * vekto\z
	zf.f = matrix\mat[6] * vekto\x + matrix\mat[7] * vekto\y + matrix\mat[8] * vekto\z

	persp\x = screen_x_center + (xf*screen_dist) / (screen_ppd + zf)
	persp\y = screen_y_center + (yf*screen_dist) / (screen_ppd + zf)
	persp\z = zf
	
;	persp\x = (xf*d) / (d + ppd + zf)
;	persp\y = (yf*d) / (d + ppd + zf)

; / *
; 3dica : 
;                ¦ a b c 0 ¦
;   (Xi + Yj + Zk) * ¦ e f g 0 ¦ = (aX + eY + iZ + m)i + (bX + fY + jZ + n)j  + 
;                ¦ i j k 0 ¦   (cX + gY + kZ + o)k
;                ¦ m n o 1 ¦
;* / 
EndMacro

;*************************************************************************************************************************************

Procedure matrix_rotation(*m.matrix, pitch.f, yaw.f, roll.f)

 sx.f = Sin(pitch)
 sy.f = Sin(yaw)
 sz.f = Sin(roll)

 cx.f = Cos(pitch)
 cy.f = Cos(yaw)
 cz.f = Cos(roll)

 *m\mat[0 + 0*3] = cy * cz
 *m\mat[0 + 1*3] = cy * sz
 *m\mat[0 + 2*3] =  - sy

 *m\mat[1 + 0*3] = sx * sy * cz - cx * sz
 *m\mat[1 + 1*3] = sx * sy * sz + cx * cz
 *m\mat[1 + 2*3] = sx * cy

 *m\mat[2 + 0*3] = cx * sy * cz + sx * sz
 *m\mat[2 + 1*3] = cx * sy * sz - sx * cz
 *m\mat[2 + 2*3] = cx * cy

; / *3dica : 
;                     ¦ cy*cz          cy*sz           - sy    0 ¦
;                     ¦ sx*sy*cz - cx*sz sx*sy*sz + cx*cz  sx*cy 0 ¦
;       [X]*[Y]*[Z] = ¦ cx*sy*cz + sx*sz cx*sy*sz - sx*cz  cx*cy 0 ¦
;                     ¦ 0              0               0     1 ¦
;* / 
EndProcedure

;*************************************************************************************************************************************

Procedure matrix_rotation_around_axis(*m.matrix, *axis.vector, angle.f)

 nx.f = *axis\x
 ny.f = *axis\y
 nz.f = *axis\z

 ;normalize axis
 length.f = Sqr(nx*nx + ny*ny + nz*nz)

 ; / / too close to 0, can't make a normalized vector
 If (length < 0.000001) 
  length = 0.000001
 EndIf

 nx = nx / length
 ny = ny / length
 nz = nz / length

 sina.f = Sin(angle)
 cosa.f = Cos(angle)

 nx2.f = nx*nx
 ny2.f = ny*ny
 nz2.f = nz*nz
 nx3.f = nx*ny*(1 - cosa)
 ny3.f = ny*nz*(1 - cosa)
 nx5.f = nx*nz*(1 - cosa)
 nx4.f = nx*sina
 ny4.f = ny*sina
 nz2.f = nz*sina

 *m\mat[0] = nx2 + (1 - nx2) * cosa
 *m\mat[3] = nx3 + nz2
 *m\mat[6] = nx5 - ny4

 *m\mat[1] = nx3 - nz2
 *m\mat[4] = ny2 + (1 - ny2) * cosa
 *m\mat[7] = ny3 + nx4

 *m\mat[2] = nx5 + ny4
 *m\mat[5] = ny3 - nx4
 *m\mat[8] = nz2 + (1 - nz2) * cosa

; nx2.f = nx*nx
; ny2.f = ny*ny
; nz2.f = nz*nz

; *m\mat[0 + 0*3] = nx2 + (1 - nx2)*cosa
; *m\mat[0 + 1*3] = nx*ny*(1 - cosa) + nz*sina
; *m\mat[0 + 2*3] = nx*nz*(1 - cosa) - ny*sina

; *m\mat[1 + 0*3] = nx*ny*(1 - cosa) - nz*sina
; *m\mat[1 + 1*3] = ny2 + (1 - ny2)*cosa
; *m\mat[1 + 2*3] = ny*nz*(1 - cosa) + nx*sina

; *m\mat[2 + 0*3] = nx*nz*(1 - cosa) + ny*sina
; *m\mat[2 + 1*3] = ny*nz*(1 - cosa) - nx*sina
; *m\mat[2 + 2*3] = nz2 + (1 - nz2)*cosa

EndProcedure

;*************************************************************************************************************************************

Procedure matrix_identity(*m.matrix)

 *m\mat[0 + 0*3] = 1 : *m\mat[1 + 0*3] = 0 : *m\mat[2 + 0*3] = 0
 *m\mat[0 + 1*3] = 0 : *m\mat[1 + 1*3] = 1 : *m\mat[2 + 1*3] = 0
 *m\mat[0 + 2*3] = 0 : *m\mat[1 + 2*3] = 0 : *m\mat[2 + 2*3] = 1
 
; / * 3dica : 
;     ¦ 1 0 0 0 ¦
;     ¦ 0 1 0 0 ¦
;     ¦ 0 0 1 0 ¦
;     ¦ 0 0 0 1 ¦
;* / 
EndProcedure

;*************************************************************************************************************************************
;* => obj_rotation_matrix.

Procedure matrix_rotate_around_object_axis(*obj_rotation_matrix.matrix, pitch.f, yaw.f, roll.f)

 Protected axis_x.vector, axis_y.vector, axis_z.vector
 Protected axis_x_rotation_matrix.matrix, axis_y_rotation_matrix.matrix, axis_z_rotation_matrix.matrix

 ;rotation around x object axis
 axis_x\x = *obj_rotation_matrix\mat[0]
 axis_x\y = *obj_rotation_matrix\mat[3]
 axis_x\z = *obj_rotation_matrix\mat[6]
 matrix_rotation_around_axis(@axis_x_rotation_matrix, @axis_x, pitch)

 ;rotation around y object axis
 axis_y\x = *obj_rotation_matrix\mat[1]
 axis_y\y = *obj_rotation_matrix\mat[4]
 axis_y\z = *obj_rotation_matrix\mat[7]
 matrix_rotation_around_axis(@axis_y_rotation_matrix, @axis_y, yaw)

 ;rotation around z object axis
 axis_z\x = *obj_rotation_matrix\mat[2]
 axis_z\y = *obj_rotation_matrix\mat[5]
 axis_z\z = *obj_rotation_matrix\mat[8]
 matrix_rotation_around_axis(@axis_z_rotation_matrix, @axis_z, roll)

 matrix_by_matrix_multiply(@axis_x_rotation_matrix, @axis_y_rotation_matrix)
 matrix_by_matrix_multiply(@axis_x_rotation_matrix, @axis_z_rotation_matrix)
 matrix_by_matrix_multiply(*obj_rotation_matrix, @axis_x_rotation_matrix)
 
EndProcedure

;*************************************************************************************************************************************

Procedure vector_define(*vertex.vector, x, y, z)
 *vertex\x = x
 *vertex\y = y
 *vertex\z = z
EndProcedure

;*************************************************************************************************************************************

Procedure vectors_add(*vertex.vector, *vertex2add.vector)
 *vertex\x + *vertex2add\x
 *vertex\y + *vertex2add\y
 *vertex\z + *vertex2add\z
EndProcedure

;*************************************************************************************************************************************

Procedure vectors_sub(*vertex.vector, *vertex2sub.vector)
 *vertex\x - *vertex2sub\x
 *vertex\y - *vertex2sub\y
 *vertex\z - *vertex2sub\z
EndProcedure

;*************************************************************************************************************************************

Procedure vector_copy(*vertexsrc.vector, *vertexdest.vector)
 *vertexdest\x = *vertexsrc\x
 *vertexdest\y = *vertexsrc\y
 *vertexdest\z = *vertexsrc\z
EndProcedure

;*************************************************************************************************************************************

Procedure vector_rotate(*vertex.vector, *pivot.vector, pitch.f, yaw.f, roll.f)

 vectors_sub(*vertex, *pivot)

 If roll <> 0
     x.f = Cos(roll) * *vertex\x - Sin(roll) * *vertex\z
     *vertex\z = Sin(roll) * *vertex\x + Cos(roll) * *vertex\z
     *vertex\x = x
 EndIf

 If pitch <> 0
     y.f = Cos(pitch) * *vertex\y - Sin(pitch) * *vertex\z
     *vertex\z = Sin(pitch) * *vertex\y + Cos(pitch) * *vertex\z
     *vertex\y = y
 EndIf

 If yaw <> 0
     x.f = Cos(yaw) * *vertex\x - Sin(yaw) * *vertex\y
     *vertex\y = Sin(yaw) * *vertex\x + Cos(yaw) * *vertex\y
     *vertex\x = x
 EndIf

 vectors_add(*vertex, *pivot)

EndProcedure

;*************************************************************************************************************************************

Procedure vector_rotate2(*vertex.vector, *pivot.vector, pitch.f, yaw.f, roll.f)

  cr.f = Cos(pitch)
  sr.f = Sin(pitch)
  cp.f = Cos(roll)
  sp.f = Sin(roll)
  cy.f = Cos(yaw)
  sy.f = Sin(yaw)

  Dim m.f(12)
  m(0) = (cp*cy)
  m(1) = (cp*sy)
  m(2) = ( - sp)

  srsp.f = sr*sp
  crsp.f = cr*sp

  m(4) = (srsp*cy - cr*sy)
  m(5) = (srsp*sy + cr*cy)
  m(6) = (sr*cp);

  m(8) = (crsp*cy + sr*sy)
  m(9) = (crsp*sy - sr*cy)
  m(10) = (cr*cp);

  tmpx.f = *vertex\x
  tmpy.f = *vertex\y
  tmpz.f = *vertex\z

  *vertex\x = tmpx*m(0) + tmpy*m(1) + tmpz*m(2)
  *vertex\y = tmpx*m(4) + tmpy*m(5) + tmpz*m(6)
  *vertex\z = tmpx*m(8) + tmpy*m(9) + tmpz*m(10)

EndProcedure
User avatar
Comtois
Addict
Addict
Posts: 1429
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Re: Simple function to rotate 3D objects over given axis

Post by Comtois »

Not sure what you mean, but try this

Code: Select all

   EntityFixedYawAxis(0, #True, axis\x, axis\y, axis\z)
   RotateEntity(0, 0, 1, 0, #PB_Relative) 
Please correct my english
http://purebasic.developpez.com/
User avatar
Psychophanta
Addict
Addict
Posts: 4997
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Re: Simple function to rotate 3D objects over given axis

Post by Psychophanta »

It seems not to do with the explained issue.
Really I suspect the requested function is not hard using the correct way with quaternions.

However, i must say that quaternions DO NOT use less computing resources than matrix, as is written in some texts.
And also some texts say that matrix also lacks about the known problem of "gimbal lock", but that is absolutely incorrect; "gimbal lock" problem is only for the use of Euler angles, i.e. Pitch, Yaw and Roll.
And moreover: quaternions use for 3D engines lacks when dealing with multi-turn rotations, which matrix do not.
Hopefully, not all academic texts about 3D engines, and robotics, talks nice about quaternions in front of homogeneous matrix.
In my own observations, I have founded suspects that there is nor matrix neither quaternions the ideal or optimal way to manage rotations. But nowadays is the tool used everywhere.

Well, time ago I wrote a tip to show it, using the MP3D lib:

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
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
Structure D3DMATRIX
  StructureUnion
    _11.f
    Xi.f
  EndStructureUnion
  StructureUnion
    _12.f
    Xj.f
  EndStructureUnion
  StructureUnion
    _13.f
    Xk.f
  EndStructureUnion
  _14.f
  StructureUnion
    _21.f
    Yi.f
  EndStructureUnion
  StructureUnion
    _22.f
    Yj.f
  EndStructureUnion
  StructureUnion
    _23.f
    Yk.f
  EndStructureUnion
  _24.f
  StructureUnion
    _31.f
    Zi.f
  EndStructureUnion
  StructureUnion
    _32.f
    Zj.f
  EndStructureUnion
  StructureUnion
    _33.f
    Zk.f
  EndStructureUnion
  _34.f
  StructureUnion
    _41.f
    Pi.f
  EndStructureUnion
  StructureUnion
    _42.f
    Pj.f
  EndStructureUnion
  StructureUnion
    _43.f
    Pk.f
  EndStructureUnion
  _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,*o.D3DMATRIX); producto
  *o\_11=*a\_11**b\_11+*a\_12**b\_21+*a\_13**b\_31:*o\_12=*a\_11**b\_12+*a\_12**b\_22+*a\_13**b\_32:*o\_13=*a\_11**b\_13+*a\_12**b\_23+*a\_13**b\_33
  *o\_21=*a\_21**b\_11+*a\_22**b\_21+*a\_23**b\_31:*o\_22=*a\_21**b\_12+*a\_22**b\_22+*a\_23**b\_32:*o\_23=*a\_21**b\_13+*a\_22**b\_23+*a\_23**b\_33
  *o\_31=*a\_31**b\_11+*a\_32**b\_21+*a\_33**b\_31:*o\_32=*a\_31**b\_12+*a\_32**b\_22+*a\_33**b\_32:*o\_33=*a\_31**b\_13+*a\_32**b\_23+*a\_33**b\_33
  ProcedureReturn *o
EndProcedure
Procedure.i Matriz4x4xMatriz4x4(*a.D3DMATRIX,*b.D3DMATRIX,*o.D3DMATRIX); producto
  *o\_11=*a\_11**b\_11+*a\_12**b\_21+*a\_13**b\_31+*a\_14**b\_41:*o\_12=*a\_11**b\_12+*a\_12**b\_22+*a\_13**b\_32+*a\_14**b\_42:*o\_13=*a\_11**b\_13+*a\_12**b\_23+*a\_13**b\_33+*a\_14**b\_43:*o\_14=*a\_11**b\_14+*a\_12**b\_24+*a\_13**b\_34+*a\_14**b\_44
  *o\_21=*a\_21**b\_11+*a\_22**b\_21+*a\_23**b\_31+*a\_24**b\_41:*o\_22=*a\_21**b\_12+*a\_22**b\_22+*a\_23**b\_32+*a\_24**b\_42:*o\_23=*a\_21**b\_13+*a\_22**b\_23+*a\_23**b\_33+*a\_24**b\_43:*o\_24=*a\_21**b\_14+*a\_22**b\_24+*a\_23**b\_34+*a\_24**b\_44
  *o\_31=*a\_31**b\_11+*a\_32**b\_21+*a\_33**b\_31+*a\_34**b\_41:*o\_32=*a\_31**b\_12+*a\_32**b\_22+*a\_33**b\_32+*a\_34**b\_42:*o\_33=*a\_31**b\_13+*a\_32**b\_23+*a\_33**b\_33+*a\_34**b\_43:*o\_34=*a\_31**b\_14+*a\_32**b\_24+*a\_33**b\_34+*a\_34**b\_44
  *o\_41=*a\_41**b\_11+*a\_42**b\_21+*a\_43**b\_31+*a\_44**b\_41:*o\_42=*a\_41**b\_12+*a\_42**b\_22+*a\_43**b\_32+*a\_44**b\_42:*o\_43=*a\_41**b\_13+*a\_42**b\_23+*a\_43**b\_33+*a\_44**b\_43:*o\_44=*a\_41**b\_14+*a\_42**b\_24+*a\_43**b\_34+*a\_44**b\_44
  ProcedureReturn *o
EndProcedure
Procedure.i flecha(x.f=1,y.f=0,z.f=0,color.l=$EE3333,lados.a=8)
  Protected mod.f=Sqr(x*x+y*y+z*z)
  If mod>0.0001
    Protected 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-mod/20)
    MP_TranslateMesh(cil,0,0,(mod-mod/20)/2)
    mod*7/8
    MP_RotateMesh(cono,180,0,180)
    MP_ResizeMesh(cono,mod/20,mod/20,mod/10)
    MP_TranslateMesh(cono,0,0,mod+mod/10)
    MP_AddMesh(cono,cil):MP_FreeEntity(cono)
    MP_EntityLookAt(cil,x+0.000001,y,z,0,0)
    MP_EntitySetTexture(cil,ciltexture,0,0)
    ProcedureReturn cil
  EndIf
  ProcedureReturn 0
EndProcedure
Procedure.i BaseSistemaCoordenadas(size.f=1,lados.a=8,color.l=$22AADD)
  Protected cil.i=MP_CreateCylinder(lados,size),cono.i=MP_CreateCone(lados,size/8),cil2.i
  MP_ResizeMesh(cil,size/80,size/80,size-size/20)
  MP_TranslateMesh(cil,0,0,(size-size/20)/2)
  size*7/8
  MP_RotateMesh(cono,180,0,180)
  MP_ResizeMesh(cono,size/20,size/20,size/10)
  MP_TranslateMesh(cono,0,0,size+size/10)
  MP_AddMesh(cono,cil):MP_FreeEntity(cono)
  cil2.i=MP_CopyEntity(cil)
  MP_RotateMesh(cil2,-90,0,0)
  MP_AddMesh(cil2,cil):MP_FreeEntity(cil2)
  cil2.i=MP_CopyEntity(cil)
  MP_RotateMesh(cil2,0,90,0)
  MP_AddMesh(cil2,cil):MP_FreeEntity(cil2)
  MP_EntitySetTexture(cil,MP_CreateTextureColor(8,8,color),0,0)
  ProcedureReturn cil
EndProcedure
Procedure.i BaseSistemaCoordenadas0(px.f=0,py.f=0,pz.f=0,size.f=1,lados.a=8,colorx.l=$DD3333,colory.l=$99DD99,colorz.l=$2299DD)
  Protected vx.i=flecha(size,0,0,colorx,lados)
  Protected vy.i=flecha(0,size,0,colory,lados)
  Protected vz.i=flecha(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)
  MP_PositionEntity(vy,px,py,pz)
  ProcedureReturn vy.i
EndProcedure
Procedure.i Turn_Body_by_Angle_adding(Body.i,*fi.Vector3D,*matriz.D3DMATRIX=0,vx.f=0,vy.f=0,vz.f=0); <- usar esta cuando no disponemos del módulo angular de antemano (antes de llamar a la función), sino solo del propio vector ángulo
  ;Rotar una entity (una matriz) un ángulo dado '*fi.Vector3D':
  Protected rot.D3DMATRIX,rot1.D3DMATRIX,cos.f,sen.f,coss.f,*u.Vector3D
  *fi\m=getmodulo(*fi)
  If *fi\m
    *u.Vector3D=AllocateMemory(SizeOf(Vector3D)):CopyMemory(*fi,*u,SizeOf(Vector3D))
    *u\x/*u\m:*u\y/*u\m:*u\z/*u\m; <- obtener vector unidad (llamado "vector normalizado")
    If *matriz=0
      *matriz=MP_EntityGetMatrix(Body)
    EndIf
    cos=Cos(*u\m):sen=Sin(*u\m):coss=1.0-cos
    ;Matriz de Rotación de un ángulo dado 'A' alrededor de un eje dado definido por el vector unidad (*u\x,*u\y,*u\z)
    rot1\Xi=cos+*u\x**u\x*coss:rot1\Xj=*u\x**u\y*coss-*u\z*sen:rot1\Xk=*u\x**u\z*coss+*u\y*sen
    rot1\Yi=*u\y**u\x*coss+*u\z*sen:rot1\Yj=cos+*u\y**u\y*coss:rot1\Yk=*u\y**u\z*coss-*u\x*sen
    rot1\Zi=*u\z**u\x*coss-*u\y*sen:rot1\Zj=*u\z**u\y*coss+*u\x*sen:rot1\Zk=cos+*u\z**u\z*coss
    CopyMemory(*matriz,@rot,SizeOf(D3DMATRIX))
    rot\_41+vx:rot\_42+vy:rot\_43+vz
    MP_EntitySetMatrix(Body,Matriz3x3xMatriz3x3(*matriz,@rot1,@rot)); <- se multiplica la matriz de inclinación del entity por la matriz rotación y se obtiene la matriz original rotada
    FreeMemory(*u)
    ProcedureReturn @rot
  EndIf
  ProcedureReturn 0
EndProcedure
Procedure.i MatrizRotacionaldeunAngulodadoalrededordeunejedefinidoporunvectorunidad(Body.i,*u.Vector3D,A.f,*matriz.D3DMATRIX=0,vx.f=0,vy.f=0,vz.f=0); <- usar esta cuando disponemos de antemano (antes de llamar a la función) del módulo angular y del vector unitario del ángulo
  ;Rotar un entity un ángulo dado cuya dirección viene dada por el vector unidad '*u.Vector3D' y además por un módulo 'A'
  Protected rot.D3DMATRIX,rot1.D3DMATRIX,cos.f,sen.f,coss.f
  If A
    If *matriz=0
      *matriz=MP_EntityGetMatrix(Body)
    EndIf
    cos=Cos(A):sen=Sin(A):coss=1.0-cos
    ;Matriz de Rotación de un ángulo dado 'A' alrededor de un eje dado definido por el vector unidad (*u\x,*u\y,*u\z)
    rot1\Xi=cos+*u\x**u\x*coss:rot1\Xj=*u\x**u\y*coss-*u\z*sen:rot1\Xk=*u\x**u\z*coss+*u\y*sen
    rot1\Yi=*u\y**u\x*coss+*u\z*sen:rot1\Yj=cos+*u\y**u\y*coss:rot1\Yk=*u\y**u\z*coss-*u\x*sen
    rot1\Zi=*u\z**u\x*coss-*u\y*sen:rot1\Zj=*u\z**u\y*coss+*u\x*sen:rot1\Zk=cos+*u\z**u\z*coss
    CopyMemory(*matriz,@rot,SizeOf(D3DMATRIX))
    rot\_41+vx:rot\_42+vy:rot\_43+vz
    MP_EntitySetMatrix(Body,Matriz3x3xMatriz3x3(*matriz,@rot1,@rot)); <- se multiplica la matriz de inclinación del entity por la matriz rotación y se obtiene la matriz original rotada
    ProcedureReturn @rot
  EndIf
  ProcedureReturn 0
EndProcedure
; Object0.i=MP_CreateSkySphere(20)
; Object0.i=BaseSistemaCoordenadas()
; Object0.i=MP_CreateSphere(20)
Object0.i=MP_CreateCube()
MP_EntitySetTexture(Object0,MP_ImageToTexture(0),0,0)
baseglobal.i=BaseSistemaCoordenadas():MP_PositionEntity(baseglobal,-2,0.5,0)
*rot.D3DMATRIX=MP_EntityGetMatrix(pivotcam)
rot.D3DMATRIX
rot1.D3DMATRIX
rotx.D3DMATRIX
roty.D3DMATRIX
rotz.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
  mdz.f=MP_MouseDeltaWheel()/400
  If MP_KeyDown(#PB_Key_Up):mdy.f=-0.01
  ElseIf MP_KeyDown(#PB_Key_Down):mdy.f=0.01
  ElseIf MP_KeyDown(#PB_Key_Left):mdx.f=-0.01
  ElseIf MP_KeyDown(#PB_Key_Right):mdx.f=0.01
  Else
    mdx.f=MP_MouseDeltaX()/200:mdy.f=MP_MouseDeltaY()/200
  EndIf
  If MP_KeyDown(#PB_Key_LeftControl) Or MP_MouseButtonDown(1); <- mover el punto de vista
    MP_TurnEntity(pivotcam,mdy.f*60,mdx.f*60,0,0)
    If mdz.f
      MP_EntitySetZ(maincam,MP_EntityGetZ(maincam)+mdz); <- MP_MoveEntity(cam,0,0,mdz)
    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
    ;matriz de rotación sobre eje z del mundo:
    rotz\_11=Cos(mdz):rotz\_12=0:rotz\_13=Sin(mdz):rotz\_14=0
    rotz\_21=0:rotz\_22=1:rotz\_23=0:rotz\_24=0
    rotz\_31=-Sin(mdz):rotz\_32=0:rotz\_33=Cos(mdz):rotz\_34=0
    rotz\_41=0:rotz\_42=0:rotz\_43=0:rotz\_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.f*mdx.f+mdy.f*mdy.f+mdz.f*mdz.f)
    If THETA.d>0
      ux_m.d=Sqr(*rot\_11**rot\_11+*rot\_12**rot\_12+*rot\_13**rot\_13)
      If ux_m.d>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 Y pero en el plano frontal del ojo:
        uy_x*mdx:uy_y*mdx:uy_z*mdx
      EndIf
      ;Hacemos lo mismo para obtener la componente Z del movimiento del ratón pero en el plano frontal del ojo
      uz_m.d=Sqr(*rot\_31**rot\_31+*rot\_32**rot\_32+*rot\_33**rot\_33)
      If uz_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
        uz_x.d=*rot\_31/uz_m:uz_y.d=*rot\_32/uz_m:uz_z.d=*rot\_33/uz_m; <- son los cosenos directores. 
        ;ahora multiplicando este vector unitario, por el modulo de (0,0,mdz) obtenemos ya la componente Z pero en el plano frontal del ojo:
        uz_x*mdz:uz_y*mdz:uz_z*mdz
      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+uz_x.d:u\y=ux_y.d+uy_y.d+uz_y.d:u\z=ux_z.d+uy_z.d+uz_z.d
      If MP_KeyDown(#PB_Key_LeftShift)=0; <- METODO MIO
        Turn_Body_by_Angle_adding(Object0.i,@u.Vector3D,0,0.0,0.0,0.0)
      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(Object0.i,@u.Vector3D,THETA,0,0.0,0.0,0.0)
      EndIf
    EndIf
  EndIf
  MP_RenderWorld()
  MP_Flip():Delay(8)
Wend
If you do not have that lib installed then this is the compiled executeable an should work for you there, it is a normal windows 32bit executeable.
Moving the mouse can rotate the object. With left CTRL + mouse moving orbitates the eye over the object.
The program is able to perform the object rotation ALWAYS over the eye view plane, this is, with the rotation axis contained inside de front view plane.
https://mega.nz/#!QpgSVKDB!HNlntXQCuwNF ... cjAwvEzlhE

In that code, i just replaced conversion functions (quaternion--->rotation matrix) and viceversa, in order it works in the native PB.
Result:
No success.
Previous MP3D code converted to PB native code. Here can see the used functions conversions for quaternion--->rotation matrix and viceversa:

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
;/ inits
Global pantallacompleta.b=0,Titulo$="Par secundario en los cuerpos celestes"
Select MessageRequester("Pantalla para graficos 3D:","¿Usar pantalla completa?",#PB_MessageRequester_YesNoCancel)
Case #PB_MessageRequester_Yes:pantallacompleta.b=1
Case #PB_MessageRequester_Cancel:End
EndSelect
inicio:
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 pantallacompleta
  RX=FRX:RY=FRY
Else
  If FRX<1280 Or FRY<720:RX=FRX*2/3:RY=FRY*2/3:Else:RX=1280:RY=720:EndIf
EndIf
If InitEngine3D()=0
  MessageRequester("Error","The 3D Engine can't be initialized",0):End
EndIf
;AntialiasingMode(#PB_AntialiasingMode_None)
;AntialiasingMode(#PB_AntialiasingMode_x2)
AntialiasingMode(#PB_AntialiasingMode_x4)
;AntialiasingMode(#PB_AntialiasingMode_x6)
;
InitSprite():InitKeyboard():InitMouse()
If pantallacompleta.b=2
  OpenScreen(RX,RY,bitplanes.a,Titulo$,#PB_Screen_WaitSynchronization,FrecuenciadeMuestreo.u)
Else
  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)
EndIf
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Textures",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/fonts",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Models",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Packs/desert.zip",#PB_3DArchive_Zip)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/Packs/skybox.zip",#PB_3DArchive_Zip)
Add3DArchive(#PB_Compiler_Home+"examples/3D/Data/GUI",#PB_3DArchive_FileSystem)
Add3DArchive("media/",#PB_3DArchive_FileSystem)
Add3DArchive("media/cielo1.zip",#PB_3DArchive_Zip)
Add3DArchive("media/cielo2.zip",#PB_3DArchive_Zip)
Add3DArchive("media/cielo3.zip",#PB_3DArchive_Zip)
Add3DArchive("media/cielo4.zip",#PB_3DArchive_Zip)
Parse3DScripts()
; Lo que sigue es una plantilla de los elementos de un mundo 3D que ofrecen las bibliotecas nativas el PureBasic:
Enumeration; Camaras
  #Camara
EndEnumeration
Enumeration; Luces
  #Luz
EndEnumeration
Enumeration; Texturas
  #Textura
EndEnumeration
Enumeration; Materiales
  #Material
EndEnumeration
Enumeration; Mallas
  #Object0malla
EndEnumeration
Enumeration; Entidades
  #Object0
EndEnumeration
Enumeration; Nodos
  #Nodo
  #Pivotcam
EndEnumeration
Global ventanaprincipalx.l=10,ventanaprincipaly.l=10,ventanaprincipalw.l=RX/2.5,ventanaprincipalh.l=RY/2
;\

CreateLight(#luz,$EEEEEE,4,4,2,#PB_Light_Point)
CreateCamera(#Camara,0,0,100,100):CreateNode(#Pivotcam,0,0,0):AttachNodeObject(#Pivotcam,CameraID(#Camara)):CameraRange(#Camara,0.1,10000):CameraBackColor(#Camara,$181911)
MoveCamera(#Camara,0,0,3,#PB_Absolute)

Structure D3DMATRIX
  StructureUnion
    _11.f
    Xi.f
  EndStructureUnion
  StructureUnion
    _12.f
    Xj.f
  EndStructureUnion
  StructureUnion
    _13.f
    Xk.f
  EndStructureUnion
  _14.f
  StructureUnion
    _21.f
    Yi.f
  EndStructureUnion
  StructureUnion
    _22.f
    Yj.f
  EndStructureUnion
  StructureUnion
    _23.f
    Yk.f
  EndStructureUnion
  _24.f
  StructureUnion
    _31.f
    Zi.f
  EndStructureUnion
  StructureUnion
    _32.f
    Zj.f
  EndStructureUnion
  StructureUnion
    _33.f
    Zk.f
  EndStructureUnion
  _34.f
  StructureUnion
    _41.f
    Pi.f
  EndStructureUnion
  StructureUnion
    _42.f
    Pj.f
  EndStructureUnion
  StructureUnion
    _43.f
    Pk.f
  EndStructureUnion
  _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 EntityGetMatrixFromQuaternion(objeto.i,*matriz.D3DMATRIX,modo.i=#PB_Absolute)
  FetchOrientation(objeto,modo):Protected x.f=GetX(),y.f=GetY(),z.f=GetZ(),w.f=GetW(),s.f=2.0/(x*x+y*y+z*z+w*w)
  *matriz\Xi=1-s*(y*y+z*z); <- 0,0
  *matriz\Xj=s*(x*y-z*w); <- 0,1
  *matriz\Xk=s*(x*z+y*w); <- 0,2
  *matriz\Yi=s*(x*y+z*w); <- 1,0
  *matriz\Yj=1-s*(x*x+z*z); <- 1,1
  *matriz\Yk=s*(y*z-x*w); <- 1,2
  *matriz\Zi=s*(x*z-y*w); <- 2,0
  *matriz\Zj=s*(y*z+x*w); <- 2,1
  *matriz\Zk=1-s*(x*x+y*y); <- 2,2
  ProcedureReturn *matriz
EndProcedure
Procedure EntityGetQuaternionFromMatrix1(objeto.i,*matriz.D3DMATRIX)
  Protected x.f,y.f,z.f,w.f
  w=Sqr(*matriz\Xi+*matriz\Yj+*matriz\Zk+1)/2
  x=Sign(*matriz\Zj-*matriz\Yk)*Sqr(*matriz\Xi-*matriz\Yj-*matriz\Zk+1)/2
  y=Sign(*matriz\Xk-*matriz\Zi)*Sqr(*matriz\Yj-*matriz\Xi-*matriz\Zk+1)/2
  z=Sign(*matriz\Yi-*matriz\Xj)*Sqr(*matriz\Zk-*matriz\Xi-*matriz\Yj+1)/2
  SetOrientation(objeto,x,y,z,w)
EndProcedure
Procedure EntityGetQuaternionFromMatrix(objeto.i,*matriz.D3DMATRIX)
  Protected x.f,y.f,z.f,w.f,tr.f=*matriz\Xi+*matriz\Yj+*matriz\Zk,S.f
  If tr>0
    S=Sqr(tr+1)*2; S=4*w
    w=S/4
    x=(*matriz\Zj-*matriz\Yk)/S
    y=(*matriz\Xk-*matriz\Zi)/S
    z=(*matriz\Yi-*matriz\Xj)/S
  ElseIf *matriz\Xi>*matriz\Yj And *matriz\Xi>*matriz\Zk
    S=Sqr(1+*matriz\Xi-*matriz\Yj-*matriz\Zk)*2; S=4*x
    w=(*matriz\Zj-*matriz\Yk)/S
    x=S/4
    y=(*matriz\Xj+*matriz\Yi)/S
    z=(*matriz\Xk+*matriz\Zi)/S
  ElseIf *matriz\Yj>*matriz\Zk
    S=Sqr(1+*matriz\Yj-*matriz\Xi-*matriz\Zk)*2; S=4*y
    w=(*matriz\Xk-*matriz\Zi)/S
    x=(*matriz\Xj+*matriz\Yi)/S
    y=S/4
    z=(*matriz\Yk+*matriz\Zj)/S
  Else
    S=Sqr(1+*matriz\Zk-*matriz\Xi-*matriz\Yj)*2; S=4*z
    w=(*matriz\Yi-*matriz\Xj)/S
    x=(*matriz\Xk+*matriz\Zi)/S
    y=(*matriz\Yk+*matriz\Zj)/S
    z=S/4
  EndIf
  SetOrientation(objeto,x,y,z,w)
EndProcedure
Procedure.i Matriz3x3xMatriz3x3(*a.D3DMATRIX,*b.D3DMATRIX,*o.D3DMATRIX); producto
  *o\_11=*a\_11**b\_11+*a\_12**b\_21+*a\_13**b\_31:*o\_12=*a\_11**b\_12+*a\_12**b\_22+*a\_13**b\_32:*o\_13=*a\_11**b\_13+*a\_12**b\_23+*a\_13**b\_33
  *o\_21=*a\_21**b\_11+*a\_22**b\_21+*a\_23**b\_31:*o\_22=*a\_21**b\_12+*a\_22**b\_22+*a\_23**b\_32:*o\_23=*a\_21**b\_13+*a\_22**b\_23+*a\_23**b\_33
  *o\_31=*a\_31**b\_11+*a\_32**b\_21+*a\_33**b\_31:*o\_32=*a\_31**b\_12+*a\_32**b\_22+*a\_33**b\_32:*o\_33=*a\_31**b\_13+*a\_32**b\_23+*a\_33**b\_33
  ProcedureReturn *o
EndProcedure
Procedure.i Matriz4x4xMatriz4x4(*a.D3DMATRIX,*b.D3DMATRIX,*o.D3DMATRIX); producto
  *o\_11=*a\_11**b\_11+*a\_12**b\_21+*a\_13**b\_31+*a\_14**b\_41:*o\_12=*a\_11**b\_12+*a\_12**b\_22+*a\_13**b\_32+*a\_14**b\_42:*o\_13=*a\_11**b\_13+*a\_12**b\_23+*a\_13**b\_33+*a\_14**b\_43:*o\_14=*a\_11**b\_14+*a\_12**b\_24+*a\_13**b\_34+*a\_14**b\_44
  *o\_21=*a\_21**b\_11+*a\_22**b\_21+*a\_23**b\_31+*a\_24**b\_41:*o\_22=*a\_21**b\_12+*a\_22**b\_22+*a\_23**b\_32+*a\_24**b\_42:*o\_23=*a\_21**b\_13+*a\_22**b\_23+*a\_23**b\_33+*a\_24**b\_43:*o\_24=*a\_21**b\_14+*a\_22**b\_24+*a\_23**b\_34+*a\_24**b\_44
  *o\_31=*a\_31**b\_11+*a\_32**b\_21+*a\_33**b\_31+*a\_34**b\_41:*o\_32=*a\_31**b\_12+*a\_32**b\_22+*a\_33**b\_32+*a\_34**b\_42:*o\_33=*a\_31**b\_13+*a\_32**b\_23+*a\_33**b\_33+*a\_34**b\_43:*o\_34=*a\_31**b\_14+*a\_32**b\_24+*a\_33**b\_34+*a\_34**b\_44
  *o\_41=*a\_41**b\_11+*a\_42**b\_21+*a\_43**b\_31+*a\_44**b\_41:*o\_42=*a\_41**b\_12+*a\_42**b\_22+*a\_43**b\_32+*a\_44**b\_42:*o\_43=*a\_41**b\_13+*a\_42**b\_23+*a\_43**b\_33+*a\_44**b\_43:*o\_44=*a\_41**b\_14+*a\_42**b\_24+*a\_43**b\_34+*a\_44**b\_44
  ProcedureReturn *o
EndProcedure
Procedure.i MatrizRotacionaldeunAngulodadoalrededordeunejedefinidoporunvectorunidad(Body.i,*u.Vector3D,A.f,*matriz.D3DMATRIX); <- usar esta cuando disponemos de antemano (antes de llamar a la función) del módulo angular y del vector unitario del ángulo
  ;Rotar un entity un ángulo dado cuya dirección viene dada por el vector unidad '*u.Vector3D' y además por un módulo 'A'
  Protected rot.D3DMATRIX,rot1.D3DMATRIX,cos.f,sen.f,coss.f
  If A
    cos=Cos(A):sen=Sin(A):coss=1.0-cos
    ;Matriz de Rotación de un ángulo dado 'A' alrededor de un eje dado definido por el vector unidad (*u\x,*u\y,*u\z)
    rot1\Xi=cos+*u\x**u\x*coss:rot1\Xj=*u\x**u\y*coss-*u\z*sen:rot1\Xk=*u\x**u\z*coss+*u\y*sen
    rot1\Yi=*u\y**u\x*coss+*u\z*sen:rot1\Yj=cos+*u\y**u\y*coss:rot1\Yk=*u\y**u\z*coss-*u\x*sen
    rot1\Zi=*u\z**u\x*coss-*u\y*sen:rot1\Zj=*u\z**u\y*coss+*u\x*sen:rot1\Zk=cos+*u\z**u\z*coss
    CopyMemory(*matriz,@rot,SizeOf(D3DMATRIX))
    EntityGetQuaternionFromMatrix(Body,Matriz3x3xMatriz3x3(*matriz,@rot1,@rot)); <- se multiplica la matriz de inclinación del entity por la matriz rotación y se obtiene la matriz original rotada
    ProcedureReturn @rot
  EndIf
  ProcedureReturn 0
EndProcedure
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
CreateCube(#Object0malla,1)
LoadTexture(#textura,"soil_wall.jpg")
CreateMaterial(#material,TextureID(#textura))
CreateEntity(#Object0,MeshID(#Object0malla),MaterialID(#material),0,0,0)
; BaseSistemaCoordenadas(#baseglobal):MoveEntity(#baseglobal,-2,0.5,0,#PB_Absolute)
matrizpivot.D3DMATRIX
EntityGetMatrixFromQuaternion(NodeID(#pivotcam),@matrizpivot)
matrizobjeto.D3DMATRIX
EntityGetMatrixFromQuaternion(EntityID(#Object0),@matrizobjeto)
rot.D3DMATRIX
rot1.D3DMATRIX
rotx.D3DMATRIX
roty.D3DMATRIX
rotz.D3DMATRIX
Macro TeclaControldecamara(tecla=LeftControl)
  If KeyEdgeDetection(#PB_Key_#tecla#); <- inicia control camara
    pasocam.f=0.001:pasocamincr.f=0.0001
  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(#Pivotcam,mdx,-mdy,0,#PB_Local); o MoveCamera(0,mdx,-mdy,0,#PB_Local) o MoveCamera(0,mdx,-mdy,0,#PB_Relative)
      Else
        RotateNode(#Pivotcam,-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(#Pivotcam,0,-0.5,0,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_Pad7)
      RotateNode(#Pivotcam,0,0.5,0,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_Pad3) Or lmb.b
      RotateNode(#Pivotcam,0,0,-0.5,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_Pad9) Or rmb.b
      RotateNode(#Pivotcam,0,0,0.5,#PB_Relative)
    EndIf
EndMacro
Repeat
  ExamineMouse():ExamineKeyboard()
  WaitWindowEvent()
  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
  If KeyboardPushed(#PB_Key_Up):mdy.f=-0.01
  ElseIf KeyboardPushed(#PB_Key_Down):mdy.f=0.01
  ElseIf KeyboardPushed(#PB_Key_Left):mdx.f=-0.01
  ElseIf KeyboardPushed(#PB_Key_Right):mdx.f=0.01
  EndIf
  TeclaControldecamara(LeftControl)
  ElseIf KeyboardPushed(#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
    ;matriz de rotación sobre eje z del mundo:
    rotz\_11=Cos(mdz):rotz\_12=0:rotz\_13=Sin(mdz):rotz\_14=0
    rotz\_21=0:rotz\_22=1:rotz\_23=0:rotz\_24=0
    rotz\_31=-Sin(mdz):rotz\_32=0:rotz\_33=Cos(mdz):rotz\_34=0
    rotz\_41=0:rotz\_42=0:rotz\_43=0:rotz\_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)
    EntityGetQuaternionFromMatrix(EntityID(#Object0),Matriz4x4xMatriz4x4(EntityGetMatrixFromQuaternion(EntityID(#Object0),@matrizobjeto),@rot1,@rot))
  Else; <- rotar el objeto sobre eje 'x' y 'y' relativo al ojo.
    EntityGetMatrixFromQuaternion(NodeID(#pivotcam),@matrizpivot)
    ;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 matrizpivot la dirección del eje X, a través del vector X-> del plano frontal del ojo ( matrizpivot\_11,matrizpivot\_12,matrizpivot\_13 )
    ;y la dirección del eje Y, a través del vector Y-> del plano frontal del ojo ( matrizpivot\_21,matrizpivot\_22,matrizpivot\_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.f*mdx.f+mdy.f*mdy.f+mdz.f*mdz.f)
    If THETA.d>0
      ux_m.d=Sqr(matrizpivot\_11*matrizpivot\_11+matrizpivot\_12*matrizpivot\_12+matrizpivot\_13*matrizpivot\_13)
      If ux_m.d>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=matrizpivot\_11/ux_m:ux_y.d=matrizpivot\_12/ux_m:ux_z.d=matrizpivot\_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(matrizpivot\_21*matrizpivot\_21+matrizpivot\_22*matrizpivot\_22+matrizpivot\_23*matrizpivot\_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=matrizpivot\_21/uy_m:uy_y.d=matrizpivot\_22/uy_m:uy_z.d=matrizpivot\_23/uy_m; <- son los cosenos directores. 
        ;ahora multiplicando este vector unitario, por el modulo de (0,mdx,0) obtenemos ya la componente Y pero en el plano frontal del ojo:
        uy_x*mdx:uy_y*mdx:uy_z*mdx
      EndIf
      ;Hacemos lo mismo para obtener la componente Z del movimiento del ratón pero en el plano frontal del ojo
      uz_m.d=Sqr(matrizpivot\_31*matrizpivot\_31+matrizpivot\_32*matrizpivot\_32+matrizpivot\_33*matrizpivot\_33)
      If uz_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
        uz_x.d=matrizpivot\_31/uz_m:uz_y.d=matrizpivot\_32/uz_m:uz_z.d=matrizpivot\_33/uz_m; <- son los cosenos directores. 
        ;ahora multiplicando este vector unitario, por el modulo de (0,0,mdz) obtenemos ya la componente Z pero en el plano frontal del ojo:
        uz_x*mdz:uz_y*mdz:uz_z*mdz
      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+uz_x.d:u\y=ux_y.d+uy_y.d+uz_y.d:u\z=ux_z.d+uy_z.d+uz_z.d
      ;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
      EntityGetMatrixFromQuaternion(EntityID(#Object0),@matrizobjeto)
      MatrizRotacionaldeunAngulodadoalrededordeunejedefinidoporunvectorunidad(EntityID(#Object0),@u.Vector3D,THETA,@matrizobjeto)
      ;Beep_(200,5)
    EndIf
  EndIf
  TimeSinceLastFrame.i=RenderWorld(50)
;   If IsSprite(#Sprite2D):showhelpsprite():EndIf
  FlipBuffers():Delay(9)
Until KeyboardPushed(#PB_Key_Escape)
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
User avatar
Comtois
Addict
Addict
Posts: 1429
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Re: Simple function to rotate 3D objects over given axis

Post by Comtois »

Is it what you are looking for ?

Code: Select all

#CameraSpeed = 1

IncludeFile #PB_Compiler_Home + "examples/3d/Screen3DRequester.pb"

Define.f  MouseX, MouseY

If InitEngine3D()
  
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Packs/skybox.zip", #PB_3DArchive_Zip)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts", #PB_3DArchive_FileSystem)
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  Global Attached = #False
  
  If Screen3DRequester()
    
    CreateMaterial(0, LoadTexture(0, "r2skin.jpg"))    
    CreateCube(0,1)
    CreateEntity(0, MeshID(0), MaterialID(0))
    
    LoadMesh(1, "axes.mesh")
    CreateMaterial(1, LoadTexture(1, "axes.png"))
    CreateEntity(1, MeshID(1), MaterialID(1), -1, 1, -1)
    ScaleEntity(1,0.1,0.1,0.1)
        
    SkyBox("stevecube.jpg")
    
    AttachEntityObject(0,"",EntityID(1))    
    
    CreateCamera(0, 0, 0, 100, 100)
    MoveCamera(0, 5, 5, 5, #PB_Absolute)
    CameraLookAt(0, 0, 0, 0)
    
    Repeat
      Screen3DEvents()
      
      ExamineMouse()
      MouseX = -MouseDeltaX() * #CameraSpeed * 0.5
      MouseY = -MouseDeltaY() * #CameraSpeed * 0.5
            
      ExamineKeyboard()
      
      RotateEntity(0, Mousey, Mousex, 0, #PB_Relative)
      
      
      RenderWorld()
      
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  EndIf
  
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf

End 
Please correct my english
http://purebasic.developpez.com/
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 291
Joined: Thu Jul 09, 2015 9:07 am

Re: Simple function to rotate 3D objects over given axis

Post by pf shadoko »

I wanted to add the parameter w to the Entitydirection function, but I don't see how to specify the origin of the angle

don't forget the Engine3D lib functions:
Yaw, pitch and roll, usable with all 3d objects

maybe this example will meet your needs

Code: Select all

Define.f rz,dx,dy,dz,a,ya,     r=0.8

InitEngine3D():InitSprite():InitKeyboard():InitMouse()
ExamineDesktops()
ex=DesktopWidth(0)*r
ey=DesktopHeight(0)*r
OpenWindow(0, 0, 0,ex,ey, "Test 3d >>> cursor up/down  - Esc to quit",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, ex, ey, 0, 0, 0)

WorldShadows(#PB_Shadow_Additive)
CreateLight(0,$888888, 5000, 3000, 2000)
AmbientColor($777777)

CreateCamera(0, 0, 0, 100, 100)
MoveCamera(0,0,10,-20)
CameraLookAt(0,0,0,0)
CameraBackColor(0,$888888) 

Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
CreateMaterial(0, LoadTexture(0, "MRAMOR6X6.jpg"))
CreateMaterial(1, LoadTexture(1, "flaretrail.png"))

CreatePlane(0,100,100,16,16,16,16)
CreateEntity(0,MeshID(0),MaterialID(0),0,0,0)

CreateCube(1,1):TransformMesh(1,0,2,0,1,4,2,0,0,0)
CreateEntity(1,MeshID(1),MaterialID(1),0,0,0)

Macro KBdep(k1,k2)
  (Bool(KeyboardPushed(k1)<>0)-Bool(KeyboardPushed(k2)<>0)) 
EndMacro

Repeat
  WindowEvent()
  ExamineMouse()
  ExamineKeyboard()
  dx+KBdep(#PB_Key_Left,#PB_Key_Right)*0.02
  dy=2
  dz+KBdep(#PB_Key_Up,#PB_Key_Down)*0.02
  rz+KBdep(#PB_Key_PageUp,#PB_Key_PageDown)*2
  MoveEntity(1,0,0,0,#PB_Absolute)
  EntityDirection(1,dx,dy,dz,#PB_World,1)
  ya=EntityYaw(1):Yaw(EntityID(1),-ya+rz,#PB_Local)
  ;ya=EntityYaw(1):Yaw(EntityID(1),rz,#PB_World)
  Debug rz
  CreateLine3D(100,0,0,0,$ff00,dx*4,dy*4,dz*4,$ff)
  CameraLookAt(0,EntityX(1),EntityY(1),EntityZ(1))
  RenderWorld()
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)




User avatar
Psychophanta
Addict
Addict
Posts: 4997
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Re: Simple function to rotate 3D objects over given axis

Post by Psychophanta »

@Comtois: no dear, that's not. Can't you see the behaviour of the .exe I pointed to?

@pf shadoko: your tip hangs here. :?


As soon as I have a functional tip, I will post. At the moment i continue with no success.
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
User avatar
Comtois
Addict
Addict
Posts: 1429
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Re: Simple function to rotate 3D objects over given axis

Post by Comtois »

Psychophanta wrote:@Comtois: no dear, that's not. Can't you see the behaviour of the .exe I pointed to?
Well my code does the same behaviour (just add DetachEntityObject() to be more complete)

I do not understand what difference there is
Please correct my english
http://purebasic.developpez.com/
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Simple function to rotate 3D objects over given axis

Post by djes »

One should be able to rotate an entity around any axis : in a local (object) system or in a global system, for example to work with multiples cameras and points of view.

More than that, one should be able to transform any entity with any referential. For example, to scale/move/rotate several objects relatively to any defined axis : useful if you want to create a 3D tool.

If you create working EntityFixedYawAxis(), EntityFixedRollAxis() and EntityFixedPitchAxis() functions, it should be OK for rotation, but if would be more complete to add a function to give full control with something like a "pivot point" or "referential".

I think the way to go is to complete the "node" functions. There's several relative possibilities with MoveEntity(), why no scale and rotate ?

Edit: to simplify and typo
Last edited by djes on Mon Feb 18, 2019 1:07 pm, edited 2 times in total.
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 291
Joined: Thu Jul 09, 2015 9:07 am

Re: Simple function to rotate 3D objects over given axis

Post by pf shadoko »

Sorry, I didn't understand your answer.

I forgot to mention that, in my sample, you can change the direction with the arrow keys, and w with PageUp and PageDown
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Simple function to rotate 3D objects over given axis

Post by djes »

pf shadoko wrote:Sorry, I didn't understand your answer.

I forgot to mention that, in my sample, you can change the direction with the arrow keys, and w with PageUp and PageDown
The entity in your example doesn't rotate around fixed "world" axis. I've edited my previous post.
User avatar
Psychophanta
Addict
Addict
Posts: 4997
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Re: Simple function to rotate 3D objects over given axis

Post by Psychophanta »

Comtois wrote:
Psychophanta wrote:@Comtois: no dear, that's not. Can't you see the behaviour of the .exe I pointed to?
Well my code does the same behaviour (just add DetachEntityObject() to be more complete)

I do not understand what difference there is
Comtois, really?
Are you joking?
Don't you really understand?
Please answer, because i don't believe. And sorry.

Djes DOES understand perfectly, it is so simple in fact. And i sent you tips and an executeable.

To rotate around a given "world" axis. Sorry but, is it so hard to get?
None of your tip are accepting a world axis.
May be my tips are not enough clear, because they accept axis contained in the front plane of the view (the orientation of the node where the camera is attached to), which is an axis depending on the x AND y of the mouse move, but ALWAYS contained in the front plane of the camera view.

Well, please allow me to repeat the above post in other words:
I know to rotate an element around a given arbitrary "world" axis, using its orientation matrix and the rotation matrix which i derive from just an unique vector (tip above ilustrates), which i call the angle-vector, because in a single vector is contained the rotation axis, the amount angle to rotate and the direction of the rotation (this is just the Euler law of rotation).
But: Making use of the native PB 3D engine i am not able to do it: even I tried converting the quaternion to the rotation-matrix and viceversa (the other tip above), there is no success.
I know how does work a quaternion, and i am working on a funtion to do that. I know a quaternion from an object is just its current orientation, so to rotate the object in any axis, we must to perform some calculations starting from its current orientation, ... which is a real headache, because a quaternion is not exactly a 3D vector, but a rare thing to me, and i am in use to work with vectors and matrix.
At the moment, there is at least one thing very sure: the resources of computing when working with quaternions IS NOT lower than working with matrix, as is stated in some texts.
Thanks!

(Of course @djes, thanks, great)
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
User avatar
Comtois
Addict
Addict
Posts: 1429
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Re: Simple function to rotate 3D objects over given axis

Post by Comtois »

And now spheres turn around world axis (code show 2 ways) ? Or i dont understand again ?

Code: Select all

Structure Vector3
  x.f
  y.f
  z.f
EndStructure

Structure Quaternion
  x.f
  y.f
  z.f
  w.f
EndStructure

#CameraSpeed = 1

IncludeFile #PB_Compiler_Home + "examples/3d/Screen3DRequester.pb"

Define.f  MouseX, MouseY, Angle
Define.Vector3 Axis, AxisN
Define.Quaternion Q
Declare QuaternionFromAngleAxis (*Q.Quaternion, Angle.f, *Axis.Vector3)
Declare.f normalise(*V.Vector3)

Axis\x = -3
Axis\y = 5
Axis\z = 2

CopyStructure(@Axis, @AxisN, Vector3)
normalise(@AxisN)

If InitEngine3D()
  
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Packs/skybox.zip", #PB_3DArchive_Zip)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts", #PB_3DArchive_FileSystem)
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
  If Screen3DRequester()
    
    
    CreateMaterial(0, LoadTexture(0, "r2skin.jpg"))    
    CreateSphere(0,1)
    CreateEntity(1, MeshID(0), MaterialID(0),5,3,0)
    CreateEntity(2, MeshID(0), MaterialID(0),5,4,0)
    
    CreateNode(0,0,0,0)
    AttachNodeObject(0,EntityID(1))
    
    CreateNode(1,0,0,0)
    AttachNodeObject(1,EntityID(2))
    
    NodeFixedYawAxis(0, #True, AxisN\x, AxisN\y, AxisN\z)
    
    ;Ribbon
    GetScriptMaterial(2, "Examples/LightRibbonTrail")
    CreateRibbonEffect(0, MaterialID(2), 1, 2800, 180)
    RibbonEffectColor(0, 0, RGBA(0, 255*0.8, 255*0.8, 255), RGBA(0, 255, 0, 5))
    RibbonEffectWidth(0, 0, 0.1, 0.001)
    AttachRibbonEffect(0, EntityParentNode(1))
    
    CreateRibbonEffect(1, MaterialID(2), 1, 2800, 180)
    RibbonEffectColor(1, 0, RGBA(255*0.8, 255*0.8, 0, 255), RGBA(0, 255, 0, 5))
    RibbonEffectWidth(1, 0, 0.1, 0.001)
    AttachRibbonEffect(1, EntityParentNode(2))
    
    
    CreateLine3D(5,NodeX(0),NodeY(0),NodeZ(0), RGB(255,0,0), NodeX(0) + Axis\x,NodeY(0) + Axis\y,NodeZ(0) + Axis\z, RGB(255,0,0))
    
    SkyBox("stevecube.jpg")
    
    
    CreateCamera(0, 0, 0, 100, 100)
    MoveCamera(0, 0, 0, 30, #PB_Absolute)
    CameraLookAt(0, 0, 0, 0)
    
    Repeat
      
      Screen3DEvents()
      
      ExamineKeyboard()
      
      RotateNode(0,0,0.4,0, #PB_Relative)
      
      QuaternionFromAngleAxis(@Q, Radian(Angle), @AxisN)
      SetOrientation(NodeID(1), Q\x, Q\y, Q\z, Q\w)
      
      Angle + 0.4
      
      RenderWorld()
      
      FlipBuffers()
      
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
    
  EndIf
  
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf

End 

Procedure.f normalise(*V.Vector3)
  
  Length.f = Sqr( *V\x * *V\x + *V\y * *V\y + *V\z * *V\z)
  
  If  Length > 0.0
    
    InvLength.f = 1.0 / Length
    *V\x * InvLength
    *V\y * InvLength
    *V\z * InvLength
  EndIf
  
  ProcedureReturn Length
  
EndProcedure

;Axis (normalisé) 
;Angle (en radian)
Procedure QuaternionFromAngleAxis (*Q.Quaternion, Angle.f, *Axis.Vector3)
  HalfAngle.f = 0.5*Angle
  Sin.f = Sin(HalfAngle)
  *Q\w = Cos(HalfAngle)
  *Q\x = Sin * *Axis\x
  *Q\y = Sin * *Axis\y
  *Q\z = Sin * *Axis\z
EndProcedure
Please correct my english
http://purebasic.developpez.com/
User avatar
Psychophanta
Addict
Addict
Posts: 4997
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Re: Simple function to rotate 3D objects over given axis

Post by Psychophanta »

Hi Comtois,
firstly thanks for your patience.

Awesomely I see you got it.
However, your tip again does not do the thing.
Just modify the axis in real time in the loop, and you will see the chaos begins for the 2 cases: the fixedYaw one, and also with the SetOrientation() (via quaternion) one.

Code: Select all

Structure Vector3
  x.f
  y.f
  z.f
EndStructure
Structure Quaternion
  x.f
  y.f
  z.f
  w.f
EndStructure
#CameraSpeed = 1
IncludeFile #PB_Compiler_Home + "examples/3d/Screen3DRequester.pb"
Angle.f
Axis.Vector3:AxisN.Vector3
Q.Quaternion
Procedure QuaternionFromAngleAxis (*Q.Quaternion, Angle.f, *Axis.Vector3)
  HalfAngle.f = 0.5*Angle
  Sin.f = Sin(HalfAngle)
  *Q\w = Cos(HalfAngle)
  *Q\x = Sin * *Axis\x
  *Q\y = Sin * *Axis\y
  *Q\z = Sin * *Axis\z
EndProcedure
Macro GetItNormalized()
  CopyStructure(@Axis, @AxisN, Vector3)
  ;AxisN=Axis
  len.f=Sqr(AxisN\x*AxisN\x+AxisN\y*AxisN\y+AxisN\z*AxisN\z)
  AxisN\x/len:AxisN\y/len:AxisN\z/len
EndMacro
Macro SetFixedandDisplayline()
  NodeFixedYawAxis(0,#True,AxisN\x,AxisN\y,AxisN\z)
  CreateLine3D(5,NodeX(0),NodeY(0),NodeZ(0),RGB(255,0,0),NodeX(0)+Axis\x,NodeY(0)+Axis\y,NodeZ(0)+Axis\z,RGB(255,0,0))
EndMacro
Axis\x=-1.7
Axis\y=0.0
Axis\z=0.0
GetItNormalized()
If InitEngine3D()
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Packs/skybox.zip", #PB_3DArchive_Zip)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts", #PB_3DArchive_FileSystem)
  Parse3DScripts()
  InitSprite():InitKeyboard():InitMouse()
  If Screen3DRequester()
    CreateCamera(0,0,0,100,100):MoveCamera(0,0,0,10,#PB_Absolute):CameraLookAt(0,0,0,0)
    CreateMaterial(0,LoadTexture(0,"r2skin.jpg"))    
    CreateCube(0,1)
    CreateEntity(1,MeshID(0),MaterialID(0),1,1,0)
    CreateEntity(2,MeshID(0),MaterialID(0),1,2,0)
    CreateNode(0,0,0,0):AttachNodeObject(0,EntityID(1))
    CreateNode(1,0,0,0):AttachNodeObject(1,EntityID(2))
    SetFixedandDisplayline()
    Repeat
      Screen3DEvents()
      ExamineKeyboard():ExamineMouse()
      mdx.f=MouseDeltaX()/20:mdy.f=MouseDeltaY()/20:mdz.f=MouseWheel()/20
      Axis\x+mdx:Axis\y-mdy:Axis\z+mdz
      GetItNormalized()
      SetFixedandDisplayline()
      RotateNode(0,0,0.4,0,#PB_Relative)
      QuaternionFromAngleAxis(@Q,Radian(Angle),@AxisN)
      SetOrientation(NodeID(1),Q\x,Q\y,Q\z,Q\w)
      Angle+0.4
      RenderWorld()
      FlipBuffers():delay(10)
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  EndIf
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
By the way i did functions to get a quaternion form an axis vector and viceversa:

Code: Select all

Procedure.d ObtenerCuaternioDesdeVectorangulo(*fi.Vector3D,*q.cuaternio); <- usar esta cuando no disponemos del módulo angular de antemano (antes de llamar a la función), sino solo del propio vector ángulo
  Protected u.Vector3D
  With *q
  *fi\m=getmodulo(*fi); <- incluye el numero de vueltas completas (Int(*fi\m/2/#Pi)) más el resto de esa división (Mod(*fi\m,2*#Pi))
  u\m=Mod(*fi\m,2*#Pi); <- pero para obtener el cuaternio se debe trabajar con un angulo inferior a 2*#Pi, es decir con el resto de esa division (Mod(*fi\m,2*#Pi)) 
  If u\m
    u\x=*fi\x/u\m:u\y=*fi\y/u\m:u\z=*fi\z/u\m
    u\m/2
    \w=Cos(u\m)
    \v\z=Sin(u\m)
    \v\x=u\x*\v\z
    \v\y=u\y*\v\z
    \v\z*u\z
  Else
    \w=1.0
    \v\x=0.0
    \v\y=0.0
    \v\z=0.0
  EndIf
  ProcedureReturn u\m
  EndWith
EndProcedure
Procedure.d ObtenerVectoranguloDesdeCuaternio(*q.cuaternio,*fi.Vector3D); <- usar esta cuando no disponemos del módulo angular de antemano (antes de llamar a la función), sino solo del propio vector ángulo
  With *fi
  \m=ACos(*q\w)
  If \m
    \x=*q\v\x/Sin(\m)
    \y=*q\v\y/Sin(\m)
    \z=*q\v\z/Sin(\m)
    \m*2
    \x*\m
    \y*\m
    \z*\m
  Else
    \m=0.0; <- obviamente
    \x=0.0
    \y=0.0
    \z=0.0
  EndIf
  ProcedureReturn \m
  EndWith
EndProcedure
And also from Quaternion to rot matrix and viceversa:

Code: Select all

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
Macro QuaternionPorQuaternion(q0,q1,o); Composicion de 2 cuaterniones
  o#\w=q0#\w*q1#\w-ProductoEscalar(q0#\v,q1#\v)
  ProductoVectorial(q0#\v,q1#\v,vr.D3DXVECTOR3)
  o#\v\x=q0#\w*q1#\v\x+q1#\w*q0#\v\x+vr\x
  o#\v\y=q0#\w*q1#\v\y+q1#\w*q0#\v\y+vr\y
  o#\v\z=q0#\w*q1#\v\z+q1#\w*q0#\v\z+vr\z
EndMacro
Macro qpq_(q,p,o); Composicion de 2 cuaterniones
  QuaternionPorQuaternion(q#,p#,o#)
  p#=o#
  q#\v\x=-q#\v\x
  q#\v\y=-q#\v\y
  q#\v\z=-q#\v\z
  QuaternionPorQuaternion(p#,q#,o#)
EndMacro
Procedure.i ObtenerMatrizDesdeCuaternio(objeto.i,*matriz.D3DMATRIX,modo.i=#PB_Absolute)
  FetchOrientation(objeto,modo):Protected x.f=GetX(),y.f=GetY(),z.f=GetZ(),w.f=GetW(),s.f=2.0/(x*x+y*y+z*z+w*w)
  *matriz\Xi=1-s*(y*y+z*z); <- 0,0
  *matriz\Xj=s*(x*y-z*w); <- 0,1
  *matriz\Xk=s*(x*z+y*w); <- 0,2
  *matriz\Yi=s*(x*y+z*w); <- 1,0
  *matriz\Yj=1-s*(x*x+z*z); <- 1,1
  *matriz\Yk=s*(y*z-x*w); <- 1,2
  *matriz\Zi=s*(x*z-y*w); <- 2,0
  *matriz\Zj=s*(y*z+x*w); <- 2,1
  *matriz\Zk=1-s*(x*x+y*y); <- 2,2
  ProcedureReturn *matriz
EndProcedure
Procedure ObtenerCuaternioDesdeMatriz0(objeto.i,*matriz.D3DMATRIX)
  Protected q.cuaternio
  q\w=Sqr(*matriz\Xi+*matriz\Yj+*matriz\Zk+1)/2
  q\v\x=Sign(*matriz\Zj-*matriz\Yk)*Sqr(*matriz\Xi-*matriz\Yj-*matriz\Zk+1)/2
  q\v\y=Sign(*matriz\Xk-*matriz\Zi)*Sqr(*matriz\Yj-*matriz\Xi-*matriz\Zk+1)/2
  q\v\z=Sign(*matriz\Yi-*matriz\Xj)*Sqr(*matriz\Zk-*matriz\Xi-*matriz\Yj+1)/2
  SetOrientation(objeto,q\v\x,q\v\y,q\v\z,q\w)
EndProcedure
Procedure ObtenerCuaternioDesdeMatriz(objeto.i,*matriz.D3DMATRIX)
  Protected q.cuaternio,tr.f=*matriz\Xi+*matriz\Yj+*matriz\Zk,S.f
  If tr>0
    S=Sqr(tr+1)*2; S=4*w
    q\w=S/4
    q\v\x=(*matriz\Zj-*matriz\Yk)/S
    q\v\y=(*matriz\Xk-*matriz\Zi)/S
    q\v\z=(*matriz\Yi-*matriz\Xj)/S
  ElseIf *matriz\Xi>*matriz\Yj And *matriz\Xi>*matriz\Zk
    S=Sqr(1+*matriz\Xi-*matriz\Yj-*matriz\Zk)*2; S=4*x
    q\w=(*matriz\Zj-*matriz\Yk)/S
    q\v\x=S/4
    q\v\y=(*matriz\Xj+*matriz\Yi)/S
    q\v\z=(*matriz\Xk+*matriz\Zi)/S
  ElseIf *matriz\Yj>*matriz\Zk
    S=Sqr(1+*matriz\Yj-*matriz\Xi-*matriz\Zk)*2; S=4*y
    q\w=(*matriz\Xk-*matriz\Zi)/S
    q\v\x=(*matriz\Xj+*matriz\Yi)/S
    q\v\y=S/4
    q\v\z=(*matriz\Yk+*matriz\Zj)/S
  Else
    S=Sqr(1+*matriz\Zk-*matriz\Xi-*matriz\Yj)*2; S=4*z
    q\w=(*matriz\Yi-*matriz\Xj)/S
    q\v\x=(*matriz\Xk+*matriz\Zi)/S
    q\v\y=(*matriz\Yk+*matriz\Zj)/S
    q\v\z=S/4
  EndIf
  SetOrientation(objeto,q\v\x,q\v\y,q\v\z,q\w)
EndProcedure
Procedure ObtenerCuaternioDesdeMatriz2(objeto.i,*matriz.D3DMATRIX)
  Protected Dim m.f(2,2),c.cuaternio,tr.f,s.f,Dim q.f(3),i.l,j.l,k.l,Dim nxt.l(2):nxt.l(0)=1:nxt.l(1)=2:nxt.l(2)=0
  m(0,0)=*matriz\Xi:m(0,1)=*matriz\Xj:m(0,2)=*matriz\Xk
  m(1,0)=*matriz\Yi:m(1,1)=*matriz\Yj:m(1,2)=*matriz\Yk
  m(2,0)=*matriz\Zi:m(2,1)=*matriz\Zj:m(2,2)=*matriz\Zk
  tr=m(0,0)+m(1,1)+m(2,2)
  ; check the diagonal
  If tr>0.0
    s=Sqr(tr+1.0)
    c\w=s/2.0
    s=0.5/s
    c\v\x=(m(1,2)-m(2,1))*s
    c\v\y=(m(2,0)-m(0,2))*s
    c\v\z=(m(0,1)-m(1,0))*s
  Else; diagonal is negative
    i=0
    If m(1,1)>m(0,0):i=1:EndIf
    If m(2,2)>m(i,i):i=2:EndIf
    j=nxt(i)
    k=nxt(j)
    s=Sqr(m(i,i)-m(j,j)-m(k,k)+1.0)
    q(i)=s*0.5
    If s<>0.0:s=0.5/s:EndIf
    q(3)=(m(j,k)-m(k,j))*s
    q(j)=(m(i,j)+m(j,i))*s
    q(k)=(m(i,k)+m(k,i))*s
    c\v\x=q(0)
    c\v\y=q(1)
    c\v\z=q(2)
    c\w=q(3)
  EndIf
  SetOrientation(objeto,c\v\x,c\v\y,c\v\z,c\w)
EndProcedure
But still no success. I've researched in the web but no success.
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Simple function to rotate 3D objects over given axis

Post by djes »

You don't get it because this is not only maths, but global thinking.

A tip is to think by object and world, keeping axis in the structures and applying transformations on it also.

Basically, the original object can be transformed in a local context (as pb does). It can also be transformed in a world context (lacking). Finally, it can be transformed in camera context (done). Eventually, it can transformed in a node context (partially done) giving access to bones and objects hierarchy.

Additionally, you may also think on two representations : the original object, and the transformed. Object data could be altered, leading to a new geometry. If you (-1) transform the axis, you may keep the history.

Btw, you may also keep a track of all tranformations in a list.

The code I've given was basically for this purpose even if it's incomplete.
Post Reply