Skip to content
This repository has been archived by the owner on Feb 3, 2025. It is now read-only.

LensFlare - allow inheritance #2965

Merged
merged 4 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 105 additions & 96 deletions gazebo/rendering/LensFlare.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

#include "gazebo/transport/Node.hh"

#include "gazebo/rendering/ogre_gazebo.h"
#include "gazebo/rendering/Camera.hh"
#include "gazebo/rendering/Conversions.hh"
#include "gazebo/rendering/Light.hh"
Expand All @@ -34,56 +33,72 @@ namespace gazebo
{
namespace rendering
{
/// \brief We'll create an instance of this class for each camera, to be
/// used to inject lens flare uniforms in each render call.
class LensFlareCompositorListener
: public Ogre::CompositorInstance::Listener
/// \brief Private data class for LensFlareCompositorListener
class LensFlareCompositorListenerPrivate
{
/// \brief Constructor
public: LensFlareCompositorListener(CameraPtr _camera, LightPtr _light)
/// \brief Pointer to light
public: LightPtr light;

/// \brief Pointer to camera
public: CameraPtr camera;

/// \brief Dummy camera used by wide angle camera for occlusion checking
public: CameraPtr wideAngleDummyCamera;

/// \brief Position of light in world frame
public: ignition::math::Vector3d lightWorldPos;

/// \brief Scale of lens flare.
public: double scale = 1.0;

/// \brief Color of lens flare.
public: ignition::math::Vector3d color
= ignition::math::Vector3d(1.0, 1.0, 1.0);
};

//////////////////////////////////////////////////
LensFlareCompositorListener::LensFlareCompositorListener(CameraPtr _camera,
LightPtr _light)
: dataPtr(new LensFlareCompositorListenerPrivate)
{
this->camera = _camera;
this->dataPtr->camera = _camera;
this->SetLight(_light);
}

/// \brief Destructor
public: ~LensFlareCompositorListener()
//////////////////////////////////////////////////
LensFlareCompositorListener::~LensFlareCompositorListener()
{
if (this->wideAngleDummyCamera)
if (this->dataPtr->wideAngleDummyCamera)
{
this->wideAngleDummyCamera->GetScene()->RemoveCamera(
this->wideAngleDummyCamera->Name());
this->dataPtr->wideAngleDummyCamera->GetScene()->RemoveCamera(
this->dataPtr->wideAngleDummyCamera->Name());
}
}

/// \brief Set directional light that generates lens flare
/// \param[in] _light Pointer to directional light
public: void SetLight(LightPtr _light)
//////////////////////////////////////////////////
void LensFlareCompositorListener::SetLight(LightPtr _light)
{
this->light = _light;
this->dataPtr->light = _light;
}

/// \brief Set the scale of lens flare.
/// \param[in] _scale Scale of lens flare
public: void SetScale(const double _scale)
//////////////////////////////////////////////////
void LensFlareCompositorListener::SetScale(const double _scale)
{
this->scale = _scale;
this->dataPtr->scale = _scale;
}

/// \brief Set the color of lens flare.
/// \param[in] _color Color of lens flare
public: void SetColor(const ignition::math::Vector3d &_color)
//////////////////////////////////////////////////
void LensFlareCompositorListener::SetColor(
const ignition::math::Vector3d &_color)
{
this->color = _color;
this->dataPtr->color = _color;
}

/// \brief Callback that OGRE will invoke for us on each render call
/// \param[in] _passID OGRE material pass ID.
/// \param[in] _mat Pointer to OGRE material.
public: virtual void notifyMaterialRender(unsigned int _passId,
//////////////////////////////////////////////////
void LensFlareCompositorListener::notifyMaterialRender(unsigned int _passId,
Ogre::MaterialPtr &_mat)
{
if (!this->light)
if (!this->dataPtr->light)
{
// return if this->light is not set, we may still be initializing
return;
Expand All @@ -104,54 +119,55 @@ namespace gazebo

// for adjusting aspect ratio of flare
params->setNamedConstant("viewport",
Ogre::Vector3(static_cast<double>(this->camera->ViewportWidth()),
static_cast<double>(this->camera->ViewportHeight()), 1.0));
Ogre::Vector3(
static_cast<double>(this->dataPtr->camera->ViewportWidth()),
static_cast<double>(this->dataPtr->camera->ViewportHeight()),
1.0));

// use light's world position for lens flare position
if (this->light->Type() == "directional")
if (this->dataPtr->light->Type() == "directional")
{
// Directional lights misuse position as a direction.
// The large multiplier is for occlusion testing and assumes the light
// is very far away. Larger values cause the light to disappear on
// some frames for some unknown reason.
this->lightWorldPos = -(this->light->WorldPose().Rot() *
light->Direction()) * 100000.0;
this->dataPtr->lightWorldPos =
-(this->dataPtr->light->WorldPose().Rot() *
this->dataPtr->light->Direction()) * 100000.0;
}
else
this->lightWorldPos = this->light->WorldPose().Pos();
this->dataPtr->lightWorldPos = this->dataPtr->light->WorldPose().Pos();

ignition::math::Vector3d pos;
double lensFlareScale = 1.0;

// wide angle camera has a different way of projecting 3d points and
// occlusion checking
auto wideAngleCam =
boost::dynamic_pointer_cast<WideAngleCamera>(this->camera);
boost::dynamic_pointer_cast<WideAngleCamera>(this->dataPtr->camera);
if (wideAngleCam)
this->WideAngleCameraPosScale(wideAngleCam, pos, lensFlareScale);
else
this->CameraPosScale(this->camera, pos, lensFlareScale);
this->CameraPosScale(this->dataPtr->camera, pos, lensFlareScale);

params->setNamedConstant("lightPos", Conversions::Convert(pos));
params->setNamedConstant("scale",
static_cast<Ogre::Real>(lensFlareScale));
params->setNamedConstant("color",
Ogre::Vector3(this->color.X(), this->color.Y(), this->color.Z()));
Ogre::Vector3(this->dataPtr->color.X(), this->dataPtr->color.Y(),
this->dataPtr->color.Z()));
}

/// \brief Get the lens flare position and scale for a normal camera
/// \param[in] _camera Camera which the lens flare is added to
/// \param[out] _pos lens flare position in normalized device coordinates
/// \param[out] _scale Amount to scale the lens flare by.
private: void CameraPosScale(const CameraPtr &_camera,
//////////////////////////////////////////////////
void LensFlareCompositorListener::CameraPosScale(const CameraPtr &_camera,
ignition::math::Vector3d &_pos, double &_scale)
{
Ogre::Vector3 lightPos;
// project 3d world space to clip space
auto viewProj = _camera->OgreCamera()->getProjectionMatrix() *
_camera->OgreCamera()->getViewMatrix();
auto pos = viewProj * Ogre::Vector4(
Conversions::Convert(this->lightWorldPos));
Conversions::Convert(this->dataPtr->lightWorldPos));
// normalize x and y
// keep z for visibility test
lightPos.x = pos.x / pos.w;
Expand All @@ -162,17 +178,14 @@ namespace gazebo
if (lightPos.z >= 0.0)
{
occlusionScale = this->OcclusionScale(_camera,
Conversions::ConvertIgn(lightPos), this->lightWorldPos);
Conversions::ConvertIgn(lightPos), this->dataPtr->lightWorldPos);
}
_pos = Conversions::ConvertIgn(lightPos);
_scale = occlusionScale * this->scale;
_scale = occlusionScale * this->dataPtr->scale;
}

/// \brief Get the lens flare position and scale for a wide angle camera
/// \param[in] _wideAngleCam Camera which the lens flare is added to
/// \param[out] _pos lens flare position in normalized device coordinates
/// \param[out] _scale Amount to scale the lens flare by.
private: void WideAngleCameraPosScale(
//////////////////////////////////////////////////
void LensFlareCompositorListener::WideAngleCameraPosScale(
const WideAngleCameraPtr &_wideAngleCam,
ignition::math::Vector3d &_pos, double &_scale)
{
Expand All @@ -182,36 +195,36 @@ namespace gazebo
// a gazebo camera object
std::vector<Ogre::Camera *> ogreEnvCameras =
_wideAngleCam->OgreEnvCameras();
if (!this->wideAngleDummyCamera)
if (!this->dataPtr->wideAngleDummyCamera)
{
// create camera with auto render set to false
// so it doesn't actually use up too much gpu resources
static unsigned int dummyCamId = 0;
std::string dummyCamName =
_wideAngleCam->Name() + "_lensflare_occlusion_" +
std::to_string(dummyCamId);
this->wideAngleDummyCamera =
this->dataPtr->wideAngleDummyCamera =
_wideAngleCam->GetScene()->CreateCamera(
dummyCamName, false);
this->wideAngleDummyCamera->Load();
this->dataPtr->wideAngleDummyCamera->Load();

// set dummy camera properties based on env cam
Ogre::Camera *cam = ogreEnvCameras[0];
this->wideAngleDummyCamera->SetImageWidth(
this->dataPtr->wideAngleDummyCamera->SetImageWidth(
cam->getViewport()->getActualWidth());
this->wideAngleDummyCamera->SetImageHeight(
this->dataPtr->wideAngleDummyCamera->SetImageHeight(
cam->getViewport()->getActualHeight());
this->wideAngleDummyCamera->Init();
this->wideAngleDummyCamera->CreateRenderTexture(
this->dataPtr->wideAngleDummyCamera->Init();
this->dataPtr->wideAngleDummyCamera->CreateRenderTexture(
dummyCamName + "_rtt");
this->wideAngleDummyCamera->SetAspectRatio(
this->dataPtr->wideAngleDummyCamera->SetAspectRatio(
cam->getAspectRatio());
// aspect ratio should be 1.0 so VFOV should equal to HFOV
this->wideAngleDummyCamera->SetHFOV(
this->dataPtr->wideAngleDummyCamera->SetHFOV(
ignition::math::Angle(cam->getFOVy().valueRadians()));
// reset camera orientation so we can set the exact world pose
// below when doing occlusion ray cast test
this->wideAngleDummyCamera->OgreCamera()->setOrientation(
this->dataPtr->wideAngleDummyCamera->OgreCamera()->setOrientation(
Ogre::Quaternion::IDENTITY);
}

Expand All @@ -220,7 +233,7 @@ namespace gazebo
static_cast<double>(_wideAngleCam->ViewportWidth());
double viewportHeight =
static_cast<double>(_wideAngleCam->ViewportHeight());
auto imagePos = _wideAngleCam->Project3d(this->lightWorldPos);
auto imagePos = _wideAngleCam->Project3d(this->dataPtr->lightWorldPos);

GZ_ASSERT(viewportWidth > 0, "Viewport width is 0");
GZ_ASSERT(viewportHeight > 0, "Viewport height is 0");
Expand Down Expand Up @@ -248,35 +261,32 @@ namespace gazebo
// project light world point to camera clip space.
auto viewProj = cam->getProjectionMatrix() * cam->getViewMatrix();
auto pos = viewProj *
Ogre::Vector4(Conversions::Convert(this->lightWorldPos));
Ogre::Vector4(Conversions::Convert(this->dataPtr->lightWorldPos));
pos.x /= pos.w;
pos.y /= pos.w;
// check if light is visible
if (std::fabs(pos.x) <= 1 && std::fabs(pos.y) <= 1 && pos.z > 0)
{
// check occlusion using this env camera
this->wideAngleDummyCamera->SetWorldPose(ignition::math::Pose3d(
this->dataPtr->wideAngleDummyCamera->SetWorldPose(
ignition::math::Pose3d(
Conversions::ConvertIgn(cam->getDerivedPosition()),
Conversions::ConvertIgn(cam->getDerivedOrientation())));

occlusionScale = this->OcclusionScale(
this->wideAngleDummyCamera,
this->dataPtr->wideAngleDummyCamera,
ignition::math::Vector3d(pos.x, pos.y, pos.z),
this->lightWorldPos);
this->dataPtr->lightWorldPos);
break;
}
}
}
_pos = Conversions::ConvertIgn(lightPos);
_scale = occlusionScale * this->scale;
_scale = occlusionScale * this->dataPtr->scale;
}

/// \brief Check to see if the lens flare is occluded and return a scaling
/// factor that is proportional to the lens flare's visibility
/// \param[in] _cam Camera used for checking occlusion
/// \param[in] _imgPos light pos in clip space
/// \param[in] _worldPos light pos in 3D world space
private: double OcclusionScale(const CameraPtr &_cam,
//////////////////////////////////////////////////
double LensFlareCompositorListener::OcclusionScale(const CameraPtr &_cam,
const ignition::math::Vector3d &_imgPos,
const ignition::math::Vector3d &_worldPos)
{
Expand All @@ -301,7 +311,7 @@ namespace gazebo
unsigned int occluded = 0u;
// work in normalized device coordinates
// lens flare's halfSize is just an approximated value
double halfSize = 0.05 * this->scale;
double halfSize = 0.05 * this->dataPtr->scale;
double steps = 10;
double stepSize = halfSize * 2 / steps;
double cx = _imgPos.X();
Expand All @@ -326,27 +336,7 @@ namespace gazebo
double s = static_cast<double>(rays - occluded) /
static_cast<double>(rays);
return s;
};

/// \brief Pointer to light
private: LightPtr light;

/// \brief Pointer to camera
private: CameraPtr camera;

/// \brief Dummy camera used by wide angle camera for occlusion checking
private: CameraPtr wideAngleDummyCamera;

/// \brief Position of light in world frame
private: ignition::math::Vector3d lightWorldPos;

/// \brief Scale of lens flare.
private: double scale = 1.0;

/// \brief Color of lens flare.
private: ignition::math::Vector3d color
= ignition::math::Vector3d(1.0, 1.0, 1.0);
};
}

/// \brief Private data class for LensFlare
class LensFlarePrivate
Expand Down Expand Up @@ -533,3 +523,22 @@ void LensFlare::OnRequest(ConstRequestPtr &_msg)
std::bind(&LensFlare::Update, this));
}
}

//////////////////////////////////////////////////
void LensFlare::SetCameraSensor(CameraPtr _camera)
{
this->dataPtr->camera = _camera;
}

//////////////////////////////////////////////////
void LensFlare::SetLensFlareCompositorListener(
std::shared_ptr<LensFlareCompositorListener> _listener)
{
this->dataPtr->lensFlareCompositorListener = _listener;
}

//////////////////////////////////////////////////
void LensFlare::SetLensFlareInstance(Ogre::CompositorInstance *_instance)
{
this->dataPtr->lensFlareInstance = _instance;
}
Loading