Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support skybox in wide angle cam view #901

Merged
merged 6 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
10 changes: 10 additions & 0 deletions ogre2/include/gz/rendering/ogre2/Ogre2WideAngleCamera.hh
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ namespace gz
std::function<void(const unsigned char *, unsigned int, unsigned int,
unsigned int, const std::string &)> _subscriber) override;

/// \brief Set the background material of this camera
/// \param[in] _material Material to set the background to
public: virtual void SetBackgroundMaterial(MaterialPtr _material);

/// \brief Get the background material of this camera
/// \return background material
public: virtual MaterialPtr BackgroundMaterial() const;

/// \brief Returns the workspace name for the final pass
/// that stitches all faces.
Expand Down Expand Up @@ -179,6 +186,9 @@ namespace gz
protected: void SetupMSAA(Ogre::CompositorManager2 *_ogreCompMgr,
uint8_t _msaa);

/// \brief Update the background material
private: virtual void UpdateBackgroundMaterial();

/// \brief Saves the CompositorPassSceneDef of each of the 6 passes
/// defined in WideAngleCamera.compositor data file for later
/// manipulation.
Expand Down
9 changes: 9 additions & 0 deletions ogre2/src/Ogre2Scene.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,8 @@
{
Ogre2WideAngleCameraPtr camera(new Ogre2WideAngleCamera);
bool result = this->InitObject(camera, _id, _name);
if (this->backgroundMaterial)
camera->SetBackgroundMaterial(this->backgroundMaterial);

Check warning on line 1100 in ogre2/src/Ogre2Scene.cc

View check run for this annotation

Codecov / codecov/patch

ogre2/src/Ogre2Scene.cc#L1100

Added line #L1100 was not covered by tests
return (result) ? camera : nullptr;
}

Expand Down Expand Up @@ -1535,6 +1537,13 @@
{
camera->SetBackgroundMaterial(skyboxMat);
}
else
{
auto wideAngleCamera =
std::dynamic_pointer_cast<Ogre2WideAngleCamera>(sensor);
if (wideAngleCamera)
wideAngleCamera->SetBackgroundMaterial(skyboxMat);
}
}
this->dataPtr->skyEnabled = _enabled;
}
Expand Down
88 changes: 87 additions & 1 deletion ogre2/src/Ogre2WideAngleCamera.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <Compositor/OgreCompositorWorkspace.h>
#include <Compositor/OgreCompositorWorkspaceListener.h>
#include <Compositor/Pass/PassQuad/OgreCompositorPassQuad.h>
#include <Compositor/Pass/PassQuad/OgreCompositorPassQuadDef.h>
#include <Compositor/Pass/PassScene/OgreCompositorPassSceneDef.h>
#include <OgreDepthBuffer.h>
#include <OgreImage2.h>
Expand Down Expand Up @@ -150,6 +151,16 @@
/// \brief See Ogre2WideAngleCameraWorkspaceListenerPrivate
public: Ogre2WideAngleCameraWorkspaceListenerPrivate workspaceListener;

/// \brief Name of sky box material
public: const std::string kSkyboxMaterialName = "SkyBox";

/// \brief Background material of the render target
public: MaterialPtr backgroundMaterial;

/// \brief Flag to indicate if the render target background material has
/// changed
public: bool backgroundMaterialDirty = false;

explicit Implementation(gz::rendering::Ogre2WideAngleCamera &_owner) :
workspaceListener(_owner)
{
Expand Down Expand Up @@ -216,6 +227,13 @@
{
BaseCamera::PreRender();

if (this->dataPtr->backgroundMaterialDirty)
{
this->UpdateBackgroundMaterial();
this->RemoveAllRenderPasses();
this->DestroyTextures();
}

{
auto thisAsCameraPtr =
std::dynamic_pointer_cast<Camera>(this->shared_from_this());
Expand Down Expand Up @@ -621,6 +639,26 @@
const IdString cubemapPassNodeName =
_withMsaa ? "WideAngleCameraCubemapPassMsaa" : "WideAngleCameraCubemapPass";

bool validBackground = this->dataPtr->backgroundMaterial &&
!this->dataPtr->backgroundMaterial->EnvironmentMap().empty();

// render background, e.g. sky, after opaque stuff
if (validBackground)
{
Ogre::CompositorNodeDef *nodeDef = ogreCompMgr->getNodeDefinitionNonConst(
cubemapPassNodeName);
Ogre::CompositorTargetDef *target0 = nodeDef->getTargetPass(0);

// quad pass
Ogre::CompositorPassQuadDef *passQuad =
static_cast<Ogre::CompositorPassQuadDef *>(
target0->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = this->dataPtr->kSkyboxMaterialName + "_"
+ this->Name();
passQuad->mFrustumCorners =
Ogre::CompositorPassQuadDef::CAMERA_DIRECTION;
}

for (uint32_t faceIdx = 0u; faceIdx < kWideAngleNumCubemapFaces; ++faceIdx)
{
const std::string wsDefName = this->WorkspaceDefinitionName(faceIdx);
Expand Down Expand Up @@ -969,7 +1007,7 @@

if (msaa > 1u)
{
SetupMSAA(ogreCompMgr, msaa);
this->SetupMSAA(ogreCompMgr, msaa);

Check warning on line 1010 in ogre2/src/Ogre2WideAngleCamera.cc

View check run for this annotation

Codecov / codecov/patch

ogre2/src/Ogre2WideAngleCamera.cc#L1010

Added line #L1010 was not covered by tests
}

this->CreateFacesWorkspaces(msaa > 1u);
Expand Down Expand Up @@ -1366,3 +1404,51 @@
this->owner.PrepareForFinalPass(pass);
}
}

//////////////////////////////////////////////////
void Ogre2WideAngleCamera::SetBackgroundMaterial(MaterialPtr _material)
{
this->dataPtr->backgroundMaterial = _material;
this->dataPtr->backgroundMaterialDirty = true;
}

//////////////////////////////////////////////////
MaterialPtr Ogre2WideAngleCamera::BackgroundMaterial() const

Check warning on line 1416 in ogre2/src/Ogre2WideAngleCamera.cc

View check run for this annotation

Codecov / codecov/patch

ogre2/src/Ogre2WideAngleCamera.cc#L1416

Added line #L1416 was not covered by tests
{
return this->dataPtr->backgroundMaterial;

Check warning on line 1418 in ogre2/src/Ogre2WideAngleCamera.cc

View check run for this annotation

Codecov / codecov/patch

ogre2/src/Ogre2WideAngleCamera.cc#L1418

Added line #L1418 was not covered by tests
}

//////////////////////////////////////////////////
void Ogre2WideAngleCamera::UpdateBackgroundMaterial()
{
if (!this->dataPtr->backgroundMaterialDirty)
return;

Check warning on line 1425 in ogre2/src/Ogre2WideAngleCamera.cc

View check run for this annotation

Codecov / codecov/patch

ogre2/src/Ogre2WideAngleCamera.cc#L1425

Added line #L1425 was not covered by tests

bool validBackground = this->dataPtr->backgroundMaterial &&
!this->dataPtr->backgroundMaterial->EnvironmentMap().empty();

if (validBackground)
{
Ogre::MaterialManager &matManager = Ogre::MaterialManager::getSingleton();
std::string skyMatName = this->dataPtr->kSkyboxMaterialName + "_"
+ this->Name();
auto mat = matManager.getByName(skyMatName);
if (!mat)
{
auto skyboxMat = matManager.getByName(this->dataPtr->kSkyboxMaterialName);
if (!skyboxMat)
{
gzerr << "Unable to find skybox material" << std::endl;
return;

Check warning on line 1442 in ogre2/src/Ogre2WideAngleCamera.cc

View check run for this annotation

Codecov / codecov/patch

ogre2/src/Ogre2WideAngleCamera.cc#L1441-L1442

Added lines #L1441 - L1442 were not covered by tests
}
mat = skyboxMat->clone(skyMatName);
}
Ogre::TextureUnitState *texUnit =
mat->getTechnique(0u)->getPass(0u)->getTextureUnitState(0u);
texUnit->setTextureName(this->dataPtr->backgroundMaterial->EnvironmentMap(),
Ogre::TextureTypes::TypeCube);
texUnit->setHardwareGammaEnabled(false);
}

this->dataPtr->backgroundMaterialDirty = false;
}
97 changes: 97 additions & 0 deletions test/integration/sky.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include "gz/rendering/Image.hh"
#include "gz/rendering/PixelFormat.hh"
#include "gz/rendering/Scene.hh"
#include "gz/rendering/WideAngleCamera.hh"

#include <gz/utils/ExtraTestMacros.hh>

using namespace gz;
using namespace rendering;
Expand Down Expand Up @@ -86,6 +89,100 @@ TEST_F(SkyTest, Sky)
unsigned int gSkySum = 0u;
unsigned int bSkySum = 0u;

for (unsigned int i = 0; i < height; ++i)
{
for (unsigned int j = 0; j < step; j += channelCount)
{
unsigned int idx = i * step + j;
rSum += data[idx];
gSum += data[idx + 1];
bSum += data[idx + 2];

rSkySum += dataSky[idx];
gSkySum += dataSky[idx + 1];
bSkySum += dataSky[idx + 2];
}
}

// sky disabled - red background
EXPECT_GT(rSum, 0u);
EXPECT_EQ(0u, gSum);
EXPECT_EQ(0u, bSum);

// sky enabled - blue should be the dominant color
EXPECT_GT(rSkySum, 0u);
EXPECT_GT(gSkySum, 0u);
EXPECT_GT(bSkySum, 0u);
EXPECT_GT(bSkySum, gSkySum);
EXPECT_GT(bSkySum, rSkySum);

// Clean up
engine->DestroyScene(scene);
}

/////////////////////////////////////////////////
TEST_F(SkyTest, GZ_UTILS_TEST_DISABLED_ON_WIN32(WideAngleCamera))
{
CHECK_SUPPORTED_ENGINE("ogre2");

// add resources in build dir
engine->AddResourcePath(
common::joinPaths(std::string(PROJECT_BUILD_PATH), "src"));

ScenePtr scene = engine->CreateScene("scene");
ASSERT_NE(nullptr, scene);
scene->SetAmbientLight(0.3, 0.3, 0.3);

scene->SetBackgroundColor(1.0, 0.0, 0.0);

VisualPtr root = scene->RootVisual();
ASSERT_NE(nullptr, root);

// create camera
auto camera = scene->CreateWideAngleCamera("WideAngleCamera");
ASSERT_NE(nullptr, camera);

CameraLens lens;
lens.SetCustomMappingFunction(1.05, 4.0, AFT_TAN, 1.0, 0.0);
lens.SetType(MFT_CUSTOM);
lens.SetCutOffAngle(GZ_PI);

camera->SetLens(lens);
camera->SetHFOV(2.6);
camera->SetImageWidth(100);
camera->SetImageHeight(100);
camera->SetAspectRatio(1.333);
camera->SetLocalPosition(0.0, 0.0, 0.0);

// look up into the sky
camera->SetLocalRotation(math::Quaterniond(0, -GZ_PI/2.0, 0));
root->AddChild(camera);

// capture original image with red background
Image image = camera->CreateImage();
camera->Capture(image);

// Enable sky
scene->SetSkyEnabled(true);

// capture image with sky enabled
Image imageSky = camera->CreateImage();
camera->Capture(imageSky);

// Compare image pixels
unsigned char *data = image.Data<unsigned char>();
unsigned char *dataSky = imageSky.Data<unsigned char>();
unsigned int height = camera->ImageHeight();
unsigned int width = camera->ImageWidth();
unsigned int channelCount = PixelUtil::ChannelCount(camera->ImageFormat());
unsigned int step = width * channelCount;

unsigned int rSum = 0u;
unsigned int gSum = 0u;
unsigned int bSum = 0u;
unsigned int rSkySum = 0u;
unsigned int gSkySum = 0u;
unsigned int bSkySum = 0u;

for (unsigned int i = 0; i < height; ++i)
{
Expand Down