Re: Smooth align Player to Object/Terrain he's standing
Posted: Tue Sep 03, 2013 6:17 pm
Please post a snippet showing the issue if you want help.
http://www.purebasic.com
https://www.purebasic.fr/english/
Code: Select all
IncludeFile "Screen3DRequester.pb"
#TerrainMiniX = 0
#TerrainMiniY = 0
#TerrainMaxiX = 0
#TerrainMaxiY = 0
#PlayerSpeed = 6
#CameraSpeed = 1
Define.f KeyX, KeyY, MouseX, MouseY, TimeSinceLastFrame
Declare InitBlendMaps()
Structure Vector3
x.f
y.f
z.f
EndStructure
Structure s_Key
Up.i
Down.i
Left.i
Right.i
StrafeLeft.i
StrafeRight.i
Jump.i
EndStructure
Structure s_Entity
Entity.i
EntityBody.i
BodyOffsetY.f
elapsedTime.f
Key.s_Key
MainNode.i
SightNode.i
CameraNode.i
ForwardNode.i
StrafeNode.i
EndStructure
Structure s_Camera
Camera.i
Tightness.f
CameraNode.i
TargetNode.i
EndStructure
Macro GetNodePosition(Position, Node)
Position\x = NodeX(Node)
Position\y = NodeY(Node)
Position\z = NodeZ(Node)
EndMacro
Macro SubVector3(V, V1, V2)
V\x = V1\x - V2\x
V\y = V1\y - V2\y
V\z = V1\z - V2\z
EndMacro
;-Declare
Declare HandleEntity(*Entity.s_Entity)
Declare CameraTrack(*Camera.s_Camera, *Entity.s_Entity)
Declare OnGround(*Entity.s_Entity)
Define Robot.s_Entity
Define Camera.s_Camera
; OpenGL needs to have CG enabled to work (Linux and OS X have OpenGL by default)
;
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows Or Subsystem("OpenGL")
Flags = #PB_Engine3D_EnableCG
CompilerEndIf
If InitEngine3D(Flags)
InitSprite()
InitKeyboard()
InitMouse()
If Screen3DRequester()
Add3DArchive("Data/Textures/" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Models" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Scripts" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Textures/nvidia" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Packs/desert.zip", #PB_3DArchive_Zip)
Parse3DScripts()
WorldShadows(#PB_Shadow_Modulative, 200, RGB(120, 120, 120))
MaterialFilteringMode(#PB_Default, #PB_Material_Anisotropic, 8)
;- Light
;
light = CreateLight(#PB_Any ,RGB(185, 185, 185), 4000, 1200, 1000, #PB_Light_Directional)
SetLightColor(light, #PB_Light_SpecularColor, RGB(255*0.4, 255*0.4,255*0.4))
LightDirection(light ,0.55, -0.3, -0.75)
AmbientColor(RGB(5, 5,5))
;- Camera
;
CreateCamera(0, 0, 0, 100, 100)
CameraBackColor(0, RGB(5, 5, 10))
;----------------------------------
;-terrain definition
SetupTerrains(LightID(Light), 300, #PB_Terrain_NormalMapping)
;-initialize terrain
CreateTerrain(0, 513, 1200, 60, 3, "TerrainPhysic", "dat")
;-set all texture will be use when terrrain will be constructed
AddTerrainTexture(0, 0, 10, "dirt_grayrocky_diffusespecular.jpg", "dirt_grayrocky_normalheight.jpg")
AddTerrainTexture(0, 1, 3, "grass_green-01_diffusespecular.jpg", "grass_green-01_normalheight.jpg")
AddTerrainTexture(0, 2, 20, "growth_weirdfungus-03_diffusespecular.jpg", "growth_weirdfungus-03_normalheight.jpg")
;-Construct terrains
For ty = #TerrainMiniY To #TerrainMaxiY
For tx = #TerrainMiniX To #TerrainMaxiX
Imported = DefineTerrainTile(0, tx, ty, "terrain513.png", ty % 2, tx % 2)
Next
Next
BuildTerrain(0)
If Imported = #True
InitBlendMaps()
UpdateTerrain(0)
; If enabled, it will save the terrain as a (big) cache for a faster load next time the program is executed
; SaveTerrain(0, #False)
EndIf
; enable shadow terrain
TerrainRenderMode(0, 0)
;Add Physic
TerrainPhysicBody(0, 0.1, 1)
;Texture
CreateTexture(1, 256, 256)
StartDrawing(TextureOutput(1))
Box(0, 0, 256, 256, $002255)
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, 256, 256, $FFFFFF)
Box(10, 10, 236, 236, $FFFF)
StopDrawing()
;Material
CreateMaterial(0, LoadTexture(0, "r2skin.jpg"))
CreateMaterial(1, TextureID(1))
CreateMaterial(2, LoadTexture(2, "Dirt.jpg"))
CreateMaterial(3, LoadTexture(3, "Wood.jpg"))
GetScriptMaterial(4, "Scene/GroundBlend")
;Robot
CreateSphere(0, 1)
Rob = LoadMesh(#PB_Any, "Robot.mesh")
CreateEntity (0, MeshID(Rob), #PB_Material_None)
ScaleEntity(0, 0.1, 0.1, 0.1)
StartEntityAnimation(0, "Walk")
;Robot Body
CreateEntity(1, MeshID(0), #PB_Material_None, 0, 426, 0)
HideEntity(1, 1)
;Body
EntityPhysicBody(1, #PB_Entity_SphereBody, 1, 0, 0)
; Skybox
SkyBox("desert07.jpg")
;
With Robot
\Entity = 0
\EntityBody = 1
\BodyOffsetY = 1
\Key\Down = #PB_Key_Down
\Key\Left = #PB_Key_Left
\Key\Right = #PB_Key_Right
\Key\Up = #PB_Key_Up
\Key\StrafeLeft = #PB_Key_X
\Key\StrafeRight = #PB_Key_C
\Key\Jump = #PB_Key_Space
\MainNode = CreateNode(#PB_Any) ; Entity position
\SightNode = CreateNode(#PB_Any, 12, 2, 0) ; For cameraLookAt
\CameraNode = CreateNode(#PB_Any, -14, 10, 0) ; Camera position
\ForwardNode = CreateNode(#PB_Any, 1, 0, 0) ; Direction normalized
\StrafeNode = CreateNode(#PB_Any, 0, 0, -1) ; Direction normalized
AttachNodeObject(\MainNode, NodeID(\SightNode))
AttachNodeObject(\MainNode, NodeID(\CameraNode))
AttachNodeObject(\MainNode, NodeID(\ForwardNode))
AttachNodeObject(\MainNode, NodeID(\StrafeNode))
AttachNodeObject(\MainNode, EntityID(\Entity))
EndWith
;-Camera
With Camera
\Camera = 0
\Tightness = 0.035
; Camera use 2 nodes
\CameraNode = CreateNode(#PB_Any, -3000, 700, 0) ; Camera position
\TargetNode = CreateNode(#PB_Any) ; For cameraLookAt
AttachNodeObject(\CameraNode, CameraID(\Camera))
EndWith
;==================================
; create material
Red = GetScriptMaterial(#PB_Any, "Color/Red")
Blue = GetScriptMaterial(#PB_Any, "Color/Blue")
Yellow = GetScriptMaterial(#PB_Any, "Color/Yellow")
Green = GetScriptMaterial(#PB_Any, "Color/Green")
;==================================
; create Sphere
MeshSphere = CreateSphere(#PB_Any, 1.0)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshSphere), MaterialID(Green))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_SphereBody, 1.0)
Next
;==================================
; create Cylinder
MeshCylinder = CreateCylinder(#PB_Any, 1.0, 6)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshCylinder), MaterialID(Red))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_CylinderBody, 1.0, 0, 1)
Next
;==================================
; create Cube
MeshCube = CreateCube(#PB_Any, 0.25)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshCube), MaterialID(Yellow))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_BoxBody, 1.0)
Next
Repeat
Screen3DEvents()
Robot\elapsedTime = TimeSinceLastFrame
HandleEntity(@Robot)
CameraTrack(@Camera, @Robot)
TimeSinceLastFrame = RenderWorld(60) * 40 / 1000
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
End
EndIf
Else
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows Or Subsystem("OpenGL")
;
; Terrain on Linux/OSX and Windows with OpenGL needs CG toolkit from nvidia
; It can be freely downloaded and installed from this site: https://developer.nvidia.com/cg-toolkit-download
;
MessageRequester("Error","Can't initialize engine3D (Please ensures than CG Toolkit from nvidia is correcly installed)")
CompilerElse
MessageRequester("Error","Can't initialize engine3D")
CompilerEndIf
EndIf
Procedure Clamp(*var.float, min.f, max.f)
If *var\f < min
*var\f = min
ElseIf *var\f > max
*var\f = max
EndIf
EndProcedure
Procedure InitBlendMaps()
minHeight1.f = 7
fadeDist1.f = 40
minHeight2.f = 7
fadeDist2.f = 15
For ty = #TerrainMiniY To #TerrainMaxiY
For tx = #TerrainMiniX To #TerrainMaxiX
Size = TerrainTileLayerMapSize(0, tx, ty)
For y = 0 To Size-1
For x = 0 To Size-1
Height.f = TerrainTileHeightAtPosition(0, tx, ty, 1, x, y)
val.f = (Height - minHeight1) / fadeDist1
Clamp(@val, 0, 1)
SetTerrainTileLayerBlend(0, tx, ty, 1, x, y, val)
val.f = (Height - minHeight2) / fadeDist2
Clamp(@val, 0, 1)
SetTerrainTileLayerBlend(0, tx, ty, 2, x, y, val)
Next
Next
UpdateTerrainTileLayerBlend(0, tx, ty, 1)
UpdateTerrainTileLayerBlend(0, tx, ty, 2)
Next
Next
EndProcedure
Procedure OnGround(*Entity.s_Entity)
With *Entity
Result = RayCollide(EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), EntityX(\EntityBody), EntityY(\EntityBody)-7, EntityZ(\EntityBody))
;CreateLine3D(20,EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), $FFFF, EntityX(\EntityBody), EntityY(\EntityBody)-7, EntityZ(\EntityBody), $FFFF)
Delta.f = EntityY(\EntityBody) - PickY() - \BodyOffsetY
If Result=-1 Or (Result>-1 And (delta >= 1))
ProcedureReturn 0
Else
CreateLine3D(20,PickX(), PickY(), PickZ(), $FFFF, PickX()+NormalX()*6, PickY()+NormalY()*6, PickZ()+NormalZ()*6, $FFFF)
RotateEntity(\Entity, Degree(ASin(NormalZ())), 0, Degree(ASin(-NormalX())))
ProcedureReturn 1
EndIf
EndWith
EndProcedure
Procedure HandleEntity(*Entity.s_Entity)
Protected.Vector3 Forward, Strafe, PosMain, PosDir, PosStrafe
Protected.f Speed, Speed2, x, y, MouseX, MouseY
Static Jump.f, MemJump.i, Rot.Vector3, Trans.Vector3, Clic
With *Entity
GetNodePosition(PosMain, \MainNode)
GetNodePosition(PosDir, \ForwardNode)
GetNodePosition(PosStrafe, \StrafeNode)
SubVector3(Forward, PosDir, PosMain)
SubVector3(Strafe, PosStrafe, PosMain)
Speed = #PlayerSpeed * \elapsedTime
Speed2 = Speed / 2
If ExamineKeyboard()
If KeyboardReleased(#PB_Key_F5)
WorldDebug(#PB_World_DebugBody)
ElseIf KeyboardReleased(#PB_Key_F6)
WorldDebug(#PB_World_DebugEntity)
ElseIf KeyboardReleased(#PB_Key_F7)
WorldDebug(#PB_World_DebugNone)
EndIf
If KeyboardPushed(\Key\Jump) And OnGround(*Entity)
Jump = 2
MemJump = 1
EndIf
Rot\x * 0.30
Rot\y * 0.30
Rot\z * 0.30
Trans\x * 0.20
Trans\y = Jump
Trans\z * 0.20
If KeyboardPushed(\Key\Up)
Trans\x + Forward\x * Speed
Trans\z + Forward\z * Speed
ElseIf KeyboardPushed(\Key\Down)
Trans\x + Forward\x * -Speed2
Trans\z + Forward\z * -Speed2
EndIf
If KeyboardPushed(\Key\Left)
Rot\y + 2 * \elapsedTime
ElseIf KeyboardPushed(\Key\Right)
Rot\y - 2 * \elapsedTime
EndIf
If KeyboardPushed(\Key\StrafeLeft)
Trans\x + Strafe\x * Speed2
Trans\z + Strafe\z * Speed2
ElseIf KeyboardPushed(\Key\StrafeRight)
Trans\x + Strafe\x * -Speed2
Trans\z + Strafe\z * -Speed2
EndIf
If OnGround(*Entity)
Jump = 0
ElseIf MemJump
Jump + 2 * \elapsedTime
If Jump > 15
MemJump = 0
EndIf
Else
Jump - 9
EndIf
EndIf
MoveEntity (\EntityBody, Trans\x, Trans\y, Trans\z)
RotateEntity(\EntityBody, 0, Rot\y, 0, #PB_Relative)
MoveNode(\MainNode, EntityX(\EntityBody), EntityY(\EntityBody)-\BodyOffsetY, EntityZ(\EntityBody), #PB_Absolute)
RotateNode(\MainNode, 0, EntityYaw(\EntityBody), 0)
EndWith
EndProcedure
Procedure CameraTrack(*Camera.s_Camera, *Entity.s_Entity)
Protected.Vector3 CameraPosition, TargetPosition
Protected.f x, y, z
GetNodePosition(CameraPosition, *Entity\CameraNode)
GetNodePosition(TargetPosition, *Entity\SightNode)
x = NodeX(*Camera\CameraNode)
y = NodeY(*Camera\CameraNode)
z = NodeZ(*Camera\CameraNode)
x = (CameraPosition\x - x) * *Camera\Tightness
y = (CameraPosition\y - y) * *Camera\Tightness
z = (CameraPosition\z - z) * *Camera\Tightness
MoveNode(*Camera\CameraNode, x, y, z)
x = NodeX(*Camera\TargetNode)
y = NodeY(*Camera\TargetNode)
z = NodeZ(*Camera\TargetNode)
x = (TargetPosition\x - x) * *Camera\Tightness
y = (TargetPosition\y - y) * *Camera\Tightness
z = (TargetPosition\z - z) * *Camera\Tightness
MoveNode(*Camera\TargetNode, x, y, z)
CameraLookAt(*Camera\Camera, NodeX(*Camera\TargetNode), NodeY(*Camera\TargetNode), NodeZ(*Camera\TargetNode))
EndProcedureCode: Select all
;
; ------------------------------------------------------------
;
; PureBasic - Terrain : Physic
;
; (c) 2012 - Fantaisie Software
;
; ------------------------------------------------------------
;
IncludeFile "Screen3DRequester.pb"
#TerrainMiniX = 0
#TerrainMiniY = 0
#TerrainMaxiX = 0
#TerrainMaxiY = 0
#PlayerSpeed = 6
#CameraSpeed = 1
Define.f KeyX, KeyY, MouseX, MouseY, TimeSinceLastFrame
Declare InitBlendMaps()
Structure Vector3
x.f
y.f
z.f
EndStructure
Structure Quaternion
w.f
x.f
y.f
z.f
EndStructure
Structure Colonne3
n.f[3]
EndStructure
Structure Matrix3
m.Colonne3[3]
EndStructure
Structure s_Key
Up.i
Down.i
Left.i
Right.i
StrafeLeft.i
StrafeRight.i
Jump.i
EndStructure
Structure s_Entity
Entity.i
EntityBody.i
BodyOffsetY.f
elapsedTime.f
Key.s_Key
MainNode.i
SightNode.i
Direction.i
EndStructure
Structure s_Camera
Camera.i
Tightness.f
CameraNode.i
TargetNode.i
EndStructure
Macro GetNodePosition(Position, Node)
Position\x = NodeX(Node)
Position\y = NodeY(Node)
Position\z = NodeZ(Node)
EndMacro
Macro SubVector3(V, V1, V2)
V\x = V1\x - V2\x
V\y = V1\y - V2\y
V\z = V1\z - V2\z
EndMacro
Macro AddVector3(V, V1, V2)
V\x = V1\x + V2\x
V\y = V1\y + V2\y
V\z = V1\z + V2\z
EndMacro
Macro PRODUIT_VECTORIEL(N, V1, V2)
N\x = ((V1\y * V2\z) - (V1\z * V2\y))
N\y = ((V1\z * V2\x) - (V1\x * V2\z))
N\z = ((V1\x * V2\y) - (V1\y * V2\x))
EndMacro
;-Declare
Declare HandleEntity(*Entity.s_Entity)
Declare CameraTrack(*Camera.s_Camera, *Entity.s_Entity)
Declare OnGround(*Entity.s_Entity)
Define Robot.s_Entity
Define Camera.s_Camera
Global R.Quaternion
; OpenGL needs to have CG enabled to work (Linux and OS X have OpenGL by default)
;
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows Or Subsystem("OpenGL")
Flags = #PB_Engine3D_EnableCG
CompilerEndIf
If InitEngine3D(Flags)
InitSprite()
InitKeyboard()
InitMouse()
If Screen3DRequester()
Add3DArchive("Data/Textures/" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Models" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Scripts" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Textures/nvidia" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Packs/desert.zip", #PB_3DArchive_Zip)
Parse3DScripts()
WorldShadows(#PB_Shadow_Modulative, 200, RGB(120, 120, 120))
MaterialFilteringMode(#PB_Default, #PB_Material_Anisotropic, 8)
;- Light
;
light = CreateLight(#PB_Any ,RGB(185, 185, 185), 4000, 1200, 1000, #PB_Light_Directional)
SetLightColor(light, #PB_Light_SpecularColor, RGB(255*0.4, 255*0.4,255*0.4))
LightDirection(light ,0.55, -0.3, -0.75)
AmbientColor(RGB(5, 5,5))
;----------------------------------
;-terrain definition
SetupTerrains(LightID(Light), 300, #PB_Terrain_NormalMapping)
;-initialize terrain
CreateTerrain(0, 513, 1200, 60, 3, "TerrainPhysic", "dat")
;-set all texture will be use when terrrain will be constructed
AddTerrainTexture(0, 0, 10, "dirt_grayrocky_diffusespecular.jpg", "dirt_grayrocky_normalheight.jpg")
AddTerrainTexture(0, 1, 3, "grass_green-01_diffusespecular.jpg", "grass_green-01_normalheight.jpg")
AddTerrainTexture(0, 2, 20, "growth_weirdfungus-03_diffusespecular.jpg", "growth_weirdfungus-03_normalheight.jpg")
;-Construct terrains
For ty = #TerrainMiniY To #TerrainMaxiY
For tx = #TerrainMiniX To #TerrainMaxiX
Imported = DefineTerrainTile(0, tx, ty, "terrain513.png", ty % 2, tx % 2)
Next
Next
BuildTerrain(0)
If Imported = #True
InitBlendMaps()
UpdateTerrain(0)
; If enabled, it will save the terrain as a (big) cache for a faster load next time the program is executed
; SaveTerrain(0, #False)
EndIf
; enable shadow terrain
TerrainRenderMode(0, 0)
;Add Physic
TerrainPhysicBody(0, 0.1, 1)
;Texture
CreateTexture(1, 256, 256)
StartDrawing(TextureOutput(1))
Box(0, 0, 256, 256, $002255)
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, 256, 256, $FFFFFF)
Box(10, 10, 236, 236, $FFFF)
StopDrawing()
;Material
CreateMaterial(0, LoadTexture(0, "r2skin.jpg"))
CreateMaterial(1, TextureID(1))
CreateMaterial(2, LoadTexture(2, "Dirt.jpg"))
CreateMaterial(3, LoadTexture(3, "Wood.jpg"))
GetScriptMaterial(4, "Scene/GroundBlend")
;Robot
CreateSphere(0, 1)
Rob = LoadMesh(#PB_Any, "Robot.mesh")
CreateEntity (0, MeshID(Rob), #PB_Material_None)
ScaleEntity(0, 0.1, 0.1, 0.1)
StartEntityAnimation(0, "Walk")
;Robot Body
CreateEntity(1, MeshID(0), #PB_Material_None, 0, 426, 0)
HideEntity(1, 1)
;Body
EntityPhysicBody(1, #PB_Entity_SphereBody, 1, 0, 0)
; Skybox
SkyBox("desert07.jpg")
;
With Robot
\Entity = 0
\EntityBody = 1
\BodyOffsetY = 1
\Key\Down = #PB_Key_Down
\Key\Left = #PB_Key_Left
\Key\Right = #PB_Key_Right
\Key\Up = #PB_Key_Up
\Key\StrafeLeft = #PB_Key_X
\Key\StrafeRight = #PB_Key_C
\Key\Jump = #PB_Key_Space
;\MainNode = CreateNode(#PB_Any) ; Entity position
\Direction = CreateNode(#PB_Any, 1, 0, 0) ; For cameraLookAt
\SightNode = CreateNode(#PB_Any, 12, 2, 0) ; For cameraLookAt
AttachEntityObject(\EntityBody, "", NodeID(\Direction))
AttachEntityObject(\EntityBody, "", NodeID(\SightNode))
;AttachNodeObject(\MainNode, EntityID(\Entity))
EndWith
;- Camera
;
CreateCamera(0, 0, 0, 100, 100)
CameraBackColor(0, RGB(5, 5, 10))
;==================================
; create material
Red = GetScriptMaterial(#PB_Any, "Color/Red")
Blue = GetScriptMaterial(#PB_Any, "Color/Blue")
Yellow = GetScriptMaterial(#PB_Any, "Color/Yellow")
Green = GetScriptMaterial(#PB_Any, "Color/Green")
;==================================
; create Sphere
MeshSphere = CreateSphere(#PB_Any, 1.0)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshSphere), MaterialID(Green))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_SphereBody, 1.0)
Next
;==================================
; create Cylinder
MeshCylinder = CreateCylinder(#PB_Any, 1.0, 6)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshCylinder), MaterialID(Red))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_CylinderBody, 1.0, 0, 1)
Next
;==================================
; create Cube
MeshCube = CreateCube(#PB_Any, 0.25)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshCube), MaterialID(Yellow))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_BoxBody, 1.0)
Next
Repeat
Screen3DEvents()
Robot\elapsedTime = TimeSinceLastFrame
HandleEntity(@Robot)
CameraFollow(0, EntityID(Robot\Entity), -90, EntityY(Robot\Entity) + 10, 25, 0.1, 0.1, 0)
CameraLookAt(0, NodeX(Robot\SightNode), NodeY(Robot\SightNode), NodeZ(Robot\SightNode))
TimeSinceLastFrame = RenderWorld(60) * 40 / 1000
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
End
EndIf
Else
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows Or Subsystem("OpenGL")
;
; Terrain on Linux/OSX and Windows with OpenGL needs CG toolkit from nvidia
; It can be freely downloaded and installed from this site: https://developer.nvidia.com/cg-toolkit-download
;
MessageRequester("Error","Can't initialize engine3D (Please ensures than CG Toolkit from nvidia is correcly installed)")
CompilerElse
MessageRequester("Error","Can't initialize engine3D")
CompilerEndIf
EndIf
Procedure Clamp(*var.float, min.f, max.f)
If *var\f < min
*var\f = min
ElseIf *var\f > max
*var\f = max
EndIf
EndProcedure
Procedure InitBlendMaps()
minHeight1.f = 7
fadeDist1.f = 40
minHeight2.f = 7
fadeDist2.f = 15
For ty = #TerrainMiniY To #TerrainMaxiY
For tx = #TerrainMiniX To #TerrainMaxiX
Size = TerrainTileLayerMapSize(0, tx, ty)
For y = 0 To Size-1
For x = 0 To Size-1
Height.f = TerrainTileHeightAtPosition(0, tx, ty, 1, x, y)
val.f = (Height - minHeight1) / fadeDist1
Clamp(@val, 0, 1)
SetTerrainTileLayerBlend(0, tx, ty, 1, x, y, val)
val.f = (Height - minHeight2) / fadeDist2
Clamp(@val, 0, 1)
SetTerrainTileLayerBlend(0, tx, ty, 2, x, y, val)
Next
Next
UpdateTerrainTileLayerBlend(0, tx, ty, 1)
UpdateTerrainTileLayerBlend(0, tx, ty, 2)
Next
Next
EndProcedure
Procedure Normalize(*V.Vector3)
Protected.f magSq, oneOverMag
magSq = *V\x * *V\x + *V\y * *V\y + *V\z * *V\z
If magsq > 0
oneOverMag = 1.0 / Sqr(magSq)
*V\x * oneOverMag
*V\y * oneOverMag
*V\z * oneOverMag
EndIf
EndProcedure
Procedure.f QuaternionNormalise(*Q.Quaternion)
Protected.f magSq, oneOverMag
magSq = *Q\w**Q\w+*Q\x**Q\x+*Q\y**Q\y+*Q\z**Q\z
oneOverMag = 1.0 / Sqr(magSq)
*Q\w * oneOverMag
*Q\x * oneOverMag
*Q\y * oneOverMag
*Q\z * oneOverMag
EndProcedure
Procedure.f DotProduct(*V1.Vector3, *V2.Vector3)
ProcedureReturn *V1\x * *V2\x + *V1\y * *V2\y + *V1\z * *V2\z
EndProcedure
Procedure.f QuaternionDot(*Q.Quaternion, *rkQ.Quaternion)
ProcedureReturn *Q\w**rkQ\w+*Q\x**rkQ\x+*Q\y**rkQ\y+*Q\z**rkQ\z
EndProcedure
Procedure FromRotationMatrix(*Q.Quaternion, *kRot.Matrix3)
; Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
; article "Quaternion Calculus and Fast Animation".
fTrace.f = *kRot\m[0]\n[0]+*kRot\m[1]\n[1]+*kRot\m[2]\n[2]
fRoot.f
If fTrace > 0.0
; |w| > 1/2, may As well choose w > 1/2
fRoot =Sqr(fTrace + 1.0); 2w
*Q\w = 0.5*fRoot
fRoot = 0.5/fRoot; 1/(4w)
*Q\x = (*kRot\m[2]\n[1]-*kRot\m[1]\n[2])*fRoot;
*Q\y = (*kRot\m[0]\n[2]-*kRot\m[2]\n[0])*fRoot;
*Q\z = (*kRot\m[1]\n[0]-*kRot\m[0]\n[1])*fRoot;
Else
; |w| <= 1/2
Dim s_iNext(2)
s_iNext(0) = 1
s_iNext(1) = 2
s_iNext(2) = 0
i = 0
If *kRot\m[1]\n[1] > *kRot\m[0]\n[0]
i = 1
EndIf
If *kRot\m[2]\n[2] > *kRot\m[i]\n[i]
i = 2
EndIf
j = s_iNext(i)
k = s_iNext(j)
fRoot =Sqr(*kRot\m[i]\n[i]-*kRot\m[j]\n[j]-*kRot\m[k]\n[k] + 1.0)
Dim *apkQuat.Float(2)
*apkQuat(0) = @*Q\x
*apkQuat(1) = @*Q\y
*apkQuat(2) = @*Q\z
*apkQuat(i)\f = 0.5*fRoot
fRoot = 0.5/fRoot
*Q\w = (*kRot\m[k]\n[j]-*kRot\m[j]\n[k])*fRoot
*apkQuat(j)\f = (*kRot\m[j]\n[i]+*kRot\m[i]\n[j])*fRoot
*apkQuat(k)\f = (*kRot\m[k]\n[i]+*kRot\m[i]\n[k])*fRoot
EndIf
EndProcedure
Procedure QuaternionFromAxes(*Q.Quaternion, *xaxis.Vector3, *yaxis.Vector3, *zaxis.Vector3)
Protected kRot.Matrix3
kRot\m[0]\n[0] = *xaxis\x
kRot\m[1]\n[0] = *xaxis\y
kRot\m[2]\n[0] = *xaxis\z
kRot\m[0]\n[1] = *yaxis\x
kRot\m[1]\n[1] = *yaxis\y
kRot\m[2]\n[1] = *yaxis\z
kRot\m[0]\n[2] = *zaxis\x
kRot\m[1]\n[2] = *zaxis\y
kRot\m[2]\n[2] = *zaxis\z
FromRotationMatrix(*Q, @kRot)
EndProcedure
Procedure Slerp(*t.Quaternion, fT.f, *rkP.Quaternion, *rkQ.Quaternion, shortestPath)
msEpsilon = 1e-03
fCos.f = QuaternionDot(*rkP, *rkQ)
rkT.Quaternion
; Do we need To invert rotation?
If Bool((fCos < 0.0) And shortestPath)
fCos = -fCos
rkT\w = -*rkQ\w
rkT\x = -*rkQ\x
rkT\y = -*rkQ\y
rkT\z = -*rkQ\z
Else
rkT\w = *rkQ\w
rkT\x = *rkQ\x
rkT\y = *rkQ\y
rkT\z = *rkQ\z
EndIf
If (Abs(fCos) < 1 - msEpsilon)
; Standard Case (slerp)
fSin.f = Sqr(1 - (fCos*fCos))
fAngle.f =ATan2(fSin, fCos)
fInvSin.f = 1.0 / fSin;
fCoeff0.f = Sin((1.0 - fT) * fAngle) * fInvSin
fCoeff1.f = Sin(fT * fAngle) * fInvSin
*t\w = fCoeff0 * *rkP\w + fCoeff1 * rkT\w
*t\x = fCoeff0 * *rkP\x + fCoeff1 * rkT\x
*t\y = fCoeff0 * *rkP\y + fCoeff1 * rkT\y
*t\z = fCoeff0 * *rkP\z + fCoeff1 * rkT\z
Else
; There are two situations:
; 1. "rkP" And "rkQ" are very close (fCos ~= +1), so we can do a linear
; interpolation safely.
; 2. "rkP" And "rkQ" are almost inverse of each other (fCos ~= -1), there
; are an infinite number of possibilities interpolation. but we haven't
; have method To fix this Case, so just use linear interpolation here.
*t\w = (1.0 - fT) * *rkP\w + fT * rkT\w
*t\x = (1.0 - fT) * *rkP\x + fT * rkT\x
*t\y = (1.0 - fT) * *rkP\y + fT * rkT\y
*t\z = (1.0 - fT) * *rkP\z + fT * rkT\z
; taking the complement requires renormalisation
QuaternionNormalise(*t)
EndIf
EndProcedure
Procedure OnGround(*Entity.s_Entity)
Protected.Quaternion S, Q
Protected.Vector3 xaxis, yaxis, zaxis
With *Entity
Result = RayCollide(EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), EntityX(\EntityBody), EntityY(\EntityBody)-7, EntityZ(\EntityBody))
;CreateLine3D(20,EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), $FFFF, EntityX(\EntityBody), EntityY(\EntityBody)-7, EntityZ(\EntityBody), $FFFF)
Delta.f = EntityY(\EntityBody) - PickY() - \BodyOffsetY
If Result=-1 Or (Result>-1 And (delta >= 1))
ProcedureReturn 0
Else
;CreateLine3D(20,PickX(), PickY(), PickZ(), $FFFF, PickX()+NormalX()*6, PickY()+NormalY()*6, PickZ()+NormalZ()*6, $FFFF)
xaxis\x = NodeX(\Direction) - EntityX(\EntityBody)
xaxis\y = NodeY(\Direction) - EntityY(\EntityBody)
xaxis\z = NodeZ(\Direction) - EntityZ(\EntityBody)
yaxis\x = NormalX()
yaxis\y = NormalY()
yaxis\z = NormalZ()
PRODUIT_VECTORIEL(zaxis, xaxis, yaxis)
PRODUIT_VECTORIEL(xaxis, yaxis, zaxis)
QuaternionFromAxes(@Q, @xaxis, @yaxis, @zaxis)
FetchOrientation(EntityID(\Entity))
S\w = GetW()
S\x = GetX()
S\y = GetY()
S\z = GetZ()
Slerp(@R, 0.05, @S, @Q, 0)
SetOrientation(EntityID(\Entity),r\x, r\y, r\z, r\w)
ProcedureReturn 1
EndIf
EndWith
EndProcedure
Procedure HandleEntity(*Entity.s_Entity)
Protected.f Speed, Speed2, x, y, MouseX, MouseY
Static Jump.f, MemJump.i, Rot.Vector3, Trans.Vector3, Clic
With *Entity
Speed = #PlayerSpeed * \elapsedTime
Speed2 = Speed / 2
If ExamineKeyboard()
If KeyboardReleased(#PB_Key_F5)
WorldDebug(#PB_World_DebugBody)
ElseIf KeyboardReleased(#PB_Key_F6)
WorldDebug(#PB_World_DebugEntity)
ElseIf KeyboardReleased(#PB_Key_F7)
WorldDebug(#PB_World_DebugNone)
EndIf
If KeyboardPushed(\Key\Jump) And OnGround(*Entity)
Jump = 2
MemJump = 1
EndIf
Rot\x * 0.30
Rot\y * 0.30
Rot\z * 0.30
Trans\x * 0.20
Trans\y = Jump
Trans\z * 0.20
If KeyboardPushed(\Key\Up)
Trans\x = Speed
ElseIf KeyboardPushed(\Key\Down)
Trans\x = -Speed2
EndIf
If KeyboardPushed(\Key\Left)
Rot\y + 2 * \elapsedTime
ElseIf KeyboardPushed(\Key\Right)
Rot\y - 2 * \elapsedTime
EndIf
If KeyboardPushed(\Key\StrafeLeft)
Trans\z = -Speed2
ElseIf KeyboardPushed(\Key\StrafeRight)
Trans\z = Speed2
EndIf
If OnGround(*Entity)
Jump = 0
ElseIf MemJump
Jump + 2 * \elapsedTime
If Jump > 15
MemJump = 0
EndIf
Else
Jump - 9
EndIf
EndIf
MoveEntity (\EntityBody, Trans\x, Trans\y, Trans\z, #PB_Local)
RotateEntity(\EntityBody, 0, Rot\y, 0, #PB_Relative)
MoveEntity(\Entity, EntityX(\EntityBody), EntityY(\EntityBody)-\BodyOffsetY, EntityZ(\EntityBody), #PB_Absolute)
EndWith
EndProcedureCode: Select all
xaxis\x = NodeX(\Direction) - EntityX(\Entity)
xaxis\y = NodeY(\Direction) - EntityY(\Entity)
xaxis\z = NodeZ(\Direction) - EntityZ(\Entity)Code: Select all
xaxis\x = NodeX(\Direction) - EntityX(\EntityBody)
xaxis\y = NodeY(\Direction) - EntityY(\EntityBody)
xaxis\z = NodeZ(\Direction) - EntityZ(\EntityBody)yes this is an example, there are still things to do.Edit: oh, and by pressing Space it freezes
Code: Select all
xaxis\x = NodeX(\Direction) - EntityX(\EntityBody)
xaxis\y = NodeY(\Direction) - EntityY(\EntityBody)
xaxis\z = NodeZ(\Direction) - EntityZ(\EntityBody)
yaxis\x = NormalX()
yaxis\y = NormalY()
yaxis\z = NormalZ()
PRODUIT_VECTORIEL(zaxis, xaxis, yaxis)
PRODUIT_VECTORIEL(xaxis, yaxis, zaxis)
QuaternionFromAxes(@Q, @xaxis, @yaxis, @zaxis)Code: Select all
FetchOrientation(EntityID(\Entity))
S\w = GetW()
S\x = GetX()
S\y = GetY()
S\z = GetZ()Code: Select all
Slerp(@R, 0.05, @S, @Q, 0)Code: Select all
;
; ------------------------------------------------------------
;
; PureBasic - Terrain : Physic
;
; (c) 2012 - Fantaisie Software
;
; ------------------------------------------------------------
;
IncludeFile "Screen3DRequester.pb"
#TerrainMiniX = 0
#TerrainMiniY = 0
#TerrainMaxiX = 0
#TerrainMaxiY = 0
#PlayerSpeed = 6
#CameraSpeed = 1
Define.f KeyX, KeyY, MouseX, MouseY, TimeSinceLastFrame
Declare InitBlendMaps()
Structure Vector3
x.f
y.f
z.f
EndStructure
Structure Quaternion
w.f
x.f
y.f
z.f
EndStructure
Structure Colonne3
n.f[3]
EndStructure
Structure Matrix3
m.Colonne3[3]
EndStructure
Structure s_Key
Up.i
Down.i
Left.i
Right.i
StrafeLeft.i
StrafeRight.i
Jump.i
EndStructure
Structure s_Entity
Entity.i
EntityBody.i
BodyOffsetY.f
elapsedTime.f
Key.s_Key
MainNode.i
SightNode.i
Direction.i
EndStructure
Structure s_Camera
Camera.i
Tightness.f
CameraNode.i
TargetNode.i
EndStructure
Macro GetNodePosition(Position, Node)
Position\x = NodeX(Node)
Position\y = NodeY(Node)
Position\z = NodeZ(Node)
EndMacro
Macro SubVector3(V, V1, V2)
V\x = V1\x - V2\x
V\y = V1\y - V2\y
V\z = V1\z - V2\z
EndMacro
Macro AddVector3(V, V1, V2)
V\x = V1\x + V2\x
V\y = V1\y + V2\y
V\z = V1\z + V2\z
EndMacro
Macro PRODUIT_VECTORIEL(N, V1, V2)
N\x = ((V1\y * V2\z) - (V1\z * V2\y))
N\y = ((V1\z * V2\x) - (V1\x * V2\z))
N\z = ((V1\x * V2\y) - (V1\y * V2\x))
EndMacro
;-Declare
Declare HandleEntity(*Entity.s_Entity)
Declare CameraTrack(*Camera.s_Camera, *Entity.s_Entity)
Declare OnGround(*Entity.s_Entity)
Define Robot.s_Entity
Define Camera.s_Camera
Global R.Quaternion
; OpenGL needs to have CG enabled to work (Linux and OS X have OpenGL by default)
;
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows Or Subsystem("OpenGL")
Flags = #PB_Engine3D_EnableCG
CompilerEndIf
If InitEngine3D(Flags)
InitSprite()
InitKeyboard()
InitMouse()
If Screen3DRequester()
Add3DArchive("Data/Textures/" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Models" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Scripts" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Textures/nvidia" , #PB_3DArchive_FileSystem)
Add3DArchive("Data/Packs/desert.zip", #PB_3DArchive_Zip)
Parse3DScripts()
WorldShadows(#PB_Shadow_Modulative, 200, RGB(120, 120, 120))
MaterialFilteringMode(#PB_Default, #PB_Material_Anisotropic, 8)
;- Light
;
light = CreateLight(#PB_Any ,RGB(185, 185, 185), 4000, 1200, 1000, #PB_Light_Directional)
SetLightColor(light, #PB_Light_SpecularColor, RGB(255*0.4, 255*0.4,255*0.4))
LightDirection(light ,0.55, -0.3, -0.75)
AmbientColor(RGB(5, 5,5))
;----------------------------------
;-terrain definition
SetupTerrains(LightID(Light), 300, #PB_Terrain_NormalMapping)
;-initialize terrain
CreateTerrain(0, 513, 1200, 60, 3, "TerrainPhysic", "dat")
;-set all texture will be use when terrrain will be constructed
AddTerrainTexture(0, 0, 10, "dirt_grayrocky_diffusespecular.jpg", "dirt_grayrocky_normalheight.jpg")
AddTerrainTexture(0, 1, 3, "grass_green-01_diffusespecular.jpg", "grass_green-01_normalheight.jpg")
AddTerrainTexture(0, 2, 20, "growth_weirdfungus-03_diffusespecular.jpg", "growth_weirdfungus-03_normalheight.jpg")
;-Construct terrains
For ty = #TerrainMiniY To #TerrainMaxiY
For tx = #TerrainMiniX To #TerrainMaxiX
Imported = DefineTerrainTile(0, tx, ty, "terrain513.png", ty % 2, tx % 2)
Next
Next
BuildTerrain(0)
If Imported = #True
InitBlendMaps()
UpdateTerrain(0)
; If enabled, it will save the terrain as a (big) cache for a faster load next time the program is executed
; SaveTerrain(0, #False)
EndIf
; enable shadow terrain
TerrainRenderMode(0, 0)
;Add Physic
TerrainPhysicBody(0, 0, 0.5)
;Texture
CreateTexture(1, 256, 256)
StartDrawing(TextureOutput(1))
Box(0, 0, 256, 256, $002255)
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, 256, 256, $FFFFFF)
Box(10, 10, 236, 236, $FFFF)
StopDrawing()
;Material
CreateMaterial(0, LoadTexture(0, "r2skin.jpg"))
CreateMaterial(1, TextureID(1))
CreateMaterial(2, LoadTexture(2, "Dirt.jpg"))
CreateMaterial(3, LoadTexture(3, "Wood.jpg"))
GetScriptMaterial(4, "Scene/GroundBlend")
;Robot
CreateSphere(0, 1)
Rob = LoadMesh(#PB_Any, "Robot.mesh")
CreateEntity (0, MeshID(Rob), #PB_Material_None)
ScaleEntity(0, 0.1, 0.1, 0.1)
StartEntityAnimation(0, "Walk")
;Robot Body
CreateEntity(1, MeshID(0), #PB_Material_None, 0, 426, 0)
HideEntity(1, 1)
;Body
EntityPhysicBody(1, #PB_Entity_SphereBody, 1, 0, 0.5)
; Skybox
SkyBox("desert07.jpg")
;
With Robot
\Entity = 0
\EntityBody = 1
\BodyOffsetY = 1
\Key\Down = #PB_Key_Down
\Key\Left = #PB_Key_Left
\Key\Right = #PB_Key_Right
\Key\Up = #PB_Key_Up
\Key\StrafeLeft = #PB_Key_X
\Key\StrafeRight = #PB_Key_C
\Key\Jump = #PB_Key_Space
;\MainNode = CreateNode(#PB_Any) ; Entity position
\Direction = CreateNode(#PB_Any, 1, 0, 0) ; For cameraLookAt
\SightNode = CreateNode(#PB_Any, 12, 2, 0) ; For cameraLookAt
AttachEntityObject(\EntityBody, "", NodeID(\Direction))
AttachEntityObject(\EntityBody, "", NodeID(\SightNode))
;AttachNodeObject(\MainNode, EntityID(\Entity))
EndWith
;- Camera
;
CreateCamera(0, 0, 0, 100, 100)
CameraBackColor(0, RGB(5, 5, 10))
;==================================
; create material
Red = GetScriptMaterial(#PB_Any, "Color/Red")
Blue = GetScriptMaterial(#PB_Any, "Color/Blue")
Yellow = GetScriptMaterial(#PB_Any, "Color/Yellow")
Green = GetScriptMaterial(#PB_Any, "Color/Green")
;==================================
; create Sphere
MeshSphere = CreateSphere(#PB_Any, 1.0)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshSphere), MaterialID(Green))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_SphereBody, 1.0)
Next
;==================================
; create Cylinder
MeshCylinder = CreateCylinder(#PB_Any, 1.0, 6)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshCylinder), MaterialID(Red))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_CylinderBody, 1.0, 0, 1)
Next
;==================================
; create Cube
MeshCube = CreateCube(#PB_Any, 3)
For i = 0 To 5
Entity=CreateEntity(#PB_Any, MeshID(MeshCube), MaterialID(Yellow))
MoveEntity(Entity, Random(200)-100, 80, Random(400)-200, #PB_Absolute)
; create bodies
EntityPhysicBody(Entity, #PB_Entity_BoxBody, 1.0)
Next
Repeat
Screen3DEvents()
Robot\elapsedTime = TimeSinceLastFrame
HandleEntity(@Robot)
CameraFollow(0, EntityID(Robot\Entity), -90, EntityY(Robot\Entity) + 10, 25, 0.1, 0.1, 0)
CameraLookAt(0, NodeX(Robot\SightNode), NodeY(Robot\SightNode), NodeZ(Robot\SightNode))
TimeSinceLastFrame = RenderWorld(60) * 40 / 1000
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
End
EndIf
Else
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows Or Subsystem("OpenGL")
;
; Terrain on Linux/OSX and Windows with OpenGL needs CG toolkit from nvidia
; It can be freely downloaded and installed from this site: https://developer.nvidia.com/cg-toolkit-download
;
MessageRequester("Error","Can't initialize engine3D (Please ensures than CG Toolkit from nvidia is correcly installed)")
CompilerElse
MessageRequester("Error","Can't initialize engine3D")
CompilerEndIf
EndIf
Procedure Clamp(*var.float, min.f, max.f)
If *var\f < min
*var\f = min
ElseIf *var\f > max
*var\f = max
EndIf
EndProcedure
Procedure InitBlendMaps()
minHeight1.f = 7
fadeDist1.f = 40
minHeight2.f = 7
fadeDist2.f = 15
For ty = #TerrainMiniY To #TerrainMaxiY
For tx = #TerrainMiniX To #TerrainMaxiX
Size = TerrainTileLayerMapSize(0, tx, ty)
For y = 0 To Size-1
For x = 0 To Size-1
Height.f = TerrainTileHeightAtPosition(0, tx, ty, 1, x, y)
val.f = (Height - minHeight1) / fadeDist1
Clamp(@val, 0, 1)
SetTerrainTileLayerBlend(0, tx, ty, 1, x, y, val)
val.f = (Height - minHeight2) / fadeDist2
Clamp(@val, 0, 1)
SetTerrainTileLayerBlend(0, tx, ty, 2, x, y, val)
Next
Next
UpdateTerrainTileLayerBlend(0, tx, ty, 1)
UpdateTerrainTileLayerBlend(0, tx, ty, 2)
Next
Next
EndProcedure
Procedure Normalize(*V.Vector3)
Protected.f magSq, oneOverMag
magSq = *V\x * *V\x + *V\y * *V\y + *V\z * *V\z
If magsq > 0
oneOverMag = 1.0 / Sqr(magSq)
*V\x * oneOverMag
*V\y * oneOverMag
*V\z * oneOverMag
EndIf
EndProcedure
Procedure.f QuaternionNormalise(*Q.Quaternion)
Protected.f magSq, oneOverMag
magSq = *Q\w**Q\w+*Q\x**Q\x+*Q\y**Q\y+*Q\z**Q\z
oneOverMag = 1.0 / Sqr(magSq)
*Q\w * oneOverMag
*Q\x * oneOverMag
*Q\y * oneOverMag
*Q\z * oneOverMag
EndProcedure
Procedure.f DotProduct(*V1.Vector3, *V2.Vector3)
ProcedureReturn *V1\x * *V2\x + *V1\y * *V2\y + *V1\z * *V2\z
EndProcedure
Procedure.f QuaternionDot(*Q.Quaternion, *rkQ.Quaternion)
ProcedureReturn *Q\w**rkQ\w+*Q\x**rkQ\x+*Q\y**rkQ\y+*Q\z**rkQ\z
EndProcedure
Procedure FromRotationMatrix(*Q.Quaternion, *kRot.Matrix3)
; Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
; article "Quaternion Calculus and Fast Animation".
fTrace.f = *kRot\m[0]\n[0]+*kRot\m[1]\n[1]+*kRot\m[2]\n[2]
fRoot.f
If fTrace > 0.0
; |w| > 1/2, may As well choose w > 1/2
fRoot =Sqr(fTrace + 1.0); 2w
*Q\w = 0.5*fRoot
fRoot = 0.5/fRoot; 1/(4w)
*Q\x = (*kRot\m[2]\n[1]-*kRot\m[1]\n[2])*fRoot;
*Q\y = (*kRot\m[0]\n[2]-*kRot\m[2]\n[0])*fRoot;
*Q\z = (*kRot\m[1]\n[0]-*kRot\m[0]\n[1])*fRoot;
Else
; |w| <= 1/2
Dim s_iNext(2)
s_iNext(0) = 1
s_iNext(1) = 2
s_iNext(2) = 0
i = 0
If *kRot\m[1]\n[1] > *kRot\m[0]\n[0]
i = 1
EndIf
If *kRot\m[2]\n[2] > *kRot\m[i]\n[i]
i = 2
EndIf
j = s_iNext(i)
k = s_iNext(j)
fRoot =Sqr(*kRot\m[i]\n[i]-*kRot\m[j]\n[j]-*kRot\m[k]\n[k] + 1.0)
Dim *apkQuat.Float(2)
*apkQuat(0) = @*Q\x
*apkQuat(1) = @*Q\y
*apkQuat(2) = @*Q\z
*apkQuat(i)\f = 0.5*fRoot
fRoot = 0.5/fRoot
*Q\w = (*kRot\m[k]\n[j]-*kRot\m[j]\n[k])*fRoot
*apkQuat(j)\f = (*kRot\m[j]\n[i]+*kRot\m[i]\n[j])*fRoot
*apkQuat(k)\f = (*kRot\m[k]\n[i]+*kRot\m[i]\n[k])*fRoot
EndIf
EndProcedure
Procedure QuaternionFromAxes(*Q.Quaternion, *xaxis.Vector3, *yaxis.Vector3, *zaxis.Vector3)
Protected kRot.Matrix3
kRot\m[0]\n[0] = *xaxis\x
kRot\m[1]\n[0] = *xaxis\y
kRot\m[2]\n[0] = *xaxis\z
kRot\m[0]\n[1] = *yaxis\x
kRot\m[1]\n[1] = *yaxis\y
kRot\m[2]\n[1] = *yaxis\z
kRot\m[0]\n[2] = *zaxis\x
kRot\m[1]\n[2] = *zaxis\y
kRot\m[2]\n[2] = *zaxis\z
FromRotationMatrix(*Q, @kRot)
EndProcedure
Procedure Slerp(*t.Quaternion, fT.f, *rkP.Quaternion, *rkQ.Quaternion, shortestPath)
msEpsilon = 1e-03
fCos.f = QuaternionDot(*rkP, *rkQ)
rkT.Quaternion
; Do we need To invert rotation?
If Bool((fCos < 0.0) And shortestPath)
fCos = -fCos
rkT\w = -*rkQ\w
rkT\x = -*rkQ\x
rkT\y = -*rkQ\y
rkT\z = -*rkQ\z
Else
rkT\w = *rkQ\w
rkT\x = *rkQ\x
rkT\y = *rkQ\y
rkT\z = *rkQ\z
EndIf
If (Abs(fCos) < 1 - msEpsilon)
; Standard Case (slerp)
fSin.f = Sqr(1 - (fCos*fCos))
fAngle.f =ATan2(fSin, fCos)
fInvSin.f = 1.0 / fSin;
fCoeff0.f = Sin((1.0 - fT) * fAngle) * fInvSin
fCoeff1.f = Sin(fT * fAngle) * fInvSin
*t\w = fCoeff0 * *rkP\w + fCoeff1 * rkT\w
*t\x = fCoeff0 * *rkP\x + fCoeff1 * rkT\x
*t\y = fCoeff0 * *rkP\y + fCoeff1 * rkT\y
*t\z = fCoeff0 * *rkP\z + fCoeff1 * rkT\z
Else
; There are two situations:
; 1. "rkP" And "rkQ" are very close (fCos ~= +1), so we can do a linear
; interpolation safely.
; 2. "rkP" And "rkQ" are almost inverse of each other (fCos ~= -1), there
; are an infinite number of possibilities interpolation. but we haven't
; have method To fix this Case, so just use linear interpolation here.
*t\w = (1.0 - fT) * *rkP\w + fT * rkT\w
*t\x = (1.0 - fT) * *rkP\x + fT * rkT\x
*t\y = (1.0 - fT) * *rkP\y + fT * rkT\y
*t\z = (1.0 - fT) * *rkP\z + fT * rkT\z
; taking the complement requires renormalisation
QuaternionNormalise(*t)
EndIf
EndProcedure
Procedure OnGround(*Entity.s_Entity)
Protected.Quaternion S, Q
Protected.Vector3 xaxis, yaxis, zaxis
With *Entity
Result = RayCollide(EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), EntityX(\EntityBody), EntityY(\EntityBody)-7, EntityZ(\EntityBody))
;CreateLine3D(20,EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), $FFFF, EntityX(\EntityBody), EntityY(\EntityBody)-7, EntityZ(\EntityBody), $FFFF)
Delta.f = EntityY(\EntityBody) - PickY() - \BodyOffsetY
If Result=-1 Or (Result>-1 And (delta >= 1))
ProcedureReturn 0
Else
xaxis\x = NodeX(\Direction) - EntityX(\EntityBody)
xaxis\y = NodeY(\Direction) - EntityY(\EntityBody)
xaxis\z = NodeZ(\Direction) - EntityZ(\EntityBody)
yaxis\x = NormalX()
yaxis\y = NormalY()
yaxis\z = NormalZ()
PRODUIT_VECTORIEL(zaxis, xaxis, yaxis)
PRODUIT_VECTORIEL(xaxis, yaxis, zaxis)
CreateLine3D(20,EntityX(\EntityBody), EntityY(\EntityBody), EntityZ(\EntityBody), $FFFF, EntityX(\EntityBody)+xaxis\x*3, EntityY(\EntityBody)+xaxis\y*3, EntityZ(\EntityBody)+xaxis\z*3, $FFFF)
QuaternionFromAxes(@Q, @xaxis, @yaxis, @zaxis)
FetchOrientation(EntityID(\Entity))
S\w = GetW()
S\x = GetX()
S\y = GetY()
S\z = GetZ()
Slerp(@R, 0.05, @S, @Q, 0)
SetOrientation(EntityID(\Entity),r\x, r\y, r\z, r\w)
ProcedureReturn 1
EndIf
EndWith
EndProcedure
Procedure HandleEntity(*Entity.s_Entity)
Protected.f Speed, Speed2, x, y, MouseX, MouseY
Static Jump.f, MemJump.i, Rot.Vector3, Trans.Vector3, Clic
With *Entity
Speed = #PlayerSpeed * \elapsedTime
Speed2 = Speed / 2
If ExamineKeyboard()
If KeyboardReleased(#PB_Key_F5)
WorldDebug(#PB_World_DebugBody)
ElseIf KeyboardReleased(#PB_Key_F6)
WorldDebug(#PB_World_DebugEntity)
ElseIf KeyboardReleased(#PB_Key_F7)
WorldDebug(#PB_World_DebugNone)
EndIf
If KeyboardPushed(\Key\Jump) And OnGround(*Entity)
Jump = 90
MemJump = 1
EndIf
Rot\x * 0.30
Rot\y * 0.30
Rot\z * 0.30
Trans\x * 0.20
Trans\y = Sin(Radian(Jump)) * 5
Trans\z * 0.20
If KeyboardPushed(\Key\Up)
Trans\x = Speed
ElseIf KeyboardPushed(\Key\Down)
Trans\x = -Speed2
EndIf
If KeyboardPushed(\Key\Left)
Rot\y + 2 * \elapsedTime
ElseIf KeyboardPushed(\Key\Right)
Rot\y - 2 * \elapsedTime
EndIf
If KeyboardPushed(\Key\StrafeLeft)
Trans\z = -Speed2
ElseIf KeyboardPushed(\Key\StrafeRight)
Trans\z = Speed2
EndIf
OnGround = OnGround(*Entity)
If OnGround And MemJump = 0
MoveEntity (\EntityBody, EntityX(\EntityBody), TerrainHeight(0, EntityX(\EntityBody), EntityZ(\EntityBody))+1,EntityZ(\EntityBody),#PB_Absolute)
ElseIf MemJump
Jump - 9 * \elapsedTime
If Jump < -90
Jump = -90
EndIf
If OnGround And Jump < 0
MemJump = 0
Jump = 0
EndIf
Else
MoveEntity (\EntityBody, EntityX(\EntityBody), TerrainHeight(0, EntityX(\EntityBody), EntityZ(\EntityBody))+1,EntityZ(\EntityBody),#PB_Absolute)
EndIf
EndIf
MoveEntity (\EntityBody, Trans\x,Trans\y, Trans\z, #PB_Local)
RotateEntity(\EntityBody, 0, Rot\y, 0, #PB_Relative)
MoveEntity(\Entity, EntityX(\EntityBody), EntityY(\EntityBody)-\BodyOffsetY, EntityZ(\EntityBody), #PB_Absolute)
EndWith
EndProcedure