This is an attempt to answer some recurring questions as well as give people some practical understanding on how to circumvent the limitations of a 3D engine.
I'd like some feedback on this, particularly with regard to my understanding of and explanation of the problems.
Please note that the part on DRM isn't finished yet, so just concentrate on the first part.
Andy
The issues with B3D
When trying to create large worlds in B3D you will encounter several issues
which must be solved in order to create a credible large world.
1) Z buffer issues:
The Z-buffer in B3D has a predefined word-size in which to represent the
range you set with the CameraRange command. As the difference between
Near# and Far# grows, the same number of bit's must represent a larger
range and thus precission suffers.
This means that as you increase the difference between the Near# and Far#
in your CameraRange command, you will experience that entities which are in
view will seem to be melted together or fight over the same place. This
happens because the Z buffer cannot differentiate between an entity placed
at 50000 and 51000. To the Z-buffer they are at the same place.
Basically, things which are further away is drawn on top of things which are
closer. This is because far away things may be so close to each other, that
the lack of z-buffer accuracy makes them appear to be at the same place.
2) Floating point inaccuracies:
Floating point math is inherently imprecise, so when you write 5.0000. The
computer will represent it as approximately 5.0000.
This means that as you get further away from the centre of your 3D
coordinate system, entities will start to jump around. Again, the
larger the numbers get, the less precise the position is.
Basically, 3D coordinates in B3D are only correct to 6 digits, meaning that when
you get far away from the center of your world, everything is just a little
bit away from where it should be, and when you try moving it somewhere, it
will seem to jump around.
What is the solution
When refering to entities in the following, I am really refering to 2 different
kinds of entities. The immovable entities like mesh terrain and buildings, and
moveable entities like vehicles, projectiles etc. I refer to the former as
static entities and refer to the latter as free entities.
Floating Point Inaccuracies:
Floating Point Inaccuracies can be rectified by normalizing your cameras
position every once in a while... If you are at 10000,10000,10000, then you
simply move everything -10000,-10000,-10000, so that the camera is now at 0,0,0.
This way everything stays where it is in relation to each other, but is moved
closer to the origo.
1) Low number of total entities:
If the static entitycount is low, then you can simply move every entity in a
loop(both static and free). This is a simple and instant fix that can be
applied well into the development of a game. I've included Exhibit A to give
you an idea of how this may be done.
2) medium to large number of static entities:
If you have a medium to large number of entities, you will need to attach every
static entity to a pivot and simply move the pivot instead of every entity. Then
you move the free entities in a loop.
The pivot also suffers from Floating Point inaccuracy problems, so to make this
concept useful in a large world, you will have to normalize the static entities
position to the pivot and the pivots position to the cetre of the coordinate
system regularly, but when you do, you are never again limited with regard to
the size of you world.
Z-Buffer inaccuracy:
Z-Buffer inaccuracy can be solved in several ways. You can calculate the largest
distance needed and adjust the Near# and Far# values using the CameraRange command
regularly.
Another way is to render every frame with different sets of Near# and Far# values.
The problem with this is that while it increases accuracy, it does so while
sacrificing speed as you basically render every frame twice. I've included
Exhibit B to give you an idea of how this may be done.
Dynamic Resource Management
For small worlds, you can usually keep the entire map in memory, but for
medium and large sized worlds you will need DRM.
Basically, DRM is any system which will manage the resources used by your programme.
This is done by loading and deleting entities, triangles, vertices, textures or
data on the fly.
Exhibit A:
;***********************************************************'
; Call housekeeping from your main loop
;***********************************************************'
num_ent=10 ; number of entities
dim mesh(num_ent)
fieldsize=5000
.housekeeping
mx = 0.0
my = 0.0
mz = 0.0
If EntityX(player_pivot)>5000 Then
PositionEntity player_pivot,EntityX(player_pivot)-fieldsize,EntityY(player_pivot),EntityZ(player_pivot)
mx = -fieldsize : my = 0.0 : mz = 0.0
EndIf
If EntityZ(player_pivot)>5000 Then
PositionEntity player_pivot,EntityX(player_pivot),EntityY(player_pivot),EntityZ(player_pivot)-fieldsize
mx = 0.0 : my = 0.0 : mz = -fieldsize
EndIf
If EntityX(player_pivot)<-5000 Then
PositionEntity player_pivot,EntityX(player_pivot)+fieldsize,EntityY(player_pivot),EntityZ(player_pivot)
mx = fieldsize : my = 0.0 : mz = 0.0
EndIf
If EntityZ(player_pivot)<-5000 Then
PositionEntity player_pivot,EntityX(player_pivot),EntityY(player_pivot),EntityZ(player_pivot)+fieldsize
mx = 0.0 : my = 0.0 : mz = fieldsize
EndIf
For q = 1 To num_ent
MoveEntity mesh(q),mx,my,mz
Next
Return
;*******************************************************
Exhibit B
;***********************************************************'
; Replace your regular RenderWorld with this
;*******************************************************
near#=1.0
intermediate#=5000.0
far#=1000000.0
;far
CameraRange cam,intermediate#,far#
CameraClsMode cam,1,1
RenderWorld frameTween
;near
CameraRange cam,near#,intermediate#+500
CameraClsMode cam,0,1
RenderWorld frameTween
;*******************************************************
I'd like some feedback on this, particularly with regard to my understanding of and explanation of the problems.
Please note that the part on DRM isn't finished yet, so just concentrate on the first part.
Andy
The issues with B3D
When trying to create large worlds in B3D you will encounter several issues
which must be solved in order to create a credible large world.
1) Z buffer issues:
The Z-buffer in B3D has a predefined word-size in which to represent the
range you set with the CameraRange command. As the difference between
Near# and Far# grows, the same number of bit's must represent a larger
range and thus precission suffers.
This means that as you increase the difference between the Near# and Far#
in your CameraRange command, you will experience that entities which are in
view will seem to be melted together or fight over the same place. This
happens because the Z buffer cannot differentiate between an entity placed
at 50000 and 51000. To the Z-buffer they are at the same place.
Basically, things which are further away is drawn on top of things which are
closer. This is because far away things may be so close to each other, that
the lack of z-buffer accuracy makes them appear to be at the same place.
2) Floating point inaccuracies:
Floating point math is inherently imprecise, so when you write 5.0000. The
computer will represent it as approximately 5.0000.
This means that as you get further away from the centre of your 3D
coordinate system, entities will start to jump around. Again, the
larger the numbers get, the less precise the position is.
Basically, 3D coordinates in B3D are only correct to 6 digits, meaning that when
you get far away from the center of your world, everything is just a little
bit away from where it should be, and when you try moving it somewhere, it
will seem to jump around.
What is the solution
When refering to entities in the following, I am really refering to 2 different
kinds of entities. The immovable entities like mesh terrain and buildings, and
moveable entities like vehicles, projectiles etc. I refer to the former as
static entities and refer to the latter as free entities.
Floating Point Inaccuracies:
Floating Point Inaccuracies can be rectified by normalizing your cameras
position every once in a while... If you are at 10000,10000,10000, then you
simply move everything -10000,-10000,-10000, so that the camera is now at 0,0,0.
This way everything stays where it is in relation to each other, but is moved
closer to the origo.
1) Low number of total entities:
If the static entitycount is low, then you can simply move every entity in a
loop(both static and free). This is a simple and instant fix that can be
applied well into the development of a game. I've included Exhibit A to give
you an idea of how this may be done.
2) medium to large number of static entities:
If you have a medium to large number of entities, you will need to attach every
static entity to a pivot and simply move the pivot instead of every entity. Then
you move the free entities in a loop.
The pivot also suffers from Floating Point inaccuracy problems, so to make this
concept useful in a large world, you will have to normalize the static entities
position to the pivot and the pivots position to the cetre of the coordinate
system regularly, but when you do, you are never again limited with regard to
the size of you world.
Z-Buffer inaccuracy:
Z-Buffer inaccuracy can be solved in several ways. You can calculate the largest
distance needed and adjust the Near# and Far# values using the CameraRange command
regularly.
Another way is to render every frame with different sets of Near# and Far# values.
The problem with this is that while it increases accuracy, it does so while
sacrificing speed as you basically render every frame twice. I've included
Exhibit B to give you an idea of how this may be done.
Dynamic Resource Management
For small worlds, you can usually keep the entire map in memory, but for
medium and large sized worlds you will need DRM.
Basically, DRM is any system which will manage the resources used by your programme.
This is done by loading and deleting entities, triangles, vertices, textures or
data on the fly.
Exhibit A:
;***********************************************************'
; Call housekeeping from your main loop
;***********************************************************'
num_ent=10 ; number of entities
dim mesh(num_ent)
fieldsize=5000
.housekeeping
mx = 0.0
my = 0.0
mz = 0.0
If EntityX(player_pivot)>5000 Then
PositionEntity player_pivot,EntityX(player_pivot)-fieldsize,EntityY(player_pivot),EntityZ(player_pivot)
mx = -fieldsize : my = 0.0 : mz = 0.0
EndIf
If EntityZ(player_pivot)>5000 Then
PositionEntity player_pivot,EntityX(player_pivot),EntityY(player_pivot),EntityZ(player_pivot)-fieldsize
mx = 0.0 : my = 0.0 : mz = -fieldsize
EndIf
If EntityX(player_pivot)<-5000 Then
PositionEntity player_pivot,EntityX(player_pivot)+fieldsize,EntityY(player_pivot),EntityZ(player_pivot)
mx = fieldsize : my = 0.0 : mz = 0.0
EndIf
If EntityZ(player_pivot)<-5000 Then
PositionEntity player_pivot,EntityX(player_pivot),EntityY(player_pivot),EntityZ(player_pivot)+fieldsize
mx = 0.0 : my = 0.0 : mz = fieldsize
EndIf
For q = 1 To num_ent
MoveEntity mesh(q),mx,my,mz
Next
Return
;*******************************************************
Exhibit B
;***********************************************************'
; Replace your regular RenderWorld with this
;*******************************************************
near#=1.0
intermediate#=5000.0
far#=1000000.0
;far
CameraRange cam,intermediate#,far#
CameraClsMode cam,1,1
RenderWorld frameTween
;near
CameraRange cam,near#,intermediate#+500
CameraClsMode cam,0,1
RenderWorld frameTween
;*******************************************************