1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-21 12:23:51 +00:00

Merge branch 'bzzt_6_fix_shadows_in_screenshot_with_octreeoclusion' into 'master'

fix shadows in save game screenshot

See merge request OpenMW/openmw!183
This commit is contained in:
David Cernat 2020-04-22 19:24:43 +00:00
commit 728b92c4d8
3 changed files with 58 additions and 9 deletions

View file

@ -744,17 +744,19 @@ namespace MWRender
class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback
{
public:
NotifyDrawCompletedCallback()
: mDone(false)
NotifyDrawCompletedCallback(unsigned int frame)
: mDone(false), mFrame(frame)
{
}
virtual void operator () (osg::RenderInfo& renderInfo) const
{
mMutex.lock();
mDone = true;
mMutex.unlock();
mCondition.signal();
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame)
{
mDone = true;
mCondition.signal();
}
}
void waitTillDone()
@ -769,6 +771,7 @@ namespace MWRender
mutable OpenThreads::Condition mCondition;
mutable OpenThreads::Mutex mMutex;
mutable bool mDone;
unsigned int mFrame;
};
bool RenderingManager::screenshot360(osg::Image* image, std::string settingStr)
@ -948,7 +951,7 @@ namespace MWRender
mRootNode->addChild(camera);
// The draw needs to complete before we can copy back our image.
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback);
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback(0));
camera->setFinalDrawCallback(callback);
MWBase::Environment::get().getWindowManager()->getLoadingScreen()->loadingOn(false);
@ -967,6 +970,51 @@ namespace MWRender
mRootNode->removeChild(camera);
}
class ReadImageFromFramebufferCallback : public osg::Drawable::DrawCallback
{
public:
ReadImageFromFramebufferCallback(osg::Image* image, int width, int height)
: mWidth(width), mHeight(height), mImage(image)
{
}
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* /*drawable*/) const
{
int screenW = renderInfo.getCurrentCamera()->getViewport()->width();
int screenH = renderInfo.getCurrentCamera()->getViewport()->height();
double imageaspect = (double)mWidth/(double)mHeight;
int leftPadding = std::max(0, static_cast<int>(screenW - screenH * imageaspect) / 2);
int topPadding = std::max(0, static_cast<int>(screenH - screenW / imageaspect) / 2);
int width = screenW - leftPadding*2;
int height = screenH - topPadding*2;
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
mImage->scaleImage(mWidth, mHeight, 1);
}
private:
int mWidth;
int mHeight;
osg::ref_ptr<osg::Image> mImage;
};
void RenderingManager::screenshotFramebuffer(osg::Image* image, int w, int h)
{
osg::Camera* camera = mViewer->getCamera();
osg::ref_ptr<osg::Drawable> tempDrw = new osg::Drawable;
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
tempDrw->setCullingActive(false);
tempDrw->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin", osg::StateSet::USE_RENDERBIN_DETAILS); // so its after all scene bins but before POST_RENDER gui camera
camera->addChild(tempDrw);
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback(mViewer->getFrameStamp()->getFrameNumber()));
camera->setFinalDrawCallback(callback);
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
callback->waitTillDone();
// now that we've "used up" the current frame, get a fresh frame number for the next frame() following after the screenshot is completed
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
camera->removeChild(tempDrw);
camera->setFinalDrawCallback(nullptr);
}
void RenderingManager::screenshot(osg::Image *image, int w, int h, osg::Matrixd cameraTransform)
{
osg::ref_ptr<osg::Camera> rttCamera (new osg::Camera);

View file

@ -144,7 +144,8 @@ namespace MWRender
void setWaterHeight(float level);
/// Take a screenshot of w*h onto the given image, not including the GUI.
void screenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd());
void screenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd()); // make a new render at given size
void screenshotFramebuffer(osg::Image* image, int w, int h); // copy directly from framebuffer and scale to given size
bool screenshot360(osg::Image* image, std::string settingStr);
struct RayResult

View file

@ -2554,7 +2554,7 @@ namespace MWWorld
void World::screenshot(osg::Image* image, int w, int h)
{
mRendering->screenshot(image, w, h);
mRendering->screenshotFramebuffer(image, w, h);
}
bool World::screenshot360(osg::Image* image, std::string settingStr)