Sign in to follow this  
mazelle

How to fix this? (Glow effect artifact)

Recommended Posts

mazelle    106
This is my problem (see encircled): It seems that the pixels that resulted from blur convolution was carried over to the opposite edge. This is also exhibited in left/right edges. This is my GlowProcessor class:
class GlowProcessor : public virtual IDeviceDependentLoader
{
public:
  /**
   * Defualt constructor.
   */
  GlowProcessor()
  {
    getScreenAlignedProjection()->setViewVolumeReduction( 1.0f );
    getScreenAlignedProjection()->setAspectRatio( 1.0f );
  }

  /**
   * Virtual destructor.
   */
  virtual ~GlowProcessor()
  {
  }

  /**
   * Loads the required resources.
   */
  void load( IDirect3DDevice9* const device )
  {
    setDevice( device );

    // load quad
    getQuad()->setRenderingProcedure( QuadTriangleListProcedure::getInstance() );
    getQuad()->loadRenderable( device );

    // load blur effect
    Effect* const blurEffect = CommonEffects::getBlurEffect( device );
    setBlurEffect( blurEffect );

    // set screen width and height variables
    blurEffect->setFloat( EffectVariables::SCREEN_WIDTH, ( float ) GraphicsConstants::DEFAULT_SCREEN_WIDTH );
    blurEffect->setFloat( EffectVariables::SCREEN_HEIGHT, ( float ) GraphicsConstants::DEFAULT_SCREEN_HEIGHT );

    // load blur textures (textures are half of the specified dimension)
    getBlurTextures()->load( device, GraphicsConstants::DEFAULT_SCREEN_WIDTH >> 1, GraphicsConstants::DEFAULT_SCREEN_HEIGHT >> 1 );
  }

  /**
   * Applies the blur on the specified surface.
   */
  void process( IDirect3DSurface9* const surface )
  {
    setMainSurface( surface );
    copyMainSurface();
    constructBlur();
  }

private:
  typedef Quad< TexturedUQuadVL<XYQuadCoordinates> > XYQuad;

private:
  /**
   * Copies the main surface.
   */
  void copyMainSurface()
  {
    IDirect3DDevice9* const device = getDevice();
    device->BeginScene();

    // get scene copy surface
    Texture* const sceneCopyTexture = getSceneCopyTexture();
    IDirect3DSurface9* const sceneCopySurface = sceneCopyTexture->getSurface();

    // copy main surface to sceneCopy surface
    device->StretchRect( getMainSurface(), null, sceneCopySurface, null, D3DTEXF_LINEAR );

    device->EndScene();
  }

  /**
   * Constructs the blurred texture.
   */
  void constructBlur()
  {
    IDirect3DDevice9* const device = getDevice();

    // store original surface from device
    IDirect3DSurface9* originalSurface = null;
    device->GetRenderTarget( 0, &originalSurface );

    // -- Apply Horizontal Blur --
    // set render target to horizontalBlurTexture
    device->SetRenderTarget( 0, getHorizontalBlurTexture()->getSurface() );
    device->Clear( 0, null, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0 );

    device->BeginScene();
    renderTextureWithBlur( getSceneCopyTexture(), CommonEffects::HORIZONTAL_BLUR );
    device->EndScene();

    // -- Apply Vertical Blur --
    // set render target to horizontalBlurTexture
    device->SetRenderTarget( 0, getVerticalBlurTexture()->getSurface() );
    device->Clear( 0, null, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0 );

    device->BeginScene();
    renderTextureWithBlur( getHorizontalBlurTexture(), CommonEffects::VERTICAL_BLUR );
    device->EndScene();

    // restore original surface
    device->SetRenderTarget( 0, originalSurface );

    device->BeginScene();

    // overlay final texture to glow scene
    renderTextureWithBlur( getVerticalBlurTexture(), CommonEffects::BLUR_OVERLAY );
    device->EndScene();
  }

  /**
   * Renders the scene with horizontal blur.
   */
  void renderTextureWithBlur( Texture* const sourceTexture, const String& technique )
  {
    static Effect* const effect = getBlurEffect();

    effect->setTechnique( technique );

    // set view-proj matrix
    effect->setMatrix( EffectVariables::VIEW_PROJECTION_MATRIX, getScreenAlignedProjection()->getViewProjMatrix() );

    // set world matrix
    static GlowProcessor::XYQuad* const quad = getQuad();
    effect->setMatrix( EffectVariables::WORLD_MATRIX, quad->getTransformation() );

    // set texture
    effect->setTexture( EffectVariables::TEXTURE0, sourceTexture );

    // set modulation color
    effect->setFloatArray( EffectVariables::MODULATION_COLOR, RGBAColor::WHITE.getColorAsArray(), 4 );

    effect->beginRender();
    while( effect->hasMorePasses() )
    {
      effect->beginPass();
      effect->commitChanges();
      quad->render();
      effect->endPass();
    }
    effect->endRender();
  }

  /**
   * Returns the quad.
   */
  XYQuad* const getQuad()
  {
    return &this->quad;
  }

  /**
   * Returns the scene copy texture.
   */
  Texture* const getSceneCopyTexture()
  {
    return getBlurTextures()->getSceneCopyTexture();
  }

  /**
   * Returns the ScreenAlignedProjection instance.
   */
  ScreenAlignedProjection* const getScreenAlignedProjection()
  {
    return &this->screenAlignedProjection;
  }

  /**
   * Returns the device instance.
   */
  IDirect3DDevice9* const getDevice()
  {
    return this->device.getContainedObject();
  }

  /**
   * Sets the device.
   */
  void setDevice( IDirect3DDevice9* const device )
  {
    this->device.setContainedObject( device );
  }

  /**
   * Returns the main surface.
   */
  IDirect3DSurface9* const getMainSurface()
  {
    return this->mainSurface.getContainedObject();
  }

  /**
   * Sets the main surface.
   */
  void setMainSurface( IDirect3DSurface9* const surface )
  {
    this->mainSurface.setContainedObject( surface );
  }

  /**
   * Returns the blur effect.
   */
  Effect* const getBlurEffect()
  {
    return this->blurEffect.getContainedObject();
  }

  /**
   * Sets the blur effect.
   */
  void setBlurEffect( Effect* const effect )
  {
    this->blurEffect.setContainedObject( effect );
  }

  /**
   * Returns the blur texture.
   */
  Texture* const getHorizontalBlurTexture()
  {
    return getBlurTextures()->getHorizontalBlurTexture();
  }

  Texture* const getVerticalBlurTexture()
  {
    return getBlurTextures()->getVerticalBlurTexture();
  }

  /**
   * Returns the BlurTextures instance.
   */
  BlurTextures* const getBlurTextures()
  {
    return &this->blurTextures;
  }

private:
  ObjectContainment<IDirect3DDevice9> device;

  ObjectContainment<IDirect3DSurface9> mainSurface;

  BlurTextures blurTextures;

  ObjectContainment<Effect> blurEffect;

  XYQuad quad;

  ScreenAlignedProjection screenAlignedProjection;
};

// Sample Usage
GlowProcessor glowProcessor; // this is best stored as a member object

// then somewhere at the initialize period
this->glowProcessor.load( device );

// then after rendering the scene (post processing)
// get back buffer surface
IDirect3DDevice9* const device = getDevice();
IDirect3DSurface9* backSurface = null;
device->GetRenderTarget( 0, &backSurface );

// apply glow
this->glowProcessor.process( backSurface );


This is the effect file used by GlowProcessor:
#include "CommonEffects.fx"

const float BLUR_WEIGHTS[7] = {
  0.00443185,
  0.053991,
  0.241971,
  0.398942,
  0.241971,
  0.053991,
  0.00443185
};

/**
 * Returns whether or not the color component is almost black.
 */
bool isAlmostBlack( float colorComponent ) {
  return colorComponent <= 0.0001;
}

/**
 * Returns whether the specified color is black.
 */
bool isBlack( float4 color ) {
  return isAlmostBlack( color.r ) &&
      isAlmostBlack( color.g ) &&
      isAlmostBlack( color.b );
}

float STEP_DOWNSIZE_FACTOR = 0.167;
float BLUR_FACTOR = 1.5;

/**
 * Horizontal Blur.
 */
float4 HorizontalBlurPS( float2 inTexCoord : TEXCOORD0 ) : COLOR0 {
  float4 color = 0;
  float horizontalStep = ( 1.0 / ( SCREEN_WIDTH * STEP_DOWNSIZE_FACTOR ) );
  int center = 3;
  
  for( int i = 0; i < 7; i++ ) {
    float xLookupCoord = inTexCoord.x + ( ( i - center ) * horizontalStep );
    
    float2 lookupCoord = { xLookupCoord, inTexCoord.y };
    color += tex2D( Sampler, lookupCoord ) * BLUR_WEIGHTS[ i ];
  }
  
  // set to pure transparent if color is black
  if( isBlack( color ) ) {
    color.a = 0.0;
    return color;
  }
  
  return color * BLUR_FACTOR;
}

/**
 * Vertical Blur
 */
float4 VerticalBlurPS( float2 inTexCoord : TEXCOORD0 ) : COLOR0 {
  float4 color = 0;
  float verticalStep = ( 1.0 / ( SCREEN_HEIGHT * STEP_DOWNSIZE_FACTOR ) );
  int center = 3;
  
  for( int i = 0; i < 7; i++ ) {
    float yLookupCoord = inTexCoord.y + ( ( i - center ) * verticalStep );
  
    float2 lookupCoord = { inTexCoord.x, yLookupCoord };
    color += tex2D( Sampler, lookupCoord ) * BLUR_WEIGHTS[ i ];
  }
  
  // set to pure transparent if color is black
  if( isBlack( color ) ) {
    color.a = 0.0;
    return color;
  }
  
  return color * BLUR_FACTOR;
}

/**
 * Horizontal blur technique.
 */
technique HorizontalBlur {
  pass FirstPass {
    Lighting = FALSE;
    
    AlphaBlendEnable = true;
    SrcBlend = One;
    DestBlend = One;

    Sampler[0] = (Sampler); // Needed by pixel shader

    VertexShader = compile vs_2_0 TextureColorModulationVS();
    PixelShader  = compile ps_2_0 HorizontalBlurPS();
  }
}

/**
 * Vertical blur technique.
 */
technique VerticalBlur {
  pass FirstPass {
    Lighting = FALSE;
    
    AlphaBlendEnable = true;
    SrcBlend = One;
    DestBlend = One;

    Sampler[0] = (Sampler); // Needed by pixel shader

    VertexShader = compile vs_2_0 TextureColorModulationVS();
    PixelShader  = compile ps_2_0 VerticalBlurPS();
  }
}

/**
 * Technique to use when overlaying the blur texture for glow effect.
 */
technique BlurOverlay {
  pass FirstPass {
    Lighting = FALSE;
    
    AlphaBlendEnable = true;
    SrcBlend = One;
    DestBlend = One;

    Sampler[0] = (Sampler); // Needed by pixel shader

    VertexShader = compile vs_2_0 TextureColorModulationVS();
    PixelShader  = compile ps_2_0 textureMap();
  }
}


Share this post


Link to post
Share on other sites
Armadon    1091
Maybe it's just me but I cannot really see a problem. Did you intend to make the game so that when you fly/move through an edge that the object will appear on the opposite edge? if so, I don't see a problem.

Share this post


Link to post
Share on other sites
mazelle    106
No, nothing like that. The object will just have to move forward. The problem is that when an object is on or near the edge, the blur generated pixels around that object is rendered on the opposite side, somewhat like being carried over to the opposite edge. I don't want that to happen.

Share this post


Link to post
Share on other sites
Steve132    433
Whatever graphics API you are using, make sure that texture wrapping on the convolution step is defined to clamp, not wrap, otherwise a texture read that is "offscreen" will loop around like that in screen space.

Share this post


Link to post
Share on other sites
sirob    1181
The texture wrapping mode (WRAP, CLAMP (the one you want), etc.) are part of the sampler state.

In the code you pasted, you are setting the sampler state:
 Sampler[0] = (Sampler); // Needed by pixel shader
I'm not too sure about the syntax here, but I think you might be setting the state to 0 somehow, or maybe a sampler state oddly named (Sampler) appears in one of your includes.

Either way, you'd set it something like this:

sampler yourSampler = sampler_state
{
ADDRESSU = CLAMP;
ADDRESSV = CLAMP;
};

Then you'd set "yourSampler" as the active sampler state. Hope this helps.

Share this post


Link to post
Share on other sites
mazelle    106
Sampler is found in CommonEffects.fx.

I fixed it now. I made a separate sampler state for use in blur passes that has ADDRESSU and ADDRESSV set to CLAMP.

Thanks for all your help.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this