Volumetric lighting

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
User avatar
Florin
Kobold
Posts: 33
Joined: Thu Mar 19, 2009 3:15 am

Re: Volumetric lighting

Post by Florin »

I need it too. Anyone has it already ?
lilljohan
Halfling
Posts: 82
Joined: Tue Jan 03, 2006 4:05 pm
Location: Växjö, Sweden

Re: Volumetric lighting

Post by lilljohan »

db123
Halfling
Posts: 78
Joined: Wed May 21, 2008 5:55 am

Re: Volumetric lighting

Post by db123 »

:D what is the lowest system configuration?
In my bad computor, it's so slow.
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Volumetric lighting

Post by duststorm »

Maybe someone can help me with my problem.
I'm trying to implement the godrays post effect using an occlusion pre-process, like proposed in the GPU Gems article and shown here.

What I'm doing now is render the scene first using a shader that paints objects fully black. However, when doing this I have problems with materials that have transparency, like trees, because they are completely rendered in black.
Does anyone have a suggestion how I could make it account for transparency without inducing too much speed loss. I fear that if I have to start calculating texture coordinates and sample alpha color values from the texture I will create a rather slow post process.

Some screens to illustrate my problem better:
occlusion_colors.jpg
occlusion_occluder.jpg
So I render all non-sky elements as black occluded objects. This is fine except for objects with transparency, like the trees. There are two trees in the scene that are geometry, the rest of the treeline is a just a simple quad with a semi-transparent texture applied to it. This is why there is a straight line of black on the horizon in the occlusion render, with the two geometry trees sticking out slightly.

What would be the best way to account for this transparency? Some depth buffer trick or should I go on and sample the original texture's alpha channel in the occlusion shader?
You do not have the required permissions to view the files attached to this post.
Developer @ MakeHuman.org
User avatar
razi
Greenskin
Posts: 130
Joined: Tue Oct 14, 2008 5:54 pm
Location: Slovakia
x 17

Re: Volumetric lighting

Post by razi »

I dont think there much you can do except for if(alpha<1) discard;. But you can always use MRT, I use it to get this effect. :)
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Volumetric lighting

Post by duststorm »

razi wrote:I dont think there much you can do except for if(alpha<1) discard;. But you can always use MRT, I use it to get this effect. :)
Thanks! I didn't know that technique yet. I'll look into it, maybe I use it instead of a compositor.
Or is it in fact the same thing a compositor does, only without the need to setup compositor scripts?

I made some progress. The occluders render correctly now.
occluder08212011_122941646.bmp.jpg
The solution to making the trees render correctly was to create a new material technique for each material (this could be optimized a little by only making one for each texture that has an alpha technique, for matte textures you can use on shared occluding technique).
Here is a snippet to illustrate how I create the occluder material. This is a MaterialManager::Listener I use for getting the occluder material for each material, without having to define it manually in all my material scripts. (In my opinion, even using material inheritance is still too tedious)

Code: Select all

ExtraMaterialSchemesListener::ExtraMaterialSchemesListener()
{
    this->OCCLUDERS_NAME = "occluders";
    this->CAELUM_NAME = "Caelum";

    // Create technique for "occluders" material scheme
    Ogre::ResourcePtr res = Ogre::MaterialManager::getSingleton().load("PlainColor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
    this->occludersTechnique = static_cast<Ogre::MaterialPtr>(res)->getTechnique(0);
}

Ogre::Technique* ExtraMaterialSchemesListener::handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, unsigned short lodIndex, const Ogre::Renderable *rend)
{
    if(( originalMaterial->getGroup() == CAELUM_NAME) )   // Render materials belonging to Caelum group regularly
        return NULL;

    if(schemeName == OCCLUDERS_NAME /*&& ! Ogre::StringUtil::startsWith(originalMaterial->getName(), "caelum")*/ ) {
        // Create occluder material with this specific texture, if it doesnt exist yet
        Ogre::MaterialPtr occluder_material = Ogre::MaterialManager::getSingleton().getByName(originalMaterial->getName()+"/occluder");
        if (occluder_material.isNull()) {
            occluder_material = Ogre::MaterialManager::getSingleton().create(originalMaterial->getName()+"/occluder", "u24");
            // Link original texture to this material (only needed for its alpha value, if applicable)
            // TODO you should only copy texture if it has an alpha channel
            Ogre::Pass::TextureUnitStateIterator tui = originalMaterial->getTechnique(0)->getPass(0)->getTextureUnitStateIterator();
            if(tui.begin() < tui.end()) {
                Ogre::TextureUnitState* firstTextureUnitState = tui.getNext();
                Ogre::String textureName = firstTextureUnitState->getTextureName();
                occluder_material->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName( textureName );
                Ogre::Pass *pass = occluder_material->getTechnique(0)->getPass(0);
                // Copy original texture alpha settings
                pass->setAlphaRejectFunction(originalMaterial->getTechnique(0)->getPass(0)->getAlphaRejectFunction());  //Ogre::CMPF_GREATER
                pass->setAlphaRejectValue(originalMaterial->getTechnique(0)->getPass(0)->getAlphaRejectValue());    // 192
                // Copy original texture culling settings (for double sided textures)
                pass->setCullingMode(originalMaterial->getTechnique(0)->getPass(0)->getCullingMode());
                pass->setManualCullingMode(originalMaterial->getTechnique(0)->getPass(0)->getManualCullingMode());
            } else {
                // TODO maybe set some default black (or white) texture or something, with alpha 1
            }
            occluder_material->getTechnique(0)->getPass(0)->setFragmentProgram(occludersTechnique->getPass(0)->getFragmentProgramName());
            occluder_material->getTechnique(0)->getPass(0)->setVertexProgram(occludersTechnique->getPass(0)->getVertexProgramName());

            occluder_material->load();
        }
        return occluder_material->getTechnique(0);
    }

    // Return null to select the default material scheme for this material
    return NULL;
}
The shader is something very simple. It's a solid color shader that samples the alpha channel of the texture and appends that to the output.

Code: Select all

void main_plain_color_vp(
		// Vertex Inputs
		float4 position		: POSITION,	// Vertex position in model space
		float2 texCoord0	: TEXCOORD0,	// Texture UV set 0
 
		// Outputs
		out float4 oPosition	: POSITION,	// Transformed vertex position
		out float2 uv0		: TEXCOORD0,	// UV0
 
		// Model Level Inputs
		uniform float4x4 worldViewProj)
{
	// Calculate output position
	oPosition = mul(worldViewProj, position);
 
	// Simply copy the input vertex UV to the output
	uv0 = texCoord0;
}
 
// simple and fast shader, no lighting is done
void main_plain_color_fp(
		// Pixel Inputs
		float2 uv0		: TEXCOORD0,	// UV interpolated for current pixel	 
		// Outputs
		out float4 color	: COLOR,	// Output color we want to write
		
		// Model Level Inputs
        uniform sampler2D texture,        // Texture we're going to use (for alpha)

		// Configurable parameter: Color we want rendered
		uniform float4 inColor
		)
{	 
	// Return configured color with alpha sampled from texture
	color = tex2D(texture, uv0);	// Sample color from texture (we will only keep alpha)
	color.rgb = inColor.rgb;		// Replace output RGB color values by configured color
}
The material script for this is equally trivial:

Code: Select all

vertex_program PlainColor_VS cg
{
	source plaincolor.cg
	entry_point main_plain_color_vp
	profiles vs_1_1 arbvp1
 
	default_params
	{
		param_named_auto worldViewProj worldviewproj_matrix		
	}
 
}
 
fragment_program PlainColor_PS cg			
{
	source plaincolor.cg		
	entry_point main_plain_color_fp	
	profiles ps_1_1 arbfp1
 
	default_params
	{
		param_named inColor float4 0 0 0 0
	}
}	
 
material PlainColor
{
        // Material has one technique
	technique					
	{
                // This technique has one pass
		pass					
		{
                        // Make this pass use the vertex shader defined above
			vertex_program_ref PlainColor_VS	
			{
			}
                        // Make this pass use the pixel shader defined above
			fragment_program_ref PlainColor_PS	
			{
			      param_named_auto inColor custom 1
			}
		}
	}
}
The occlusion pass works pretty well now. Here's another screenshot to illustrate how it handles materials with transparency:
occluder08212011_122953222.bmp.jpg
You do not have the required permissions to view the files attached to this post.
Developer @ MakeHuman.org
User avatar
razi
Greenskin
Posts: 130
Joined: Tue Oct 14, 2008 5:54 pm
Location: Slovakia
x 17

Re: Volumetric lighting

Post by razi »

It doesnt matter if using compositor or not, Multiple render targets means you are rendering to multiple targets at once :D. So your shader looks like

Code: Select all

// simple and fast shader, no lighting is done
void main_plain_color_fp(
      out float4 color0   : COLOR0,
      out float4 color1   : COLOR1,
      ...
      )
{    
color0 = tex2D(texture, uv0);
color1 = float4(0,0,0,color0.a);
}
and you have 2 different rendered textures after one pass.
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Volumetric lighting

Post by duststorm »

razi wrote:It doesnt matter if using compositor or not, Multiple render targets means you are rendering to multiple targets at once :D. (...) you have 2 different rendered textures after one pass.
Ah, that's how it works! Thanks, that's enlightening! :)

I have it more or less working, I only need to find a rays shader and parameters that give an effect that I'm satisfied with.
Developer @ MakeHuman.org