
Pour tester copiez le code dans le répertoire PureBasic\Examples\3D
Touches [F2]/[F3]/[F4] pour changer le point de vue de la caméra. [F4] est plus efficace quand la chenille grandit.
Code : Tout sélectionner
IncludeFile #PB_Compiler_Home + "Examples/3D/Screen3DRequester.pb"
Enumeration
#ThirdPersonChase
#ThirdPersonFixed
#TopView
EndEnumeration
#Nb = 100
#Size = 6
#PlayerSpeed = 0.1
Structure Vector3
x.f
y.f
z.f
EndStructure
Structure s_Key
Left.i
Right.i
EndStructure
Structure s_Item
Attached.i
Entity.i
MainNode.i
SecondNode.i
forward.i
EndStructure
Structure s_Head
Item.s_Item
LastItem.i
Key.s_Key
SightNode.i
CameraNode.i
DirectionNode.i
Offset.Vector3
EndStructure
Structure s_Camera
Camera.i
Mode.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 SetVector3(V, xx, yy, zz)
V\x = xx
V\y = yy
V\z = zz
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 SubVector3(V, V1, V2)
V\x = V1\x - V2\x
V\y = V1\y - V2\y
V\z = V1\z - V2\z
EndMacro
Macro NodeOnTerrain(p, Node)
p\x = NodeX(Node)
p\z = NodeZ(Node)
p\y = TerrainHeight(0, p\x, p\z) + #Size
MoveNode(Node, p\x, p\y, p\z, #PB_Absolute)
EndMacro
Define camera.s_Camera
Define p.Vector3
Define Head.s_Head
Global Dim Item.s_Item(#Nb)
Global NewList Chenille.i() ; Stock l'index du tableau
Global Speed.f
#CameraSpeed = 1
#TerrainMiniX = 0
#TerrainMiniY = 0
#TerrainMaxiX = 0
#TerrainMaxiY = 0
;-Declare
Declare HandleEntity(*Head.s_Head)
Declare CameraMode(*Camera.s_Camera, *Head.s_Head)
Declare CameraTrack(*Camera.s_Camera, *Head.s_Head)
Declare CameraInstantUpdate(*Camera.s_Camera, *CameraPosition.Vector3, *TargetPosition.Vector3)
Declare CameraUpdate(*Camera.s_Camera, *CameraPosition.Vector3, *TargetPosition.Vector3)
Declare.f Distance(*v1.Vector3, *v2.Vector3)
Declare MoveItem()
Declare TestItem(*Head.s_Head)
Declare InitBlendMaps()
Declare Clamp(*var.float, min.f, max.f)
; 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(3)
InitSprite()
InitKeyboard()
InitMouse()
If Screen3DRequester()
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures/nvidia", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/GUI", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Packs/desert.zip", #PB_3DArchive_Zip)
Parse3DScripts()
WorldShadows(#PB_Shadow_Modulative, -1, RGB(127, 127, 127))
;- Light
;
light = CreateLight(#PB_Any ,RGB(185, 185, 185), 4000, 1200, 1000, #PB_Light_Directional)
SetLightColor(light, #PB_Light_SpecularColor, RGB(255, 255,255))
LightDirection(light ,0.55, -0.3, -0.75)
AmbientColor(RGB(5, 5,5))
;----------------------------------
; terrain definition
SetupTerrains(LightID(Light), 3000, #PB_Terrain_NormalMapping)
; initialize terrain
CreateTerrain(0, 513, 12000, 600, 3, "Terrain04", "Dat")
; set all texture will be use when terrrain will be constructed
AddTerrainTexture(0, 0, 100, "dirt_grayrocky_diffusespecular.jpg", "dirt_grayrocky_normalheight.jpg")
AddTerrainTexture(0, 1, 30, "grass_green-01_diffusespecular.jpg", "grass_green-01_normalheight.jpg")
AddTerrainTexture(0, 2, 200, "growth_weirdfungus-03_diffusespecular.jpg", "growth_weirdfungus-03_normalheight.jpg")
;- define 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)
;SaveTerrain(0, #False)
EndIf
; SkyBox
;
SkyBox("desert07.jpg")
;- Materials
;
CreateMaterial(0, LoadTexture(0, "Wood.jpg"))
GetScriptMaterial(1, "SphereMap/SphereMappedRustySteel")
CreateMaterial(2, LoadTexture(2, "Dirt.jpg"))
GetScriptMaterial(3, "Scene/GroundBlend")
;- Head
;
CreateSphere(1, #Size)
With Head
\Item\Entity = CreateEntity(#PB_Any, MeshID(1), MaterialID(1))
\Key\Left = #PB_Key_Left
\Key\Right = #PB_Key_Right
\Offset\x = 0
\Offset\y = 50 ; Offset could be needed for FirstPerson
\Offset\z = 130
; Entity use 5 nodes
\Item\MainNode=CreateNode(#PB_Any, 0, #Size, 0) ; Entity position
\Item\SecondNode=CreateNode(#PB_Any, 0, 0, 2 * #Size)
\DirectionNode=CreateNode(#PB_Any, 0, 0, -1) ; Direction normalized
\SightNode=CreateNode(#PB_Any, 0, 20, -120) ; For cameraLookAt
\CameraNode=CreateNode(#PB_Any, 0, 100, 140) ; Camera position
CopyStructure(Head\Item, Item(0), s_Item)
\LastItem = 0
AttachNodeObject(\Item\MainNode, NodeID(\SightNode))
AttachNodeObject(\Item\MainNode, NodeID(\CameraNode))
AttachNodeObject(\Item\MainNode, NodeID(\DirectionNode))
AttachNodeObject(\Item\MainNode, NodeID(\Item\SecondNode))
AttachNodeObject(\Item\MainNode, EntityID(\Item\Entity))
NodeOnTerrain(p, \Item\MainNode)
EndWith
;- Item
;
For i=1 To #Nb
With Item(i)
\Entity = CreateEntity(#PB_Any, MeshID(1), MaterialID(1))
; Entity use 2 nodes
\MainNode=CreateNode(#PB_Any, Random(6000)-3000, #Size, Random(6000)-3000) ; Entity position
\SecondNode=CreateNode(#PB_Any, 0, 0, 2 * #Size) ; Direction normalized
AttachNodeObject(\MainNode, NodeID(\SecondNode))
AttachNodeObject(\MainNode, EntityID(\Entity))
NodeOnTerrain(p, \MainNode)
EndWith
Next
;- Camera
;
CreateCamera(0, 0, 0, 100, 100)
With Camera
\Camera = 0
\Mode = -1
\Tightness = 0.01
; Camera use 2 nodes
\CameraNode = CreateNode(#PB_Any, -3000, 700, 0) ; Camera position
\TargetNode = CreateNode(#PB_Any) ; For cameraLookAt
AttachNodeObject(\CameraNode, CameraID(\Camera))
EndWith
Repeat
Screen3DEvents()
If ExamineKeyboard()
CameraMode(@Camera, @Head)
HandleEntity(@Head)
EndIf
TestItem(@Head)
MoveItem()
CameraTrack(@Camera, @Head)
Speed.f = RenderWorld() * #PlayerSpeed
Screen3DStats()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
End
EndIf
Else
MessageRequester("Error","Can't initialize engine3D")
EndIf
Procedure InitBlendMaps()
minHeight1.f = 70
fadeDist1.f = 40
minHeight2.f = 70
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 Clamp(*var.float, min.f, max.f)
If *var\f < min
*var\f = min
ElseIf *var\f > max
*var\f = max
EndIf
EndProcedure
Procedure.f Distance(*v1.Vector3, *v2.Vector3)
ProcedureReturn Sqr((*v1\x-*v2\x)*(*v1\x-*v2\x)+(*v1\y-*v2\y)*(*v1\y-*v2\y)+(*v1\z-*v2\z)*(*v1\z-*v2\z))
EndProcedure
Procedure MoveItem()
Protected.Vector3 d, p, v1, v2
Protected Dist.f
ForEach Chenille()
item = Chenille()
forward = Item(item)\forward
GetNodePosition(v1, Item(item)\MainNode)
GetNodePosition(d, Item(forward)\MainNode)
Dist = (1.8 * #Size) - Distance(@v1, @d)
NodeLookAt(Item(item)\MainNode, d\x, d\y, d\z)
MoveNode(Item(item)\MainNode, 0, 0, Dist, #PB_Local)
NodeOnTerrain(p, Item(item)\MainNode)
Next
EndProcedure
Procedure TestItem(*Head.s_Head)
Protected.Vector3 v1, v2, d, p
For i = 1 To #Nb
If Not Item(i)\Attached
GetNodePosition(v1, *Head\Item\MainNode)
GetNodePosition(v2, Item(i)\MainNode)
If Distance(@v1, @v2) < 2 * #Size
AddElement(Chenille())
Chenille() = i
Item(i)\forward = *Head\LastItem
GetNodePosition(p, Item(*Head\LastItem)\SecondNode)
GetNodePosition(d, Item(*Head\LastItem)\MainNode)
MoveNode(Item(i)\MainNode, p\x, p\y, p\z, #PB_Absolute)
NodeLookAt(Item(i)\MainNode, d\x, d\y, d\z)
*Head\LastItem = i
Item(i)\Attached = #True
EndIf
EndIf
Next
EndProcedure
Procedure HandleEntity( *Head.s_Head)
Protected.Vector3 PosMain, PosDir , p
Protected Node
With *Head
MoveNode(\Item\MainNode, 0, 0, -Speed, #PB_Local)
NodeOnTerrain(p, \Item\MainNode)
If KeyboardPushed(\Key\Left)
RotateNode(\Item\MainNode, 0,Speed, 0, #PB_Relative)
ElseIf KeyboardPushed(\Key\Right)
RotateNode(\Item\MainNode, 0, -Speed, 0, #PB_Relative)
EndIf
EndWith
EndProcedure
Procedure CameraMode(*Camera.s_Camera, *Head.s_Head)
Protected.Vector3 CameraPosition, TargetPosition, Temp
If KeyboardReleased(#PB_Key_F2) Or *Camera\Mode = -1
*Camera\Mode = #ThirdPersonChase
HideEntity(*Head\Item\Entity, #False)
GetNodePosition(CameraPosition, *Head\CameraNode)
GetNodePosition(TargetPosition, *Head\SightNode)
CameraInstantUpdate(*Camera, @CameraPosition, @TargetPosition)
*Camera\Tightness = 0.01
ElseIf KeyboardReleased(#PB_Key_F3)
*Camera\Mode = #ThirdPersonFixed
HideEntity(*Head\Item\Entity, #False)
SetVector3(CameraPosition, 0, TerrainHeight(0, 0, 0) + 200, 0)
GetNodePosition(TargetPosition, *Head\SightNode)
CameraInstantUpdate(*Camera, @CameraPosition, @TargetPosition)
*Camera\Tightness = 0.01
ElseIf KeyboardReleased(#PB_Key_F4)
*Camera\Mode = #TopView
HideEntity(*Head\Item\Entity, #True)
GetNodePosition(CameraPosition, Item(*Head\LastItem)\MainNode)
CameraPosition\y + 200
GetNodePosition(TargetPosition, *Head\SightNode)
CameraInstantUpdate(*Camera, @CameraPosition, @TargetPosition)
*Camera\Tightness = 1
EndIf
EndProcedure
Procedure CameraTrack(*Camera.s_Camera, *Head.s_Head)
Protected.Vector3 CameraPosition, TargetPosition, Temp
Select *Camera\Mode
Case #ThirdPersonChase
GetNodePosition(CameraPosition, *Head\CameraNode)
GetNodePosition(TargetPosition, *Head\SightNode)
CameraUpDate(*Camera, @CameraPosition, @TargetPosition)
Case #ThirdPersonFixed
SetVector3(CameraPosition, 0, TerrainHeight(0, 0, 0) + 200, 0)
GetNodePosition(TargetPosition, *Head\SightNode)
CameraUpDate(*Camera, @CameraPosition, @TargetPosition)
Case #TopView
GetNodePosition(CameraPosition, Item(*Head\LastItem)\MainNode)
CameraPosition\y + 200
GetNodePosition(TargetPosition, *Head\Item\MainNode)
CameraUpDate(*Camera, @CameraPosition, @TargetPosition)
EndSelect
EndProcedure
Procedure CameraInstantUpdate(*Camera.s_Camera, *CameraPosition.Vector3, *TargetPosition.Vector3)
Protected V1.Vector3, V2.Vector3
MoveNode(*Camera\CameraNode, *CameraPosition\x, *CameraPosition\y, *CameraPosition\z, #PB_Absolute)
MoveNode(*Camera\TargetNode, *TargetPosition\x, *TargetPosition\y, *TargetPosition\z, #PB_Absolute)
CameraLookAt(*Camera\Camera, NodeX(*Camera\TargetNode), NodeY(*Camera\TargetNode), NodeZ(*Camera\TargetNode))
EndProcedure
Procedure CameraUpdate(*Camera.s_Camera, *CameraPosition.Vector3, *TargetPosition.Vector3)
Protected V1.Vector3, V2.Vector3
V1\x = (*CameraPosition\x - NodeX(*Camera\CameraNode)) * *Camera\Tightness
V1\y = (*CameraPosition\y - NodeY(*Camera\CameraNode)) * *Camera\Tightness
v1\z = (*CameraPosition\z - NodeZ(*Camera\CameraNode)) * *Camera\Tightness
MoveNode(*Camera\CameraNode, V1\x, V1\y, V1\z)
V2\x = (*TargetPosition\x - NodeX(*Camera\TargetNode)) * *Camera\Tightness
V2\y = (*TargetPosition\y - NodeY(*Camera\TargetNode)) * *Camera\Tightness
V2\z = (*TargetPosition\z - NodeZ(*Camera\TargetNode)) * *Camera\Tightness
MoveNode(*Camera\TargetNode, V2\x, V2\y, V2\z)
CameraLookAt(*Camera\Camera, NodeX(*Camera\TargetNode), NodeY(*Camera\TargetNode), NodeZ(*Camera\TargetNode))
EndProcedure