MiniB3D SceneGraph


Tweet blitzmax blitzmax-ng code-archives algorithms
(Posted 5 months ago) RonTek

The game world is divided into segments, and only the segment where the camera is at and any surrounding segments are rendered. Description and details in example.

This should work with OpenB3DMax as well.

Author: b32

Image

example.bmx

Import sidesign.minib3d

Include "TSceneGraph.bmx"

Graphics3D 800, 600, 0, 2

Local cam:TCamera = CreateCamera()
Local org:TEntity = CreateSphere()

'Create:TSceneGraph()
'
'   Creates a scenegraph
'
'   parameters:
'       world size  - size of world that should be clusterized
'                     a world with a size=512 will go from (0,0) to (511,511)
'       cluster size   - size of cluster
'
Local scenegraph:TSceneGraph = New TSceneGraph.Create(512, 10) 

For Local i% = 0 To 510 Step 8
For Local j% = 0 To 510 Step 8

    Local sph:TEntity = CopyEntity(org)
    PositionEntity sph, i, 0, j
    EntityColor sph, Rand(255), Rand(255), Rand(255)

'AddToSceneGraph:Int()
'
'   Adds entity to scenegraph. Results False if failed.
'   Entities outside the world area will not be added.
'
'   parameters:
'       entity      - entity to be added
'
    scenegraph.AddToSceneGraph sph

Next
Next

FreeEntity org

PositionEntity cam, 0, 5, 0

Repeat

    If KeyDown(KEY_A) TurnEntity cam, 0, 1, 0
    If KeyDown(KEY_D) TurnEntity cam, 0, -1, 0
    If KeyDown(KEY_W) MoveEntity cam, 0, 0, 1
    If KeyDown(KEY_S) MoveEntity cam, 0, 0, -1

    RenderWorld

'Render()
'
'   Renders part of the scenegraph around the camera.
'   Call directly after RenderWorld
'
'   parameters:
'       cam         - camera that is used
'       size            - size of area that should be rendered
'                     a size of 4 will render areas (-4, -4) to (4, 4) around camera
'
    scenegraph.Render(cam, 4)

    BeginMax2D
    DrawText "ok", 0,0
    EndMax2D

    Flip

Until KeyHit(27)

End

TSceneGraph.bmx

Type TSceneGraph

    'create scenegraph
    Field cluster:TList[,,]
    Field scale%
    Field clustermax%

    Method Create:TSceneGraph(size%,clustersize%)
        clustermax% = (size/clustersize) + 1
        cluster = New TList[clustermax, clustermax, clustermax]
        For Local i% = 0 To clustermax-1
        For Local j% = 0 To clustermax-1
        For Local k% = 0 To clustermax-1
            cluster[i, j, k] = CreateList()
        Next
        Next
        Next
        scale = clustersize
        Return Self
    End Method

    Method AddToSceneGraph:Int(e:TEntity)
        Local x#,y#,z#
        x# = EntityX(e, True)
        y# = EntityY(e, True)
        z# = EntityZ(e, True)
        Local cx%,cy%,cz%
        cx = x/scale
        cy = y/scale
        cz = z/scale
        If cx<0 Then Return False
        If cy<0 Then Return False
        If cz<0 Then Return False
        If cx>=clustermax Then Return False
        If cy>=clustermax Then Return False
        If cz>=clustermax Then Return False
        ListRemove TEntity.entity_list, e
        ListAddLast cluster[cx,cy,cz], e
        Return True
    End Method

    Method Render(cam:TCamera, size%=8)
        'show scenegraph    
        Local bx%, by%, bz%
        bx = EntityX(cam) / scale
        by = EntityY(cam) / scale
        bz = EntityZ(cam) / scale

        For Local j% = -size To size
        For Local i% = -size To size
        For Local k% = -size To size

            Local x%,y%,z%
            x = i + bx
            y = j + by
            z = k + bz

            If (x >= 0) And (y >= 0) And (z >= 0) And (x < clustermax) And (y < clustermax) And (z < clustermax) Then
                    For Local e:TEntity = EachIn cluster[x, y, z]
                        If sphereinfrustum(cam, e.px, e.py, e.pz, 1) Then 
                            If TSprite(e) Then UpdateSprite cam, TSprite(e)
                            e.Update()
                        End If
                    Next
            End If

        Next
        Next
        Next    
    End Method

End Type

Function SphereInFrustum#(cam:TCamera, x#,y#,z#,radius#)

    Local d#

    For Local p=0 To 5

        d# = cam.frustum[p,0] * x + cam.frustum[p,1] * y + cam.frustum[p,2] * -z + cam.frustum[p,3]

        If d <= -radius Then Return 0

    Next

    Return d + radius

End Function

Function UpdateSprite(cam:TCamera, sprite:TSprite)

    If sprite.view_mode<>2

        Local x#=sprite.mat.grid[3,0]
        Local y#=sprite.mat.grid[3,1]
        Local z#=sprite.mat.grid[3,2]

        sprite.mat.Overwrite(cam.mat)
        sprite.mat.grid[3,0]=x
        sprite.mat.grid[3,1]=y
        sprite.mat.grid[3,2]=z
        sprite.mat_sp.Overwrite(sprite.mat)

        If sprite.angle#<>0.0
            sprite.mat_sp.RotateRoll(sprite.angle#)
        EndIf

        If sprite.scale_x#<>1.0 Or sprite.scale_y#<>1.0
            sprite.mat_sp.Scale(sprite.scale_x#,sprite.scale_y#,1.0)
        EndIf

        If sprite.handle_x#<>0.0 Or sprite.handle_y#<>0.0
            sprite.mat_sp.Translate(-sprite.handle_x#,-sprite.handle_y#,0.0)
        EndIf

    Else

        sprite.mat_sp.Overwrite(sprite.mat)

        If sprite.scale_x#<>1.0 Or sprite.scale_y#<>1.0
            sprite.mat_sp.Scale(sprite.scale_x#,sprite.scale_y#,1.0)
        EndIf

    EndIf

End Function

Reply To Topic (minimum 10 characters)

Please log in to reply