cubemaps? realtime? Here we go!
Hi folks,
while working on my other projects I have started to research why the cubemapping doesn't seem to work in Leadwerks in Realtime.
I have debugged through the code ( I was using Blitzmax to have access to the full debug output and fields of textures and buffers) and found out that
it seems you can't create a real Leadwerks buffer for Cubemaps, I have also investigated TylerH' s early approach after the CreateCubemap command was added and from my experience with miniB3D extended I came to the conclusion that something must be wrong in Joshs solution and handling for realtime cubemaps.
In Tylers lua sample he creates 6 buffers for each side of the cubemap, which is not needed when using fbo (Framebuffer objects). With this in mind I have
integrated my old fbo code from 'miniB3D extended' and stripped it down to just support cubemaps and fit it (maybe a bit messy) into the existing buffer system (no I have no source license). The first result was promising and so i was extending my sample to handle full cubemaps and i was amazed how fast the result was.
This is the result:
The real fps without recording is double as high as it is showing in the video.
Here is my code:
' ==================================================================== ' This file was generated by Leadwerks C++/LEO/BlitzMax Project Wizard ' Written by Rimfrost Software ' http://www.rimfrost.com ' ==================================================================== SuperStrict Framework leadwerks.ENGINE Local world:TWorld Local gbuffer:TBuffer Local camera:TCamera Local mesh:TMesh Local light:TLight Local ground:TMesh Local material:TMaterial Local materialfloor:TMaterial 'GCSetMode(2) RegisterAbstractPath( "D:/LESDK232r5/" ) Graphics(800,600) world=CreateWorld() If Not world RuntimeError "Failed to create world." gbuffer=CreateBuffer(GraphicsWidth(),GraphicsHeight(),BUFFER_DEPTH|BUFFER_COLOR0|BUFFER_COLOR1|BUFFER_COLOR2) camera=CreateCamera() PositionEntity camera,[0.0,0.0,-4.0] material=LoadMaterial("abstract::cubemap.mat") materialfloor = LoadMaterial("abstract::cobblestones.mat") mesh = CreateSphere(32) ScaleEntity mesh,[2.0,2.0,2.0] PaintEntity mesh,material light=CreateDirectionalLight() RotateEntity light , [45.0 , 45.0 , 45.0] Local cubemap:TTexture = CreateCubemap(512 , 512) Local cubemapbuffer:TBuffer = CreateBuffer(512 , 512) SetColorBuffer(cubemapbuffer , cubemap , 0) Local cubebuffer:TCubeBuffer = TCubeBuffer.Create(cubemap,cubemapbuffer) SetMaterialTexture( material , cubemap , 0) Local p:TPivot = CreatePivot() Local sp:TMesh = CreateSphere(16,p) MoveEntity sp , [4.0 , 0.0 , 0.0] EntityColor sp,[1.0,0.0,0.0,1.0] Local p1:TPivot = CreatePivot() Local sp1:TMesh = CreateSphere(16,p1) MoveEntity sp1 , [4.0 , 0.0 , 0.0] EntityColor sp1,[0.0,1.0,0.0,1.0] Local p2:TPivot = CreatePivot() Local sp2:TMesh = CreateSphere(16,p2) MoveEntity sp2 , [4.0 , 0.0 , 0.0] EntityColor sp2,[0.0,0.0,1.0,1.0] Local skybox:TMEsh = CreateCube() ScaleMesh skybox , [4.0 , 4.0 , 4.0] FlipMesh skybox EntityShadowMode skybox,0 PaintEntity skybox,LoadMaterial("abstract::FullskiesBlueClear0016_2_L.mat") EntityColor skybox,[1.0,1.0,1.0,1.0] Local frame:Int = 0 Repeat TurnEntity p , [0.0 , AppSpeed() * .5 , 0.0] TurnEntity p1, [0.0,-AppSpeed()*.5,0.0] TurnEntity p2, [0.0,0.0,AppSpeed()*.5] If KeyHit(KEY_ESCAPE) Exit If AppTerminate() Exit UpdateAppTime() UpdateWorld(AppSpeed()) SetBuffer(cubemapbuffer) PositionEntity camera , [0.0 , 0.0 , 0.0] ScaleEntity camera,[1.0 , -1.0 , 1.0] HideEntity mesh Local stage:Int = frame Mod 6 If stage = 0 Then cubebuffer.Set(0) RotateEntity camera,[0.0 , -90.0 , 0.0] RenderWorld() Else If stage = 1 Then cubebuffer.Set(1) RotateEntity camera,[0.0 , 90.0 , 0.0] RenderWorld() Else If stage = 2 Then cubebuffer.Set(2) RotateEntity camera,[-90.0 , 0.0 , 0.0] RenderWorld() Else If stage = 3 Then cubebuffer.Set(3) RotateEntity camera,[90.0 , 0.0 , 0.0] RenderWorld() Else If stage = 4 Then cubebuffer.Set(4) RotateEntity camera,[0.0 , 0.0 , 0.0 ] RenderWorld() Else If stage = 5 Then cubebuffer.Set(5) RotateEntity camera,[0.0 , -180.0 , 0.0] RenderWorld() End If cubebuffer.UnSet() ScaleEntity camera,[1.0 , 1.0 , 1.0] RotateEntity camera,[0.0 , 0.0 , 0.0] PositionEntity camera , [0.0 , 0.0 , - 4.0] ShowEntity mesh SetBuffer(gbuffer) RenderWorld() SetBuffer(BackBuffer()) RenderLights(gbuffer) SetBlend BLEND_ALPHA DrawText(UPS(),0,0) SetBlend 0 Flip(0) frame:+1 GCCollect() Forever gbuffer=Null FreeEntity light GCCollect() End Type TCubeBuffer Field texture:TTexture Field buffer:TBuffer Field rb:Int[1] Field fb:Int[1] Field sb:Int[1] Field db:Int[1] Function Create:TCubeBuffer(texture:TTexture,buffer:TBuffer) Local cb:TCubeBuffer = New TCubeBuffer cb.Texture = texture cb.Buffer = buffer cb._BuildBuffer() cb.Buffer.Framebuffer = cb.fb[0] cb.Buffer.colorbuffer[0] = texture Return cb End Function Method _BuildBuffer() Local w:Int =texture.reference._Width Local h:Int = texture.reference._Height glBindTexture(GL_TEXTURE_CUBE_MAP , texture.reference._index) glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_X,0,GL_RGBA8 ,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,Null glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_Z,0,GL_RGBA8 ,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,Null glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_X,0,GL_RGBA8 ,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,Null glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,0,GL_RGBA8 ,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,Null glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_Y,0,GL_RGBA8 ,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,Null glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_Y , 0 , GL_RGBA8 , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , Null glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE) ; glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP , GL_TEXTURE_MIN_FILTER , GL_LINEAR) ; glGenFramebuffersEXT(1, fb ) glGenRenderbuffersEXT(1 , rb) glGenRenderbuffersEXT(1 , sb) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , fb[0]) ; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_CUBE_MAP , texture.reference._index, 0) ; glBindRenderbufferEXT(GL_RENDERBUFFER_EXT , rb[0]) ; glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24 ,W, H); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT , GL_DEPTH_ATTACHMENT_EXT , GL_RENDERBUFFER_EXT , rb[0]) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , 0) glBindRenderbufferEXT(GL_RENDERBUFFER_EXT , 0) ; End Method Method Set(cubeface:Int) 'glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , fb[0]) SetBuffer(buffer) Select cubeface Case 0 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT ,GL_TEXTURE_CUBE_MAP_POSITIVE_X,texture.reference._index,0) Case 1 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT ,GL_TEXTURE_CUBE_MAP_NEGATIVE_X,texture.reference._index,0) Case 2 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT ,GL_TEXTURE_CUBE_MAP_POSITIVE_Y,texture.reference._index,0) Case 3 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT ,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,texture.reference._index,0) Case 4 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT ,GL_TEXTURE_CUBE_MAP_POSITIVE_Z,texture.reference._index,0) Case 5 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT ,GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,texture.reference._index,0) End Select 'glgetError() End Method Method Unset() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , 0) End Method Method CheckFBOStatus:Int(index:Int = 0) Local status:Int = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) Select status Case GL_FRAMEBUFFER_COMPLETE_EXT Print index + ": FBO Complete" Case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT Print index + ": Incomplete attachment" Case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT Print index + ": Missing attachment" Case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT Print index + ": Incomplete dimensions" Case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT Print index + ": Incomplete formats" Case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT Print index + ": Incomplete draw buffer" Case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT Print index + ": Incomplete read buffer" Case GL_FRAMEBUFFER_UNSUPPORTED_EXT Print index + ": Framebufferobjects unsupported" EndSelect Return Status End Method End Type
One downside is that currently I get INVALID_ENUM error in debug mode, but I have no idea why as it is thrown from engine itself. Also this is unfortunatly a Blitzmax only hack as it needs some access to some not provided fields. But maybe Josh can use this code to finally integrate proper support of realtime cubemapping into the engine.
thx for reading
klepto2
4 Comments
Recommended Comments