Forward clustered and Single Pass Stereo Rendering

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Forward clustered and Single Pass Stereo Rendering

Post by xrgo »

Hello! I need a little help with clustered forward.
While ago I implemented Single Pass Stereo Rendering (viewtopic.php?t=93686) its mainly vertex shader stuffs but I also have to do this adjustment to the pixel shader:
xrgo wrote: Sun Oct 29, 2017 6:35 pm So far working great, reflection looked weird/flat so I did this in the pixel shader:

Code: Select all

	@property( single_pass_stereo )
		vec3 viewDir	= normalize( -(inPs.pos - vec3( float( gl_FragCoord.x > @value( half_screen_width ) )*0.064, 0, 0 ) ) );
	@end
	@property( !single_pass_stereo )
		vec3 viewDir	= normalize( -inPs.pos );
	@end
so the viewDir of the right side of the viewport get adjusted as much as I offseted the right instance (0.064)
[/code]
(actually that 0.064 is now a 0.095 don't remember why, but that's not relevant)

Things like this has to be done since with single pass stereo you are basically rendering using one camera, so stuffs for the right eye that depends on the camera parameters/position/etc has to be adjusted.
I am rendering both eyes to a single texture so thats why I am doing:

Code: Select all

gl_FragCoord.x > @value( half_screen_width ) )
so its 0 for the left eye and 1 for the right, and I can do specific stuffs for each eye

Now the problem... using single pass stereo breaks forward clustered, lights disappear as I move the camera/head and sometimes I can distinguish the cells

I partially fixed the problem by doing this (line ~88 of Forward3D_piece_ps.glsl):

Code: Select all

uint sampleOffset = sliceSkip + uint(floor( FWDPLUS_APPLY_OFFSET_X(gl_FragCoord.x) * passBuf.fwdScreenToGrid.x @property( single_pass_stereo ) *2 @end ));
This makes the left eye works perfectly, now I need to solve the right eye...

tbh I don't understand too much the algorithm so I just tried different values for FWDPLUS_APPLY_OFFSET_X, like adding/substracting 0.5, multiplying by many values, and some other stuffs etc with no success

please help!
Many many thanks in advance!
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1279
Contact:

Re: Forward clustered and Single Pass Stereo Rendering

Post by dark_sylinc »

I cannot help you with the problem itself as it's specific to the changes you've made. But I can explain you the bits of the algorithm you're missing:

Forward clustered divides the screen in tiles, and then in slices. They're just two tables.

So the TL;DR version it boils down to this:

Code: Select all

uint16 fwdClusteredTable[table_width][table_height][num_slices][num_lights_per_cell+1];

xIdx = gl_FragCoord.x / table_width;
yIdx = gl_FragCoord.y / table_height;
numLights = fwdClusteredTable[xIdx][yIdx][sliceDepth][0];
for( int i=0; i<numLights; ++i )
{
    int tableIdx = fwdClusteredTable[xIdx][yIdx][sliceDepth][i + 1];
    Light *light = lightTable[tableIdx];
    calculateLighting( light );
}
Where table_width, table_height, num_slices & num_lights_per_cell are all the parameters you passed to SceneManager::setForwardClustered.
So when we do:

Code: Select all

uint sliceSkip = uint( fSlice * @value( fwd_clustered_width_x_height ) );

@property( !hlms_forwardplus_covers_entire_target )
	#define FWDPLUS_APPLY_OFFSET_Y(v) (v - passBuf.fwdScreenToGrid.w)
	#define FWDPLUS_APPLY_OFFSET_X(v) (v - passBuf.fwdScreenToGrid.z)
@end

uint sampleOffset = sliceSkip +
					uint(floor( FWDPLUS_APPLY_OFFSET_X(gl_FragCoord.x) * passBuf.fwdScreenToGrid.x ));
float windowHeight = passBuf.f3dData.w; //renderTarget->height
sampleOffset += uint(floor( (windowHeight - FWDPLUS_APPLY_OFFSET_Y(gl_FragCoord.y) ) *
							passBuf.fwdScreenToGrid.y ) *  @value( fwd_clustered_width ));
We're actually just doing:

Code: Select all

uint sampleOffset = sliceDepth * elementsPerTable + yIdx * elementsPerRow + xIdx
It SOUNDS like you want to xIdx to be multiplied by 2.0 for the left eye because [0; 960) at 1080p res needs to map to [0; 1080); while for the right eye you want (xIdx * 2.0 - 960) so that you can map [960; 1080) to [0; 1080).
Obviously the value of 960 is dynamic because it changes with the target's resolution (seems like passBuf.f3dViewportOffset.x would be a natural fit)
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Re: Forward clustered and Single Pass Stereo Rendering

Post by xrgo »

thank you so much, I am super duper mega dumb... I was doing the right thing but I was thinking in uv values [0,1], I need it to use pixel values like you mentioned... and I knew that since I already doing that in the code I posted, I actually have the @value( half_screen_width ) in pixels (I did that long ago so in my mind that was a 0.5)... so this solved 99% of the problems:

Code: Select all

	@property( hlms_forwardplus_covers_entire_target )
		#define FWDPLUS_APPLY_OFFSET_Y(v) (v)
		#define FWDPLUS_APPLY_OFFSET_X(v) (v - float( gl_FragCoord.x > @value( half_screen_width ) ) * @value( half_screen_width ) )
	@end
still a few tiny glitches in very far lights, but its enough for now, other stuffs to do

so, once again thank you very very much!
Post Reply