Jump to content

cubemaps? realtime? Here we go!

klepto2

2,346 views

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

Guest Red Ocktober

Posted

yup... more excellent stuff from planet klepto...

 

:)

 

--Mike

Share this comment


Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...