mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-29 21:45:32 +00:00
Rewrite CompositeMapRenderer to be based on Drawable and share the FBO
This commit is contained in:
parent
4549196b31
commit
683e625c6c
7 changed files with 155 additions and 81 deletions
|
@ -53,9 +53,9 @@ void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats) cons
|
|||
stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize());
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Group> ChunkManager::createCompositeMapRTT(osg::ref_ptr<osg::Texture2D>& texture)
|
||||
osg::ref_ptr<osg::Texture2D> ChunkManager::createCompositeMapRTT()
|
||||
{
|
||||
texture = new osg::Texture2D;
|
||||
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
|
||||
texture->setTextureWidth(mCompositeMapSize);
|
||||
texture->setTextureHeight(mCompositeMapSize);
|
||||
texture->setInternalFormat(GL_RGB);
|
||||
|
@ -64,30 +64,17 @@ osg::ref_ptr<osg::Group> ChunkManager::createCompositeMapRTT(osg::ref_ptr<osg::T
|
|||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
|
||||
osg::ref_ptr<osg::Camera> camera (new osg::Camera);
|
||||
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT);
|
||||
camera->attach(osg::Camera::COLOR_BUFFER, texture);
|
||||
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
camera->setViewMatrix(osg::Matrix::identity());
|
||||
camera->setProjectionMatrix(osg::Matrix::identity());
|
||||
camera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.f));
|
||||
camera->setClearMask(GL_COLOR_BUFFER_BIT);
|
||||
camera->setViewport(0, 0, mCompositeMapSize, mCompositeMapSize);
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER, -1);
|
||||
camera->setImplicitBufferAttachmentMask(osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT); // no need for a depth buffer
|
||||
|
||||
return camera;
|
||||
return texture;
|
||||
}
|
||||
|
||||
void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, osg::Group* compositeMapNode)
|
||||
void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap)
|
||||
{
|
||||
if (chunkSize > 1.f)
|
||||
{
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y()+texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y()+ texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y()+texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y()+texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -96,16 +83,17 @@ void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f&
|
|||
float width = texCoords.z()*2.f;
|
||||
float height = texCoords.w()*2.f;
|
||||
|
||||
osg::ref_ptr<osg::Geometry> geom = osg::createTexturedQuadGeometry(osg::Vec3(left,top,0), osg::Vec3(width,0,0), osg::Vec3(0,height,0));
|
||||
geom->setTexCoordArray(1, geom->getTexCoordArray(0), osg::Array::BIND_PER_VERTEX);
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > passes = createPasses(chunkSize, chunkCenter, true);
|
||||
for (std::vector<osg::ref_ptr<osg::StateSet> >::iterator it = passes.begin(); it != passes.end(); ++it)
|
||||
{
|
||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||
group->setStateSet(*it);
|
||||
group->addChild(geom);
|
||||
compositeMapNode->addChild(group);
|
||||
osg::ref_ptr<osg::Geometry> geom = osg::createTexturedQuadGeometry(osg::Vec3(left,top,0), osg::Vec3(width,0,0), osg::Vec3(0,height,0));
|
||||
geom->setUseDisplayList(false); // don't bother making a display list for an object that is just rendered once.
|
||||
geom->setUseVertexBufferObjects(false);
|
||||
geom->setTexCoordArray(1, geom->getTexCoordArray(0), osg::Array::BIND_PER_VERTEX);
|
||||
|
||||
geom->setStateSet(*it);
|
||||
|
||||
compositeMap.mDrawables.push_back(geom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,21 +182,19 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve
|
|||
|
||||
if (useCompositeMap)
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> compositeMap;
|
||||
osg::ref_ptr<osg::Group> compositeMapNode = createCompositeMapRTT(compositeMap);
|
||||
osg::ref_ptr<CompositeMap> compositeMap = new CompositeMap;
|
||||
compositeMap->mTexture = createCompositeMapRTT();
|
||||
|
||||
createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), compositeMapNode);
|
||||
createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), *compositeMap);
|
||||
|
||||
compositeMapNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
|
||||
mCompositeMapRenderer->addCompositeMap(compositeMapNode, false);
|
||||
mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > passes2;
|
||||
passes2.push_back(new osg::StateSet);
|
||||
passes2[0]->setTextureAttributeAndModes(0, compositeMap, osg::StateAttribute::ON);
|
||||
passes2[0]->setTextureAttributeAndModes(0, compositeMap->mTexture, osg::StateAttribute::ON);
|
||||
geometry->setPasses(passes2);
|
||||
|
||||
transform->getOrCreateUserDataContainer()->addUserObject(compositeMapNode);
|
||||
transform->getOrCreateUserDataContainer()->setUserData(compositeMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace Terrain
|
|||
class TextureManager;
|
||||
class CompositeMapRenderer;
|
||||
class Storage;
|
||||
class CompositeMap;
|
||||
|
||||
/// @brief Handles loading and caching of terrain chunks
|
||||
class ChunkManager : public Resource::ResourceManager
|
||||
|
@ -41,9 +42,9 @@ namespace Terrain
|
|||
private:
|
||||
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags);
|
||||
|
||||
osg::ref_ptr<osg::Group> createCompositeMapRTT(osg::ref_ptr<osg::Texture2D>& texture);
|
||||
osg::ref_ptr<osg::Texture2D> createCompositeMapRTT();
|
||||
|
||||
void createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, osg::Group* compositeMapNode);
|
||||
void createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& map);
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(float chunkSize, const osg::Vec2f& chunkCenter, bool forCompositeMap);
|
||||
|
||||
|
|
|
@ -2,39 +2,42 @@
|
|||
|
||||
#include <OpenThreads/ScopedLock>
|
||||
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/RenderInfo>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
CompositeMapRenderer::CompositeMapRenderer()
|
||||
: mNumCompilePerFrame(1)
|
||||
, mLastFrame(0)
|
||||
{
|
||||
setSupportsDisplayList(false);
|
||||
setCullingActive(false);
|
||||
|
||||
mFBO = new osg::FrameBufferObject;
|
||||
|
||||
getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::traverse(osg::NodeVisitor &nv)
|
||||
void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const
|
||||
{
|
||||
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
|
||||
return;
|
||||
|
||||
if (mLastFrame == nv.getTraversalNumber())
|
||||
return;
|
||||
mLastFrame = nv.getTraversalNumber();
|
||||
|
||||
mCompiled.clear();
|
||||
|
||||
unsigned int numCompiled = 0;
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
||||
|
||||
if (mImmediateCompileSet.empty() && mCompileSet.empty())
|
||||
return;
|
||||
|
||||
while (!mImmediateCompileSet.empty())
|
||||
{
|
||||
osg::Node* node = *mImmediateCompileSet.begin();
|
||||
CompositeMap* node = *mImmediateCompileSet.begin();
|
||||
mCompiled.insert(node);
|
||||
|
||||
node->accept(nv);
|
||||
compile(*node, renderInfo);
|
||||
|
||||
mImmediateCompileSet.erase(mImmediateCompileSet.begin());
|
||||
|
||||
++numCompiled;
|
||||
|
@ -42,35 +45,89 @@ void CompositeMapRenderer::traverse(osg::NodeVisitor &nv)
|
|||
|
||||
while (!mCompileSet.empty() && numCompiled <= mNumCompilePerFrame)
|
||||
{
|
||||
osg::Node* node = *mCompileSet.begin();
|
||||
mCompiled.insert(node);
|
||||
CompositeMap* node = *mCompileSet.begin();
|
||||
|
||||
node->accept(nv);
|
||||
mCompileSet.erase(mCompileSet.begin());
|
||||
compile(*node, renderInfo);
|
||||
|
||||
++numCompiled;
|
||||
|
||||
mCompiled.insert(node);
|
||||
mCompileSet.erase(mCompileSet.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo &renderInfo) const
|
||||
{
|
||||
osg::State& state = *renderInfo.getState();
|
||||
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
|
||||
|
||||
if (!mFBO)
|
||||
return;
|
||||
|
||||
if (!ext->isFrameBufferObjectSupported)
|
||||
return;
|
||||
|
||||
osg::FrameBufferAttachment attach (compositeMap.mTexture);
|
||||
mFBO->setAttachment(osg::Camera::COLOR_BUFFER, attach);
|
||||
mFBO->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
|
||||
|
||||
GLenum status = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
|
||||
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
|
||||
OSG_ALWAYS << "Error attaching FBO" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i<compositeMap.mDrawables.size(); ++i)
|
||||
{
|
||||
osg::Drawable* drw = compositeMap.mDrawables[i];
|
||||
osg::StateSet* stateset = drw->getStateSet();
|
||||
|
||||
if (stateset)
|
||||
renderInfo.getState()->pushStateSet(stateset);
|
||||
|
||||
renderInfo.getState()->apply();
|
||||
|
||||
glViewport(0,0,compositeMap.mTexture->getTextureWidth(), compositeMap.mTexture->getTextureHeight());
|
||||
drw->drawImplementation(renderInfo);
|
||||
|
||||
if (stateset)
|
||||
renderInfo.getState()->popStateSet();
|
||||
}
|
||||
|
||||
state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT);
|
||||
|
||||
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
|
||||
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::setNumCompilePerFrame(int num)
|
||||
{
|
||||
mNumCompilePerFrame = num;
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::addCompositeMap(osg::Node *node, bool immediate)
|
||||
void CompositeMapRenderer::addCompositeMap(CompositeMap* compositeMap, bool immediate)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
||||
if (immediate)
|
||||
mImmediateCompileSet.insert(node);
|
||||
mImmediateCompileSet.insert(compositeMap);
|
||||
else
|
||||
mCompileSet.insert(node);
|
||||
mCompileSet.insert(compositeMap);
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::setImmediate(osg::Node *node)
|
||||
void CompositeMapRenderer::setImmediate(CompositeMap* compositeMap)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
|
||||
mImmediateCompileSet.insert(node);
|
||||
mCompileSet.erase(node);
|
||||
mImmediateCompileSet.insert(compositeMap);
|
||||
mCompileSet.erase(compositeMap);
|
||||
}
|
||||
|
||||
CompositeMap::~CompositeMap()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,46 +1,64 @@
|
|||
#ifndef OPENMW_COMPONENTS_TERRAIN_COMPOSITEMAPRENDERER_H
|
||||
#define OPENMW_COMPONENTS_TERRAIN_COMPOSITEMAPRENDERER_H
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/Drawable>
|
||||
|
||||
#include <OpenThreads/Mutex>
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class FrameBufferObject;
|
||||
class RenderInfo;
|
||||
class Texture2D;
|
||||
}
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
class CompositeMap : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
~CompositeMap();
|
||||
std::vector<osg::ref_ptr<osg::Drawable> > mDrawables;
|
||||
osg::ref_ptr<osg::Texture2D> mTexture;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The CompositeMapRenderer is responsible for updating composite map textures in a blocking or non-blocking way.
|
||||
*/
|
||||
class CompositeMapRenderer : public osg::Node
|
||||
class CompositeMapRenderer : public osg::Drawable
|
||||
{
|
||||
public:
|
||||
CompositeMapRenderer();
|
||||
|
||||
virtual void traverse(osg::NodeVisitor& nv);
|
||||
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
|
||||
|
||||
void compile(CompositeMap& compositeMap, osg::RenderInfo& renderInfo) const;
|
||||
|
||||
/// Set the maximum number of (non-immediate) composite maps to compile per frame
|
||||
void setNumCompilePerFrame(int num);
|
||||
|
||||
/// Add a composite map to be rendered
|
||||
void addCompositeMap(osg::Node* node, bool immediate=false);
|
||||
void addCompositeMap(CompositeMap* map, bool immediate=false);
|
||||
|
||||
/// Mark this composite map to be required for the current frame
|
||||
void setImmediate(osg::Node* node);
|
||||
void setImmediate(CompositeMap* map);
|
||||
|
||||
private:
|
||||
unsigned int mNumCompilePerFrame;
|
||||
unsigned int mLastFrame;
|
||||
|
||||
typedef std::set<osg::ref_ptr<osg::Node> > CompileSet;
|
||||
typedef std::set<osg::ref_ptr<CompositeMap> > CompileSet;
|
||||
|
||||
CompileSet mCompileSet;
|
||||
CompileSet mImmediateCompileSet;
|
||||
mutable CompileSet mCompileSet;
|
||||
mutable CompileSet mImmediateCompileSet;
|
||||
|
||||
CompileSet mCompiled;
|
||||
mutable CompileSet mCompiled;
|
||||
|
||||
OpenThreads::Mutex mMutex;
|
||||
mutable OpenThreads::Mutex mMutex;
|
||||
|
||||
osg::ref_ptr<osg::FrameBufferObject> mFBO;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -329,14 +329,10 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
|||
if (entry.mVisible)
|
||||
{
|
||||
osg::UserDataContainer* udc = entry.mRenderingNode->getUserDataContainer();
|
||||
if (udc && udc->getNumUserObjects() > 0)
|
||||
if (udc && udc->getUserData())
|
||||
{
|
||||
osg::Node* compositeMapNode = udc->getUserObject(0)->asNode();
|
||||
if (compositeMapNode)
|
||||
{
|
||||
mCompositeMapRenderer->setImmediate(compositeMapNode);
|
||||
udc->removeUserObject(0);
|
||||
}
|
||||
mCompositeMapRenderer->setImmediate(static_cast<CompositeMap*>(udc->getUserData()));
|
||||
udc->setUserData(NULL);
|
||||
}
|
||||
entry.mRenderingNode->accept(nv);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <osg/Group>
|
||||
#include <osg/Material>
|
||||
#include <osg/Camera>
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
|
@ -27,9 +28,20 @@ World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSyst
|
|||
|
||||
mTerrainRoot->setName("Terrain Root");
|
||||
|
||||
osg::ref_ptr<osg::Camera> compositeCam = new osg::Camera;
|
||||
compositeCam->setRenderOrder(osg::Camera::PRE_RENDER, -1);
|
||||
compositeCam->setProjectionMatrix(osg::Matrix::identity());
|
||||
compositeCam->setViewMatrix(osg::Matrix::identity());
|
||||
compositeCam->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
compositeCam->setClearMask(0);
|
||||
compositeCam->setNodeMask(preCompileMask);
|
||||
mCompositeMapCamera = compositeCam;
|
||||
|
||||
compileRoot->addChild(compositeCam);
|
||||
|
||||
|
||||
mCompositeMapRenderer = new CompositeMapRenderer;
|
||||
mCompositeMapRenderer->setNodeMask(preCompileMask);
|
||||
compileRoot->addChild(mCompositeMapRenderer);
|
||||
compositeCam->addChild(mCompositeMapRenderer);
|
||||
|
||||
mParent->addChild(mTerrainRoot);
|
||||
|
||||
|
@ -46,7 +58,9 @@ World::~World()
|
|||
mResourceSystem->removeResourceManager(mTextureManager.get());
|
||||
|
||||
mParent->removeChild(mTerrainRoot);
|
||||
mCompositeMapRenderer->getParent(0)->removeChild(mCompositeMapRenderer);
|
||||
|
||||
mCompositeMapCamera->removeChild(mCompositeMapRenderer);
|
||||
mCompositeMapCamera->getParent(0)->removeChild(mCompositeMapCamera);
|
||||
|
||||
delete mStorage;
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ namespace Terrain
|
|||
|
||||
osg::ref_ptr<osg::Group> mParent;
|
||||
osg::ref_ptr<osg::Group> mTerrainRoot;
|
||||
|
||||
osg::ref_ptr<osg::Group> mCompositeMapCamera;
|
||||
osg::ref_ptr<CompositeMapRenderer> mCompositeMapRenderer;
|
||||
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
|
|
Loading…
Reference in a new issue