[bb] Cube mapping made 6x faster and easier by Damien Sturdy [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:38

Previous topic - Next topic

BlitzBot

Title : Cube mapping made 6x faster and easier
Author : Damien Sturdy
Posted : 1+ years ago

Description : May 03 2005; MultiTexturing problem spotted by SnarkBait fixed.
-----------------------------------------------------------
Okay, today, i decided to look at cubemapping- something ive not played with before.

I got the demo from blitz to work, and fixed a couple of its bugs (not hiding the camera) so some of the credit goes to the author of that demo.

This system allows you to turn any loaded mesh into a "cubemapped" mesh- by calling one command. the system keeps track of cameras and textures on its own.

Usage:

To make an object cubemapped:

addcubemapobject(mesh,texturesize,texturelayer)
                            turns "mesh" into a cubemapped entity

Updatecubemaps()            Goes through all cubemap objects and updates their textures

Deletecubemapobject(mesh)   Deletes the cubemap resources from "mesh"

Deleteallcubemapobjects()   Frees all cubemapping resources

All thats required to get this to work:

Addcubemapobject(mesh,256)
and
updatecubemaps()

[edit]
Just added a new command:
cubemeshCameraRange(mesh,CameraRangemin#,CameraRangemax#)

This sets how far the camera that renderes the reflection can "see" :D
[New version]

Okay, so i didnt need several cameras for several objects, so i overhauled the camera management...

The usage is exactly the same as before, except if you change graphics modes without clearing all the objects, youl get a Memory Access Violation.
Make sure you use Deleteallcubemapobjects() before changing graphics mode :)
New commands on 03/10/04:

BIG UPDATE!
Setcubemapupdatefrequency (okay so this may need changing)

Setcubemapupdatefrequency(mesh,frames,faceperrender) Sets how many "updatecubemaps" should be executed before this cubemapped entity gets cubemapped. If faceperrender=1 then it only updates 1 face of each cubemap every update, which is efficient but can cause glitches depending on the scenery. this means much faster "realtime" cubemapping though!
UpdateNextCubemap()  ;Iterates to the next cubemap and updates it. call this instead of updatecubemaps each frame for a higher framerate. this command disregards the above commands "frames" property..


Code :
Code (blitzbasic) Select
Global scx=640,scy=480
Graphics3D scx,scy,16,2

light=CreateLight()
plane=CreatePlane()


gld=CreateTexture(255,255)
SetBuffer TextureBuffer(gld)
For x=0 To 128
Color x,x*2,x*3
Rect x,x,255-x/2,255-x/2,0
Next
SetBuffer BackBuffer()

ScaleTexture gld,100,100
EntityTexture plane,gld

camera=CreateCamera()
CameraClsColor camera,10,20,250
Pivot=CreatePivot()
EntityParent camera,Pivot


PositionEntity camera,0,20,-30


;Create some entities to cubemap
sphere=CreateSphere(20)
PositionEntity sphere,0,20,10
ScaleEntity sphere,10,10,10
cube=CreateCube()
PositionEntity cube,0,20,-10
ScaleEntity cube,5,5,5

;Cubemap them!
addcubemapobject(cube,256,0)
addcubemapobject(sphere,128,0)


;You dont need to do the next couple of lines, but its good for efficiency:
setcubemapupdatefrequency(cube,2,1) ;Update cube every 15 frames, and enable "face per render" (update only a part of the cubemap every update)
setcubemapupdatefrequency(sphere,2,1) ;Update sphere every 15 frames, and enable "face per render" (update only a part of the cubemap every update)




;change the camera range of these two to speed things up
cubemeshCameraRange(cube,10,250)
cubemeshCameraRange(sphere,10,250)



;do a render loop
Repeat
mlt#=1
If KeyDown(57) Then mlt#=10
TurnEntity Pivot,0,.1*mlt#,0
TurnEntity cube,.1*mlt#,0,0
updatecubemaps()   ;Update all cubemaps!

;or you can use : updatenextcubemap()   ;Update NEXT cubemap!


RenderWorld
Flip
Until KeyDown(1)
Deletecubemapobject(cube) ;Delete the cubemap stuff from "cube"
Deletecubemapobject(sphere) ;Delete the cubemap stuff from "sphere"

Deleteallcubemapobjects() ;Alternatively, call this at the end to wipe all cubemap stuff

End











;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Cubemap System;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Type cubemapobject
Field entity
Field Texture
Field detail
Field cammin#,cammax#
Field Lastupdate,updatefrequency
Field Lastcamupdate
Field faceperrender
Field Lastface=1
End Type

Global cubemapcameraent=0
Global Lastcubemapcount,cubemapcount

Function clearcubemapsystem()
Deleteallcubemapobjects()
If cubemapcameraent<>0 Then FreeEntity cubemapcameraent:cubemapcameraent=0
End Function

Function addcubemapobject(mesh,detail,Texturelayer=0,blendmode=2)
Local t.cubemapobject=New cubemapobject
tentity=mesh
Tx=CreateTexture(detail,detail,1+128+256)
EntityTexture mesh,tx,0,Texturelayer
TextureBlend tx,blendmode
tTexture=tx
tdetail=detail
If cubemapcameraent=0 Then cubemapcameraent=CreateCamera():CameraProjMode cubemapcameraent,0
tupdatefrequency=1
tLastupdate=Lastcubemapcount
CameraProjMode cubemapcameraent,0
tcammin=1
tcammax=1000
CameraRange cubemapcameraent,tcammin,tcammax
updatecubemap(tTexture,cubemapcameraent,tentity)
Lastcubemapcount=Lastcubemapcount+1;MilliSecs()
End Function


Function cubemeshCameraRange(mesh,CameraRangemin#,CameraRangemax#)  ;sets how a cubemaped texture is rendered.
Local n.cubemapobject
For n=Each cubemapobject
If nentity=mesh Then
ncammin=CameraRangemin
ncammax=CameraRangemax
EndIf
Next
End Function


Function Deleteallcubemapobjects()
Local n.cubemapobject
For n=Each cubemapobject
Deletecubemapobject nentity
Next
If cubemapcameraent<>0 Then FreeEntity cubemapcameraent:cubemapcameraent=0
End Function


Function Deletecubemapobject(mesh)
Local n.cubemapobject
For n=Each cubemapobject
If nentity=mesh Then
If nTexture<>0 Then FreeTexture nTexture
Delete n
EndIf
Next
checkifanycubemapsleft()
End Function

Function checkifanycubemapsleft()
Local cnt=0,n.cubemapobject
For n=Each cubemapobject
cnt=cnt+1
Next
If cnt=0 Then clearcubemapsystem()
End Function

Function updatecubemaps()
Local o.cubemapobject
For o.cubemapobject=Each cubemapobject
If (cubemapcount-oLastupdate)>oupdatefrequency Then
CameraProjMode cubemapcameraent,0
CameraRange cubemapcameraent,ocammin,ocammax
updatecubemap(oTexture,cubemapcameraent,oentity,oLastface*ofaceperrender):oLastface=(oLastface Mod 6)+1
oLastupdate=cubemapcount
EndIf
Next
cubemapcount=cubemapcount+1
End Function


Function updatenextcubemap()
Local o.cubemapobject
Local cnt=0,cnt2=0

For o.cubemapobject=Each cubemapobject
cnt2=cnt2+1
Next

For o.cubemapobject=Each cubemapobject
cnt=cnt+1
If cubemapcount Mod (cnt2+1)=cnt Then;If (cubemapcount-oLastupdate)>oupdatefrequency Then
CameraProjMode cubemapcameraent,0
CameraRange cubemapcameraent,ocammin,ocammax
updatecubemap(oTexture,cubemapcameraent,oentity,oLastface*ofaceperrender):oLastface=(oLastface Mod 6)+1
oLastupdate=cubemapcount
EndIf
Next
cubemapcount=cubemapcount+1
End Function

Function setcubemapupdatefrequency(mesh,updaterate,faceperrender=0)
Local o.cubemapobject
For o.cubemapobject=Each cubemapobject
If oentity=mesh Then oupdatefrequency=updaterate:ofaceperrender=faceperrender
Next
End Function

Function UpdateCubemap(tex,camera,entity,side=0)   ;the bit ripped from the Blitz demo


tex_sz=TextureWidth(tex)

; Show the camera we have specifically created for updating the cubemap
CameraProjMode camera,1
; Hide entity that will have cubemap applied to it. This is so we can get cubemap from its position, without it blocking the view
HideEntity entity

; Position camera where the entity is - this is where we will be rendering views from for cubemap
PositionEntity camera,EntityX#(entity,1),EntityY#(entity,1),EntityZ#(entity,1)

CameraClsMode camera,False,True

; Set the camera's viewport so it is the same size as our texture - so we can fit entire screen contents into texture
CameraViewport camera,0,0,tex_sz,tex_sz

; Update cubemap
If side=0 Or side=1 Then
; do left view
SetCubeFace tex,0
RotateEntity camera,0,90,0
RenderWorld
CopyRect 0,0,tex_sz,tex_sz,0,0,BackBuffer(),TextureBuffer(tex)
EndIf
If side=0 Or side=2 Then
; do forward view
SetCubeFace tex,1
RotateEntity camera,0,0,0
RenderWorld
CopyRect 0,0,tex_sz,tex_sz,0,0,BackBuffer(),TextureBuffer(tex)

EndIf
If side=0 Or side=3 Then

; do right view
SetCubeFace tex,2
RotateEntity camera,0,-90,0
RenderWorld
CopyRect 0,0,tex_sz,tex_sz,0,0,BackBuffer(),TextureBuffer(tex)

EndIf
If side=0 Or side=4 Then
; do backward view
SetCubeFace tex,3
RotateEntity camera,0,180,0
RenderWorld
CopyRect 0,0,tex_sz,tex_sz,0,0,BackBuffer(),TextureBuffer(tex)

EndIf
If side=0 Or side=5 Then

; do up view
SetCubeFace tex,4
RotateEntity camera,-90,0,0
RenderWorld
CopyRect 0,0,tex_sz,tex_sz,0,0,BackBuffer(),TextureBuffer(tex)

EndIf
If side=0 Or side=6 Then

; do down view
SetCubeFace tex,5
RotateEntity camera,90,0,0
RenderWorld
CopyRect 0,0,tex_sz,tex_sz,0,0,BackBuffer(),TextureBuffer(tex)

EndIf
; Show entity again
ShowEntity entity

; Hide the cubemap camera
CameraProjMode camera,0

End Function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Comments :


xmlspy(Posted 1+ years ago)

 I get an Entity does not exist.  Remove the # from cubemapcameraent# .


BlitzSupport(Posted 1+ years ago)

 Yeah, handy stuff, but like xml says, don't ever use floats for entity handles! (Or images, sounds, etc.)


Damien Sturdy(Posted 1+ years ago)

 Forgot to post... i fixed the # which was there from an earlier typo.Also fixed a problem with parented meshes where the camera would always be put at 0,0,0.


Snarkbait(Posted 1+ years ago)

 I had to fix this to get multitexturing to work:EntityTexture mesh,tx,0,Texturelayer <== added the '0' in the 'frame' spot, and added blendmode and textureblend to the function.
Function addcubemapobject(mesh,detail,Texturelayer=0,blendmode=2)
Local t.cubemapobject=New cubemapobject
tentity=mesh
Tx=CreateTexture(detail,detail,1+128+256)
EntityTexture mesh,tx,0,Texturelayer
TextureBlend tx,blendmode
tTexture=tx
tdetail=detail
If cubemapcameraent=0 Then cubemapcameraent=CreateCamera():CameraProjMode cubemapcameraent,0
tupdatefrequency=1
tLastupdate=Lastcubemapcount
CameraProjMode cubemapcameraent,0
tcammin=1
tcammax=1000
CameraRange cubemapcameraent,tcammin,tcammax
updatecubemap(tTexture,cubemapcameraent,tentity)
Lastcubemapcount=Lastcubemapcount+1;MilliSecs()
End Function



Damien Sturdy(Posted 1+ years ago)

 Cheers for that. I have not had an issue though i did occasionally momentarily see some wierd artifacts. Thats a silly mistake (number 2 I suppose!)I'll update the entry now.


Trader3564(Posted 1+ years ago)

 awesome, i almost feel the colthmetal cool my skin when i watch this demo. well done.


plash(Posted 1+ years ago)

 Too tired to continue working on this, but maybe someone will find it useful! (much confusion, as minib3d does not have createplane function)Blitzmax superstrict (currently not working)SuperStrict

Import sidesign.minib3d

Global scx:Int = 640, scy:Int = 480
Graphics3D scx, scy, 16, 2

Local Light:TLight = createLight()
Local PLANE:TMesh = createCube()  'substitute for createplane - as it does not exist in klepto's or simons version
ScaleEntity PLANE, 5, 0, 5
PositionEntity PLANE, - 6, - 6, 0

Local gld:TTexture = CreateTexture(255, 255)
For Local X:Int = 0 To 128
SetColor X, X * 2, X * 3
DrawRect X, X, 255 - X / 2, 255 - X / 2
Next
Flip
BackBufferToTex(gld)
Cls

scaleTexture gld, 100, 100
EntityTexture PLANE, gld

Local CAMERA:TCamera = createCamera()
CameraClsColor CAMERA, 10, 20, 250

Local PIVOT:TPivot = createPivot()
EntityParent CAMERA, PIVOT

PositionEntity CAMERA, 0, 20, - 30

'Create some entities To cubemap
Local sphere:TMesh = createSphere(20)
PositionEntity sphere, 0, 20, 10
ScaleEntity sphere, 10, 10, 10

Local cube:TMesh = createCube()
PositionEntity cube, 0, 20, - 10
ScaleEntity cube, 5, 5, 5

'Cubemap them!
addcubemapobject(cube, 256, 0)
addcubemapobject(sphere, 128, 0)

'You dont need To do the Next couple of lines, but its good For efficiency;
setcubemapupdatefrequency(cube, 2, 1)   'Update cube every 15 frames, And enable "face per render" (update only a part of the cubemap every update)
setcubemapupdatefrequency(sphere, 2, 1)   'Update sphere every 15 frames, And enable "face per render" (update only a part of the cubemap every update)

'change the camera range of these two To speed things up
cubemeshCameraRange(cube, 10, 250)
cubemeshCameraRange(sphere, 10, 250)


'do a render loop
Local mlt:Float = 1.0
Repeat

If KeyDown(57) Then mlt = 10
TurnEntity PIVOT, 0, .1 * mlt, 0
TurnEntity cube, .1 * mlt, 0, 0
updatecubemaps()    'Update all cubemaps!

'Or you can use ; updatenextcubemap()   'Update Next cubemap!


RenderWorld
Flip
Until KeyHit(KEY_ESCAPE)

Deletecubemapobject(cube)   'Delete the cubemap stuff from "cube"
Deletecubemapobject(sphere) 'Delete the cubemap stuff from "sphere"

Deleteallcubemapobjects() 'Alternatively, call this at the End To wipe all cubemap stuff

End


Type cubemapobject
  Global _list:TList = New TList
 
Field entity:TEntity
Field TEXTURE:TTexture
Field detail:Int
Field cammin:Float, cammax:Float
Field Lastupdate:Int, updatefrequency:Int
Field Lastcamupdate:Int
Field faceperrender:Int
Field Lastface:Int = 1

Method New()
  _list.AddLast(Self)

End Method

Method remove()
entity.FreeEntity() ; entity = Null
TEXTURE = Null
detail = Null
cammin = Null ; cammax = Null
lastupdate = Null ; updatefrequency = Null
lastcamupdate = Null ; faceperrender = Null
lastface = Null

  _list.remove(Self)
 
End Method

End Type

Global cubemapcameraent:TCamera = Null
Global Lastcubemapcount:Int, cubemapcount:Int

Function clearcubemapsystem()
Deleteallcubemapobjects()

   If cubemapcameraent <> Null Then FreeEntity cubemapcameraent ; cubemapcameraent = Null

End Function

Function addcubemapobject(MESH:TMesh, detail:Int, Texturelayer:Int = 0, blendmode:Int = 2)
  Local t:cubemapobject = New cubemapobject, Tx:TTexture

t.entity = MESH
Tx = CreateTexture(detail, detail, 1 + 128 + 256)
EntityTexture MESH, tx, 0, Texturelayer
TextureBlend tx, blendmode

t.TEXTURE = tx
t.detail = detail

If cubemapcameraent = Null Then cubemapcameraent = createCamera() ; CameraProjMode cubemapcameraent, 0

t.updatefrequency = 1
t.Lastupdate = Lastcubemapcount
CameraProjMode cubemapcameraent, 0
t.cammin = 1
t.cammax = 1000
CameraRange cubemapcameraent, t.cammin, t.cammax
_UpdateCubemap(t.TEXTURE, cubemapcameraent, t.entity)

Lastcubemapcount = Lastcubemapcount + 1

End Function


Function cubemeshCameraRange(MESH:TEntity, CameraRangemin:Float, CameraRangemax:Float)   'sets how a cubemaped texture is rendered.
  Local n:cubemapobject

For n = EachIn cubemapobject._list

If n.entity = MESH Then
n.cammin = CameraRangemin
n.cammax = CameraRangemax

EndIf

Next

End Function


Function Deleteallcubemapobjects()
  Local n:cubemapobject

For n = EachIn cubemapobject._list

Deletecubemapobject n.entity

Next

   If cubemapcameraent <> Null Then FreeEntity cubemapcameraent ; cubemapcameraent = Null

End Function


Function Deletecubemapobject(MESH:TEntity)
  Local n:cubemapobject

For n = EachIn cubemapobject._list
If n.entity = MESH Then
  If n.TEXTURE <> Null Then FreeTexture n.TEXTURE
n.remove()

EndIf
Next

   'checkifanycubemapsleft()
   If cubemapobject._list.count() = 0 Then cubemapobject._list.clear()
   
End Function

rem
Function checkifanycubemapsleft()
  Local cnt:Int = 0, n:cubemapobject

For n = EachIn cubemapobject._list

cnt = cnt + 1

Next

   If cnt = 0 Then clearcubemapsystem()
 
End Function
endrem

Function updatecubemaps()
  Local o:cubemapobject

For o = EachIn cubemapobject._list

If (cubemapcount - o.Lastupdate) > o.updatefrequency Then
CameraProjMode cubemapcameraent, 0
CameraRange cubemapcameraent, o.cammin, o.cammax
_UpdateCubemap(o.TEXTURE, cubemapcameraent, o.entity, o.Lastface * o.faceperrender) ; o.Lastface = (o.Lastface Mod 6) + 1
  o.Lastupdate = cubemapcount
EndIf

Next

   cubemapcount = cubemapcount + 1
   
End Function


Function updatenextcubemap()
  Local o:cubemapobject
  Local cnt:Int = 0, cnt2:Int = 0

For o = EachIn cubemapobject._list

cnt2 = cnt2 + 1

Next

For o = EachIn cubemapobject._list
  cnt = cnt + 1
If cubemapcount Mod (cnt2 + 1) = cnt Then'If (cubemapcount-oLastupdate)>oupdatefrequency Then
CameraProjMode cubemapcameraent, 0
CameraRange cubemapcameraent, o.cammin, o.cammax
_UpdateCubemap(o.TEXTURE, cubemapcameraent, o.entity, o.Lastface * o.faceperrender) ; o.Lastface = (o.Lastface Mod 6) + 1
  o.Lastupdate = cubemapcount
EndIf
Next

   cubemapcount = cubemapcount + 1
   
End Function

Function setcubemapupdatefrequency(MESH:TEntity, updaterate:Int, faceperrender:Int = 0)
  Local o:cubemapobject

For o = EachIn cubemapobject._list

If o.entity = MESH Then o.updatefrequency = updaterate ; o.faceperrender = faceperrender

Next

End Function

Function _UpdateCubemap(tex:TTexture, CAMERA:TCamera, entity:TEntity, side:Int = 0)        'the bit ripped from the Blitz demo
  Local tex_sz:Int = TextureWidth(tex)

' Show the camera we have specifically created For updating the cubemap
CameraProjMode CAMERA, 1
' Hide entity that will have cubemap applied To it. This is so we can get cubemap from its position, without it blocking the view
HideEntity entity

' Position camera where the entity is - this is where we will be rendering views from For cubemap
PositionEntity CAMERA, EntityX(entity, 1), EntityY(entity, 1), EntityZ(entity, 1)

CameraClsMode CAMERA, False, True

' Set the camera's viewport so it is the same size as our texture - so we can fit entire screen contents into texture
CameraViewport CAMERA, 0, 0, tex_sz, tex_sz

' Update cubemap
If side = 0 Or side = 1 Then
' do Left view
SetCubeFace tex, 0
RotateEntity CAMERA, 0, 90, 0
RenderWorld
'CopyRect 0, 0, tex_sz, tex_sz, 0, 0, BackBuffer(), TextureBuffer(tex)
BackBufferToTex(tex)

EndIf

If side = 0 Or side = 2 Then
' do forward view
SetCubeFace tex, 1
RotateEntity CAMERA, 0, 0, 0
RenderWorld
'CopyRect 0, 0, tex_sz, tex_sz, 0, 0, BackBuffer(), TextureBuffer(tex)
BackBufferToTex(tex)

EndIf

If side = 0 Or side = 3 Then
' do Right view
SetCubeFace tex, 2
RotateEntity CAMERA, 0, - 90, 0
RenderWorld
'CopyRect 0, 0, tex_sz, tex_sz, 0, 0, BackBuffer(), TextureBuffer(tex)
BackBufferToTex(tex)

EndIf

If side = 0 Or side = 4 Then
' do backward view
SetCubeFace tex, 3
RotateEntity CAMERA, 0, 180, 0
RenderWorld
'CopyRect 0, 0, tex_sz, tex_sz, 0, 0, BackBuffer(), TextureBuffer(tex)
BackBufferToTex(tex)

EndIf

If side = 0 Or side = 5 Then
' do up view
SetCubeFace tex, 4
RotateEntity CAMERA, - 90, 0, 0
RenderWorld
'CopyRect 0, 0, tex_sz, tex_sz, 0, 0, BackBuffer(), TextureBuffer(tex)
BackBufferToTex(tex)

EndIf

If side = 0 Or side = 6 Then
' do down view
SetCubeFace tex, 5
RotateEntity CAMERA, 90, 0, 0
RenderWorld
'CopyRect 0, 0, tex_sz, tex_sz, 0, 0, BackBuffer(), TextureBuffer(tex)
BackBufferToTex(tex)

EndIf

' Show entity again
ShowEntity entity

' Hide the cubemap camera
CameraProjMode CAMERA, 0

End Function



DareDevil(Posted 1+ years ago)

 Very good procedure, add all for my code;) [/i]