1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-17 10:10:23 +00:00
OpenMW/components/terrain/terraindrawable.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

166 lines
5.3 KiB
C++
Raw Normal View History

#include "terraindrawable.hpp"
2019-08-10 13:37:00 +00:00
#include <osg/ClusterCullingCallback>
#include <osgUtil/CullVisitor>
#include <components/sceneutil/lightmanager.hpp>
#include "compositemaprenderer.hpp"
namespace Terrain
{
TerrainDrawable::TerrainDrawable() {}
TerrainDrawable::~TerrainDrawable() {}
TerrainDrawable::TerrainDrawable(const TerrainDrawable& copy, const osg::CopyOp& copyop)
: osg::Geometry(copy, copyop)
, mPasses(copy.mPasses)
, mLightListCallback(copy.mLightListCallback)
{
2022-09-22 18:26:05 +00:00
}
void TerrainDrawable::accept(osg::NodeVisitor& nv)
2022-09-22 18:26:05 +00:00
{
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
2022-09-22 18:26:05 +00:00
{
osg::Geometry::accept(nv);
}
else if (nv.validNodeMask(*this))
2022-09-22 18:26:05 +00:00
{
nv.pushOntoNodePath(this);
cull(static_cast<osgUtil::CullVisitor*>(&nv));
nv.popFromNodePath();
2022-09-22 18:26:05 +00:00
}
}
inline float distance(const osg::Vec3& coord, const osg::Matrix& matrix)
{
return -((float)coord[0] * (float)matrix(0, 2) + (float)coord[1] * (float)matrix(1, 2)
+ (float)coord[2] * (float)matrix(2, 2) + matrix(3, 2));
}
2022-09-22 18:26:05 +00:00
// canot use ClusterCullingCallback::cull: viewpoint != eyepoint
2019-08-10 13:37:00 +00:00
// !osgfixpotential!
bool clusterCull(osg::ClusterCullingCallback* cb, const osg::Vec3f& eyePoint, bool shadowcam)
{
float _deviation = cb->getDeviation();
const osg::Vec3& _controlPoint = cb->getControlPoint();
osg::Vec3 _normal = cb->getNormal();
if (shadowcam)
_normal = _normal * -1; // inverting for shadowcam frontfaceculing
2019-08-10 13:37:00 +00:00
float _radius = cb->getRadius();
if (_deviation <= -1.0f)
2019-08-10 13:37:00 +00:00
return false;
osg::Vec3 eye_cp = eyePoint - _controlPoint;
float radius = eye_cp.length();
2019-08-10 13:37:00 +00:00
if (radius < _radius)
return false;
float deviation = (eye_cp * _normal) / radius;
2019-08-10 13:37:00 +00:00
return deviation < _deviation;
}
void TerrainDrawable::cull(osgUtil::CullVisitor* cv)
2022-09-22 18:26:05 +00:00
{
const osg::BoundingBox& bb = getBoundingBox();
2019-08-10 13:37:00 +00:00
if (_cullingActive && cv->isCulled(getBoundingBox()))
return;
bool shadowcam = cv->getCurrentCamera()->getName() == "ShadowCamera";
if (cv->getCullingMode() & osg::CullStack::CLUSTER_CULLING
&& clusterCull(mClusterCullingCallback, cv->getEyePoint(), shadowcam))
return;
2019-08-10 13:37:00 +00:00
osg::RefMatrix& matrix = *cv->getModelViewMatrix();
if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR && bb.valid())
2022-09-22 18:26:05 +00:00
{
2019-08-10 13:37:00 +00:00
if (!cv->updateCalculatedNearFar(matrix, *this, false))
return;
2022-09-22 18:26:05 +00:00
}
2019-08-10 13:37:00 +00:00
float depth = bb.valid() ? distance(bb.center(), matrix) : 0.0f;
if (osg::isNaN(depth))
return;
2021-01-09 10:41:10 +00:00
if (shadowcam)
{
cv->addDrawableAndDepth(this, &matrix, depth);
return;
2022-09-22 18:26:05 +00:00
}
if (mCompositeMap && mCompositeMapRenderer)
2022-09-22 18:26:05 +00:00
{
mCompositeMapRenderer->setImmediate(mCompositeMap);
mCompositeMapRenderer = nullptr;
2022-09-22 18:26:05 +00:00
}
bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
2022-09-22 18:26:05 +00:00
osg::StateSet* stateset = getStateSet();
if (stateset)
cv->pushStateSet(stateset);
2022-09-22 18:26:05 +00:00
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
2022-09-22 18:26:05 +00:00
{
cv->pushStateSet(*it);
cv->addDrawableAndDepth(this, &matrix, depth);
cv->popStateSet();
2022-09-22 18:26:05 +00:00
}
if (stateset)
cv->popStateSet();
if (pushedLight)
cv->popStateSet();
}
void TerrainDrawable::createClusterCullingCallback()
{
mClusterCullingCallback = new osg::ClusterCullingCallback(this);
}
void TerrainDrawable::setPasses(const TerrainDrawable::PassVector& passes)
{
mPasses = passes;
}
void TerrainDrawable::setLightListCallback(SceneUtil::LightListCallback* lightListCallback)
{
mLightListCallback = lightListCallback;
}
void TerrainDrawable::setupWaterBoundingBox(float waterheight, float margin)
{
osg::Vec3Array* vertices = static_cast<osg::Vec3Array*>(getVertexArray());
for (unsigned int i = 0; i < vertices->size(); ++i)
2022-09-22 18:26:05 +00:00
{
const osg::Vec3f& vertex = (*vertices)[i];
if (vertex.z() <= waterheight)
mWaterBoundingBox.expandBy(vertex);
}
if (mWaterBoundingBox.valid())
{
const osg::BoundingBox& bb = getBoundingBox();
mWaterBoundingBox.xMin() = std::max(bb.xMin(), mWaterBoundingBox.xMin() - margin);
mWaterBoundingBox.yMin() = std::max(bb.yMin(), mWaterBoundingBox.yMin() - margin);
mWaterBoundingBox.xMax() = std::min(bb.xMax(), mWaterBoundingBox.xMax() + margin);
mWaterBoundingBox.xMax() = std::min(bb.xMax(), mWaterBoundingBox.xMax() + margin);
2022-09-22 18:26:05 +00:00
}
}
void TerrainDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const
{
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
2022-09-22 18:26:05 +00:00
{
osg::StateSet* stateset = *it;
stateset->compileGLObjects(*renderInfo.getState());
}
osg::Geometry::compileGLObjects(renderInfo);
}
}