Main Menu

3D City Scape

Started by kevin, December 01, 2007, 10:44:02 PM

Previous topic - Next topic

kevin

3D City Scape

  This example is of a 3D city scape that's generated in code.   The example uses the Sprite Entity feature of PB1.7x combined and Draw Perspective Sprite command to render a 3D scene.   



Screen Shots

See Screen Shots




Code

  This code will work in PBV1.70 revisions (with perspective errors) but was written using PB1.71f.



; Open a 800*600*32 screen in FullScreen with Z buffer support.
OpenScreen 800,600,32,PBscreenmode_FullScreenZ

screenvsync on

; Make the Random Grass texture
Grass=MakeGrass(1024,56)
Wall=MakeWall(256,512,56)



; The Size (along edges) of the Terrain Mesh
TerrainSize=96

; Create the a Sprite With a terrain like mesh 
terrain= MakeTerrainSprite(Grass,rnd(0),rnd(0),TerrainSize)

; Set the Sprite Rotation Mode to 3D (XYZ mode()
SpriteRotationMode terrain,0

; Position the Sprite in 3D space
positionspritexyz terrain,0,0000,00

; Enable Back faces culling so Polygons facing away from the camera won't be drawn
Spritebackface Terrain,On


Dim Buildings(3500)
For lp=1 to getarrayelements(Buildings(),1)
Buildings(lp)=MakeBuildingSprite(Wall,rndrange(-50000,50000),0000,rndrange(-50000,50000),rndrange(250,1000),rndrange(1000,10000),rndrange(250,1000))
Next

;  Dim PB Camera type
  Dim Camera as PBCamera Pointer
  Camera = new PBCamera

; Camera Position
Camera.pos.X=0.0 
Camera.pos.y=5500.0 
Camera.pos.z=-10000.0


; RotationMode 0= 2d With Perspective down Z axis (z rotation supported Camera.Angle.Z)
; RotationMode 1= 3D ZYX rotation
Camera.RotationMode=1


// Set Camera Projection t
Camera.Projection.x=((GetScreenWidth()/2.0)*1000)/(400)
Camera.Projection.y=((GetScreenHeight()/2.0)*1000)/(400)

// Middle of Camera
Camera.ViewPoint.X=GetScreenWidth()/2.0 
Camera.ViewPoint.y=GetScreenHeight()/2.0 


MillisecondsPerFrame=1000/60

NextFrame=timer()+MillisecondsPerFrame

// Start of Program Main Loop
Do

; Clear the Screen
; Cls rgb(130,140,140)
Cls rgb(30,40,40)


ix=mod(ix+1,getimagewidth(1))

; DRaw the Sprite List from the Camera Viewer Perspectively
DrawPerspectiveSprites Camera


if Timer()>NextFrame

framespast=(timer()-NextFrame)/MillisecondsPerFrame

for lp=1 to framesPast
MouseLookCamera(camera,100)
next
NextFrame=NextFrame+(FramesPast*MillisecondsPerFrame)


endif

; setcursor 0,0

; print fps()
; print framespast
; print "Camera Position"
; print Camera.pos.x
; print Camera.pos.y
; print Camera.pos.z

; print "Camera Projection"
; print Camera.Projection.x
; print Camera.Projection.y

; print "Camera Rotation"
;; print Camera.Angle.x
; print Camera.Angle.y
; print Camera.Angle.z
; print Camera.RotationMode


; drawimage grass,100,100,true
; drawimage wall,00,00,true
Sync

loop 









Function MakeBuildingSprite(ThisIMage,Xpos#,Ypos#,Zpos#,Width#,Height#,Depth#)


; Create the sprite
ThisSprite=NewSprite(Xpos#,Ypos#,ThisIMage)
SpriteDrawMode ThisSprite, 2

PositionSpriteXyz thisSprite,xpos#,ypos#,zpos#

SpriteTransparent ThisSprite,off
TurnSpriteXYZ thissprite,00,00,00

SpriteBackFace ThisSprite,on
SpriteRotationMode ThisSprite,0

; Set Terrain Sprites number of Vertex and Faces
SpriteVertexQuantity thisSprite,8
SpriteFaceQuantity thisSprite,20


HandleX#=Width#/-2
HandleY#=Height#
HandleZ#=Depth#/2

y#=0
for Ylp=0 to 1

X1#=Handlex#
Z1#=Handlez#

X2#=x1#+Width#
Z2#=z1#

X3#=x2#
Z3#=z2#-Depth#

X4#=x1#
Z4#=z3#

PokeSpriteVertex ThisSprite,ThisVertex,X1#,y#,z1#
inc ThisVertex
PokeSpriteVertex ThisSprite,ThisVertex,X2#,y#,z2#
inc ThisVertex
PokeSpriteVertex ThisSprite,ThisVertex,X3#,y#,z3#
inc ThisVertex
PokeSpriteVertex ThisSprite,ThisVertex,X4#,y#,z4#
inc ThisVertex

y#=y#+Height#
next



ThisColour2=rgb(0,0,255)
ThisColour=rndrgb()
;rgb(255,255,255)

; init faces  (UV points U=X in texture space,  V = Y in texture space)
u1#=0
v1#=0

u2#=1
v2#=0

u3#=1
v3#=1

u4#=0
v4#=1


For Vert=0 to 3
PokeSpriteFaceVerts ThisSprite,ThisFace,4
NextVertTop=Vert+5

NextVertBot=Vert+1
if Vert=3
NextVertTop=NextVertTop-4
NextVertBot=NextVertBot-4
endif

PokeSpriteface ThisSprite,ThisFace,0,Vert+4 ,u1#,v1#,ThisColour
PokeSpriteface ThisSprite,ThisFace,1,NextVertTop ,u2#,v2#,ThisColour
PokeSpriteface ThisSprite,ThisFace,2,NextVertBot ,u3#,v3#,ThisColour
PokeSpriteface ThisSprite,ThisFace,3,Vert+0 ,u4#,v4#,ThisColour
inc ThisFace
next


; Set top face
PokeSpriteFaceVerts ThisSprite,ThisFace,4
PokeSpriteface ThisSprite,ThisFace,0,7 ,u1#,v1#,ThisColour
PokeSpriteface ThisSprite,ThisFace,1,6 ,u1#,v1#,ThisColour
PokeSpriteface ThisSprite,ThisFace,2,5 ,u1#,v1#,ThisColour
PokeSpriteface ThisSprite,ThisFace,3,4 ,u1#,v1#,ThisColour
inc ThisFace



;Set the numbner of faces this sprite has
SpriteFaceQuantity thisSprite,ThisFace+1

EndFUnction ThisSPrite





;*=---------------------------------------------------------------------------=*
;                >> Make A Terrain Sprite<<
;*=---------------------------------------------------------------------------=*





Function MakeTerrainSprite(ThisIMage,Xpos#,Ypos#,points)

; Create the sprite
ThisSprite=NewSprite(Xpos#,Ypos#,ThisIMage)
SpriteDrawMode ThisSprite, 2

SpriteTransparent ThisSprite,off
turnspritexyz thissprite,00,00,00

Points2=(points+1)


; Dim an Array to Hold the terraion height map
Dim Matrix#(POints2,points2)

; randomize the heights of each point in the height map
RadomizeHeightMap(Matrix#(),2000)

; smooth out the height map be averageing the points
SmoothHeightMap(Matrix#(),2)

; Set Terrain Sprites number of Vertex and Faces
SpriteVertexQuantity thisSprite,(Points2*POints2)
SpriteFaceQuantity thisSprite,(Points2*Points2)*2


Size=1000
HandleX#=-(((points+1.0)/2.0)*size)
HandleZ#=-(((points+1.0)/2.0)*size)

; init vertex
for Ylp=0 to Points
Zpos#=ylp*Size
for Xlp=0 to Points
Xpos#=Xlp*Size
ThisVertex=(Ylp*(points+1))+xlp
ypos#=Matrix#(xlp,ylp)
PokeSpriteVertex ThisSprite,ThisVertex,Xpos#+HandleX#,Ypos#,Zpos#+HandleZ#
next
next

ThisColour=rgb(255,255,255)

; init faces  (UV points U=X in texture space,  V = Y in texture space)
TUstep#=1.0/(points+1)
Tvstep#=1.0/(points+1)

For Ylp=0 to points-1
For Xlp=0 to points-1

CurrentVertexRow =(Ylp*(points+1))+Xlp
NextVertexRow =CurrentVertexRow+(points+1)

PokeSpriteFaceVerts ThisSprite,ThisFace,3

u1#=Xlp*TUstep#
v1#=Ylp*TVstep#

u2#=(Xlp+1)*TUstep#
v2#=Ylp*TVstep#

u3#=(Xlp+1)*TUstep#
v3#=(Ylp+1)*TVstep#

u4#=(Xlp+0)*TUstep#
v4#=(Ylp+1)*TVstep#

PokeSpriteface ThisSprite,ThisFace,0,CurrentVertexRow+0 ,u1#,v1#,ThisColour
PokeSpriteface ThisSprite,ThisFace,1,CurrentVertexRow+1 ,u2#,v2#,ThisColour
PokeSpriteface ThisSprite,ThisFace,2,NextVertexRow+1 ,u3#,v3#,ThisColour
inc ThisFace

PokeSpriteFaceVerts ThisSprite,ThisFace,3
PokeSpriteface ThisSprite,ThisFace,0,CurrentVertexRow+0 ,u1#,v1#,ThisColour
PokeSpriteface ThisSprite,ThisFace,1,NextVertexRow+1 ,u3#,v3#,ThisColour
PokeSpriteface ThisSprite,ThisFace,2,NextVertexRow ,u4#,v4#,ThisColour
inc ThisFace

Next
Next


;Set the numbner of faces this sprite has
SpriteFaceQuantity thisSprite,ThisFace+1

EndFUnction ThisSPrite




` *=----------------------------------------------------------------=*
`                        >> Randomize HeightMap Array <<
` *=----------------------------------------------------------------=*


Function RadomizeHeightMap(Matrix#(),Height)
Width=getarrayelements(Matrix#(),1)
Depth=getarrayelements(Matrix#(),2)
For Zlp=1 to Depth-2
For Xlp=1 to Width-2
Matrix#(xlp,zlp)=rnd#(Height)
next xlp
next zlp
Endfunction


` *=----------------------------------------------------------------=*
`                    >> Average Matrix Height <<
` *=----------------------------------------------------------------=*





Function SmoothHeightMap(Matrix#(),passes)

Width=getarrayelements(Matrix#(),1)
Depth=getarrayelements(Matrix#(),2)

Dim Temp_HeightMap_Yvalues#(Width,Depth)

For ThisPass=0 To Passes

CopyArray Matrix#(),Temp_HeightMap_Yvalues#()
For Zlp=1 to Depth-1

ZlpF=zlp-1
ZlpB=zlp+1
Width2=Width-1

For Xlp=1 to Width2
xlpL=Xlp-1
xlpR=Xlp+1

yb#=Temp_HeightMap_Yvalues#(xlp,zlp)
yt#=Temp_HeightMap_Yvalues#(xlp,zlpF)
yb#=Temp_HeightMap_Yvalues#(xlp,zlpB)
yl#=Temp_HeightMap_Yvalues#(xlpL,zlp)
yr#=Temp_HeightMap_Yvalues#(xlpR,zlp)

ytl#=Temp_HeightMap_Yvalues#(xlpL,zlpF)
ytr#=Temp_HeightMap_Yvalues#(xlpR,zlpF)
ybl#=Temp_HeightMap_Yvalues#(xlpL,zlpB)
ybr#=Temp_HeightMap_Yvalues#(xlpR,zlpB)

matrix#(xlp,zlp)=(yb#+yt#+yb#+yL#+yr#+ytl#+ytr#+ybl#+ybr#)/9

next xlp
next zlp

next ThisPass
unDim Temp_HeightMap_Yvalues#()

endfunction






Function MouseLookCamera(camera as PBcamera pointer,camspeed#)
static acamx#,acamy#

W=GetScreenWidth()
H=GetScreenHeight()

x1=GetScreenXpos()
    Y1=GetScreenYpos()
x2=x1+w
y2=y1+h


MMX#=MouseMoveX()
MMY#=MouseMoveY()

x#=x1+MouseX()
y#=y1+MouseY()


flag=0
If x#=<(x1+75) Then x#=x1+(w/2): flag=1
If x#=>(x2-75) And flag=0 Then x#=x1+(w/2): flag=1

If y#=<(y1+75) Then y#=y1+(h/2): flag=1
If y#=>(y2-75) Then y#=y1+(h/2): flag=1


If flag=1
SetMouse x#,y#
MMX2#=MouseMoveX()
MMY2#=MouseMoveY()
if pbdebugmode=0
SetMouse x#,y#
endif
EndIf


camf#=0
acamx#=WrapAngle(acamx#,mmy#*0.7)
acamy#=WrapAngle(acamy#,mmx#*0.7)

Camera.Angle.x#=CurveAngle(acamx#,Camera.Angle.x#,6.2)
Camera.Angle.y#=CurveAngle(acamy#,Camera.Angle.y#,6.2)

If KeyState(200 ) Then camf#=camf#+camspeed#
If KeyState(208) Then camf#=camf#-camspeed#

If camf#<>0
movementx#,movementy#,movementz#=CalcMovement(acamx#,acamy#,0.0,Camf#)

x#=Camera.pos.x#+movementx#
y#=Camera.pos.y#+movementy#
z#=Camera.pos.z#+movementz#

; clip the camera to 20 on y axis
; If y#<100 Then y#=100
Camera.pos.x=x#
Camera.pos.y=y#
Camera.pos.z=z#

EndIf
EndFunction






Function CalcMovement(Anglex#,angley#,anglez#,Speed#)
` invert angles
anglex#=WrapAngle(360,-anglex#)
angley#=WrapAngle(90,-angley#)
anglez#=WrapAngle(360,-anglez#)

` precalc cos+sin for rotation
  cx#=Cos(anglex#)
  sx#=Sin(anglex#)

  cy#=Cos(angley#)
  sy#=Sin(angley#)

Zpos#=Speed#

z#=(cx#*Zpos#)
y#=(sx#*zpos#)

` Around Y axis
x2#=(cY#*Z#)-(sy#*X#)
z#=((cy#*X#)+(sy#*Z#))

EndFunction x2#,y#,z#






Function MakeGrass(Size,Seed)
Randomize Seed

Me=New3DImage(Size,Size)
if Me
oldsurface=getsurface()

rendertoimage me
lockbuffer

GrassColour=$304050
For ylp=0 to size-1
For xlp=0 to size-1
IntensityColour=rnd(155)
C=(IntensityColour+OLDIntensityColour)/2
c=rgbalphamult(GrassColour,Rgb(c,c,c))
dotc xlp,ylp,c
OldIntensityColour= IntensityColour
next
next

unlockbuffer
blurimage me,8.1

inkmode 1+16
For ylp=0 to size-1 step 32
For xlp=0 to size-1 step 32
boxc xlp,0,xlp+8,size,true,rgb(90,20,20)
boxc 0,ylp,size,ylp+8,true,rgb(20,20,90)
next
next
inkmode 1

rendertoimage oldsurface
endif

EndFunction me




Function MakeWall(Width,Height,Seed)
Randomize Seed

Me=New3DImage(Width,Height)
if Me
oldsurface=getsurface()

rendertoimage me
lockbuffer

c1=rgb(10,10,40)
c2=rndrgb()

Shadebox 0,0,Width,Height,c1,c1,c2,c2

WindowWidth=16
WindowHeight=8

inkmode 1
for ylp=10 to Height-20 step (windowHeight+4)
for xlp=10 to Width-10 step (windowWidth+4)

v=rnd(1)
boxc xlp,ylp,xlp+windowWidth,ylp+windowHeight,true,v*rgb(200,200,200)
boxc xlp,ylp,xlp+windowWidth,ylp+windowHeight,false,v*rgb(255,255,255)

next
next
inkmode 1
unlockbuffer
rendertoimage oldsurface
blurimage me,8.1
endif

EndFunction me