Jump to content
  • Advertisement
Sign in to follow this  
brekehan

Occlusion Query

This topic is 3502 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am picking my work back up trying to convert this XNA sample to DX10. I've gotten as far as the occlusion query, got it rendered, and even worked out how to actually make it get occluded by scene geometry while playing with the Z used to draw it. The sample is just too simple, they only have a terrain and the lensflare. I don't even think it would get occluded by scene geometry if there was any. But anywho... It seems my occlusion query only gets drawn every other frame. I understand I am returning if the GetData fails, but I don't really understand when the query takes place and for how long. If it was simply between query->Begin() and query->End() then it should never fail to get the data. My concern is that once I draw the glow part on top of the query, that the query will be occluded by the glow. Am I missing something? I understand I am going to turn off writes to the depth buffer, which I guess is going to make anything drawn after, get drawn on top. That's why I am confused as to when the query actually takes place. If it is immediately between the begin and end calls, then that would make sense. If it takes longer than it wouldn't. So, questions: 1) Why does the query get drawn every other frame. 2) Did I code up the query incorrectly opposed to somehow getting it every frame. 3) Does it indeed only occur between the query->begin() and query->end(), but take some time to actually give me back the data? 4) Won't my drawing the glow actually occlude the query?


#include "LensFlare.h"

// Common Lib Includes
#include "StringUtil.h"
#include "BaseException.h"

// Standard Includes
#include <algorithm>

using namespace common_lib_cpisz;

//---------------------------------------------------------------------------
LensFlare::LensFlare(ID3D10Device & device, 
                     InputLayoutManager & inputLayoutManager, 
                     TextureManager & textureManager,
                     EffectManager & effectManager,
                     Position lightPosition,
                     const std::string & glowTextureFilePath,
                     const std::string & flare1TextureFilePath,
                     const std::string & flare2TextureFilePath,
                     const std::string & flare3TextureFilePath)
   :
   m_querySize(100.0f),
   m_glowSize(400.0f),
   m_device(device),
   m_inputLayoutManager(inputLayoutManager),
   m_textureManager(textureManager),
   m_effectManager(effectManager),
   m_lightPosition(lightPosition),
   m_occlusionQuery(NULL),
   m_occlusionQueryActive(false)
{
   // SNIP long exception string

   // Load the textures
   std::string glowTextureName;
   std::string flare1TextureName;
   std::string flare2TextureName;
   std::string flare3TextureName;

   RemoveExtFromFilename(glowTextureFilePath, glowTextureName);
   RemoveExtFromFilename(flare1TextureFilePath, flare1TextureName);
   RemoveExtFromFilename(flare2TextureFilePath, flare2TextureName);
   RemoveExtFromFilename(flare3TextureFilePath, flare3TextureName);

   m_textureManager.CreateTextureFromFile(glowTextureName, glowTextureFilePath);
   m_textureManager.CreateTextureFromFile(flare1TextureName, flare1TextureFilePath);
   m_textureManager.CreateTextureFromFile(flare2TextureName, flare2TextureFilePath);
   m_textureManager.CreateTextureFromFile(flare3TextureName, flare3TextureFilePath);

   // Create the effects
   Technique * occlusionTechnique = NULL;
   
   try
   {
      m_effect           = &(m_effectManager.CreateChildEffect("LensFlare", "LensFlare.fx"));
      occlusionTechnique = &(m_effect->GetTechnique("OcclusionQuery"));
      m_occlusionPass    = &(occlusionTechnique->GetPass(0));
   }
   catch(BaseException & e)
   {
      throw e;
   }

   // Create materials
   try
   {
      m_occlusionMaterial = m_effect->CreateMaterial();
      m_occlusionMaterial->SetBool("diffuseMapped", true);
      m_occlusionMaterial->SetFloat4("diffuseColor", static_cast<D3DXVECTOR4>(D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f)));
   }
   catch(BaseException & e)
   {
      throw e;
   }

   // Create a occlusion query rectangle shape
   //
   // NOTE - vertices are defined in counter clockwise order, instead of clockwise,
   //        because the projection into 2D screen space flips the quad in the Y
   //        direction and it would get culled as a backface if defined normally
   std::vector<Position> occlusionPositions;

   occlusionPositions.push_back(Position( -0.5f, -0.5f, 0.0f));
   occlusionPositions.push_back(Position(  0.5f, -0.5f, 0.0f));
   occlusionPositions.push_back(Position( -0.5f,  0.5f, 0.0f));
   occlusionPositions.push_back(Position(  0.5f,  0.5f, 0.0f));
   
   m_occlusionBuffer = Buffer::SharedPtr(new Buffer(m_device, POSITION, occlusionPositions, false));

   // Create a input layouts
   std::vector<InputElementDescription> inputElementDescs;
   std::vector<InputElementDescription> thisElementDesc;

   InputElementDescription::GetInputElementDesc(thisElementDesc,
                                                m_occlusionBuffer->GetContentType(), 
                                                0,
                                                0,
                                                m_occlusionBuffer->IsPerInstance());

   inputElementDescs.insert(inputElementDescs.end(), thisElementDesc.begin(), thisElementDesc.end());

   m_occlusionInputLayout = m_inputLayoutManager.GetInputLayout(inputElementDescs, *m_occlusionPass);

   // Create the occlusion query
   D3D10_QUERY_DESC  queryDesc;
   queryDesc.MiscFlags = 0;
   queryDesc.Query     = D3D10_QUERY_OCCLUSION;
   if( FAILED(m_device.CreateQuery(&queryDesc, &m_occlusionQuery)) )
   {
      exception.m_msg = "Could not create occlusion query";
      throw exception;
   }

   // Init the flare circle datas
   m_flares.push_back(Flare(-0.5f, 0.7f, D3DXCOLOR( 50,  25,  50, 255), "flare1"));
   m_flares.push_back(Flare( 0.3f, 0.4f, D3DXCOLOR(100, 255, 200, 255), "flare1"));
   m_flares.push_back(Flare( 1.2f, 1.0f, D3DXCOLOR(100,  50,  50, 255), "flare1"));
   m_flares.push_back(Flare( 1.5f, 1.5f, D3DXCOLOR( 50, 100,  50, 255), "flare1"));

   m_flares.push_back(Flare(-0.3f, 0.7f, D3DXCOLOR(200,  50,  50, 255), "flare2"));
   m_flares.push_back(Flare( 0.6f, 0.9f, D3DXCOLOR( 50, 100,  50, 255), "flare2"));
   m_flares.push_back(Flare( 0.7f, 0.4f, D3DXCOLOR( 50, 200, 200, 255), "flare2"));

   m_flares.push_back(Flare(-0.7f, 0.7f, D3DXCOLOR( 50, 100,  25, 255), "flare3"));
   m_flares.push_back(Flare( 0.0f, 0.6f, D3DXCOLOR( 25,  25,  25, 255), "flare3"));
   m_flares.push_back(Flare( 2.0f, 1.4f, D3DXCOLOR( 25,  50, 100, 255), "flare3"));
}


//---------------------------------------------------------------------------
LensFlare::~LensFlare()
{
   // Release the occlusion query
   if( m_occlusionQuery )
   {
      m_occlusionQuery->Release();
   }
}

//---------------------------------------------------------------------------
void LensFlare::Render()
{
   // Get the original matrices
   D3DXMATRIX origProjection;
   D3DXMATRIX origView;

   m_effectManager.GetViewMatrix(origView);
   m_effectManager.GetProjectionMatrix(origProjection);

   // Get the viewport
   UINT             numViewports = 1;
   D3D10_VIEWPORT   viewport;

   m_device.RSGetViewports(&numViewports, &viewport);

   // Create new view matrix with the camera at the origin for projection of the position into the background
   D3DXMATRIX newView = origView;
   newView._41 = newView._42 = newView._43 = 0.0f;
   newView._44 = 1.0f;

   // Project the light position into 2D screen space
   D3DXMATRIX identity;
   D3DXMatrixIdentity(&identity);

   D3DXVECTOR3 projectedPosition;
   D3DXVec3Project(&projectedPosition, &m_lightPosition, &viewport, &origProjection, &newView, &identity);

   // Don't draw any flares if the light is behind the camera
   if( (projectedPosition.z < 0.0f) || (projectedPosition.z > 1.0f) )
   {
      return;
   }

   D3DXVECTOR3 lightPosition(projectedPosition.x, projectedPosition.y, projectedPosition.z);

   // Set up matrices to render in screen space
   D3DXMatrixIdentity(&newView);
   m_effectManager.SetViewMatrix(newView);

   D3DXMATRIX newProjection;
   D3DXMatrixOrthoOffCenterLH(&newProjection,
                              0.0f,
                              static_cast<float>(viewport.Width),
                              static_cast<float>(viewport.Height),
                              0.0f,
                              0.0f,
                              1.0f);

   m_effectManager.SetProjectionMatrix(newProjection);

   // Check whether the light is occluded by the scene
   UpdateOcclusion(lightPosition);

   // If it is visible, draw the flare
   if( m_occlusionAlpha > 0 )
   {
      RenderGlow(D3DXVECTOR2(lightPosition.x, lightPosition.y));
      RenderFlares(D3DXVECTOR2(lightPosition.x, lightPosition.y));
   }

   // Restore Matrices
   m_effectManager.SetViewMatrix(origView);
   m_effectManager.SetProjectionMatrix(origProjection);
}

//---------------------------------------------------------------------------
void LensFlare::UpdateOcclusion(D3DXVECTOR3 lightPosition)
{
   if( m_occlusionQueryActive )
   {
      // If the previous query has not yet completed, wait until it does
      UINT64 queryData;

      if( S_OK != m_occlusionQuery->GetData(&queryData, sizeof(UINT64), 0) )
      {
         return;
      }

      // Use the occlusion query pixel count to work out what percentage of the sun is visible
      const float queryArea = m_querySize * m_querySize;
      m_occlusionAlpha = std::min<float>(static_cast<float>(queryData) / queryArea, 1.0f);
   }

   // Set the world matrix and material
   D3DXMATRIX matScale;
   D3DXMATRIX matTranslation;
   D3DXMATRIX world;

   D3DXMatrixScaling(&matScale, m_querySize, m_querySize, 1.0f);
   D3DXMatrixTranslation(&matTranslation, lightPosition.x, lightPosition.y, lightPosition.z);
   D3DXMatrixMultiply(&world, &matScale, &matTranslation);
   
   try
   {
      m_effect->SetWorldMatrix(world);
      m_effect->SetMaterial(*m_occlusionMaterial);
   }
   catch(BaseException & e)
   {
      throw e;
   }

   // Bind the input layout
   m_device.IASetInputLayout(m_occlusionInputLayout);
   m_device.IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

   // Bind the vertex buffers
   ID3D10Buffer * buffer = m_occlusionBuffer->GetD3DBuffer();
   UINT           stride = GetStride(m_occlusionBuffer->GetContentType());
   UINT           offset = 0;
   
   m_device.IASetVertexBuffers(0,
                               1,
                               &buffer, 
                               &stride, 
                               &offset);

   // Apply the pass
   m_occlusionPass->Apply();

   // Issue the occlusion query
   m_occlusionQuery->Begin();
   m_device.Draw(4, 0);
   m_occlusionQuery->End();

   // Flag the occlusion query as active
   m_occlusionQueryActive = true;

/*
   // Set renderstates for drawing the occlusion query geometry. We want depth
   // tests enabled, but depth writes disabled, and we set ColorWriteChannels
   // to None to prevent this query polygon actually showing up on the screen.
   RenderState renderState = GraphicsDevice.RenderState;

   renderState.DepthBufferEnable = true;
   renderState.DepthBufferWriteEnable = false;
   renderState.AlphaTestEnable = false;
   renderState.ColorWriteChannels = ColorWriteChannels.None;


   // Reset renderstates.
   renderState.ColorWriteChannels = ColorWriteChannels.All;
   renderState.DepthBufferWriteEnable = true;
*/
}

//---------------------------------------------------------------------------
void LensFlare::RenderFlares(D3DXVECTOR2 lightPosition)
{
/*
   Viewport viewport = GraphicsDevice.Viewport;

   // Lensflare sprites are positioned at intervals along a line that
   // runs from the 2D light position toward the center of the screen.
   Vector2 screenCenter = new Vector2(viewport.Width, viewport.Height) / 2;
   
   Vector2 flareVector = screenCenter - lightPosition;

   // Draw the flare sprites using additive blending.
   spriteBatch.Begin(SpriteBlendMode.Additive);

   foreach (Flare flare in flares)
   {
       // Compute the position of this flare sprite.
       Vector2 flarePosition = lightPosition + flareVector * flare.Position;

       // Set the flare alpha based on the previous occlusion query result.
       Vector4 flareColor = flare.Color.ToVector4();

       flareColor.W *= occlusionAlpha;

       // Center the sprite texture.
       Vector2 flareOrigin = new Vector2(flare.Texture.Width,
                                         flare.Texture.Height) / 2;

       // Draw the flare.
       spriteBatch.Draw(flare.Texture, flarePosition, null,
                        new Color(flareColor), 1, flareOrigin,
                        flare.Scale, SpriteEffects.None, 0);
   }

   spriteBatch.End();
*/
}

//---------------------------------------------------------------------------
void LensFlare::RenderGlow(D3DXVECTOR2 lightPosition)
{  
   /*
   Vector4 color  = new Vector4(1, 1, 1, occlusionAlpha);
   Vector2 origin = new Vector2(glowSprite.Width, glowSprite.Height) / 2;
   float   scale  = glowSize * 2 / glowSprite.Width;

   spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

   spriteBatch.Draw(glowSprite, lightPosition, null, new Color(color), 0,
                    origin, scale, SpriteEffects.None, 0);

   spriteBatch.End();
   */
}

//---------------------------------------------------------------------------
LensFlare::Flare::Flare(float position, float scale, const D3DXCOLOR & color, const std::string & textureName)
   :
m_position(position),
m_scale(scale),
m_color(color),
m_textureName(textureName)
{         
}

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!