Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
5.4 kB · 163 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164#include "terraindrawable.hpp"
#include <osg/ClusterCullingCallback>#include <osgUtil/CullVisitor>
#include <components/sceneutil/lightmanager.hpp>
#include "compositemaprenderer.hpp"
namespace Terrain{
TerrainDrawable::TerrainDrawable() {}
TerrainDrawable::~TerrainDrawable() = default;
TerrainDrawable::TerrainDrawable(const TerrainDrawable& copy, const osg::CopyOp& copyop) : osg::Geometry(copy, copyop) , mPasses(copy.mPasses) , mLightListCallback(copy.mLightListCallback) { }
void TerrainDrawable::accept(osg::NodeVisitor& nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR) { osg::Geometry::accept(nv); } else if (nv.validNodeMask(*this)) { nv.pushOntoNodePath(this); cull(static_cast<osgUtil::CullVisitor*>(&nv)); nv.popFromNodePath(); } }
inline float distance(const osg::Vec3& coord, const osg::Matrix& matrix) { return -(coord[0] * static_cast<float>(matrix(0, 2)) + coord[1] * static_cast<float>(matrix(1, 2)) + coord[2] * static_cast<float>(matrix(2, 2)) + static_cast<float>(matrix(3, 2))); }
// canot use ClusterCullingCallback::cull: viewpoint != eyepoint // !osgfixpotential! bool clusterCull(osg::ClusterCullingCallback* cb, const osg::Vec3f& eyePoint, bool shadowcam) { const float deviation = cb->getDeviation(); const osg::Vec3& controlPoint = cb->getControlPoint(); osg::Vec3 normal = cb->getNormal(); if (shadowcam) normal = normal * -1; // inverting for shadowcam frontfaceculing if (deviation <= -1.0f) return false; const osg::Vec3 eyeControlPoint = eyePoint - controlPoint; const float radius = eyeControlPoint.length(); if (radius < cb->getRadius()) return false; return (eyeControlPoint * normal) / radius < deviation; }
void TerrainDrawable::cull(osgUtil::CullVisitor* cv) { const osg::BoundingBox& bb = getBoundingBox();
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;
osg::RefMatrix& matrix = *cv->getModelViewMatrix();
if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR && bb.valid()) { if (!cv->updateCalculatedNearFar(matrix, *this, false)) return; }
float depth = bb.valid() ? distance(bb.center(), matrix) : 0.0f; if (osg::isNaN(depth)) return;
if (shadowcam) { cv->addDrawableAndDepth(this, &matrix, depth); return; }
if (mCompositeMap && mCompositeMapRenderer) { mCompositeMapRenderer->setImmediate(mCompositeMap); mCompositeMapRenderer = nullptr; }
bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
osg::StateSet* stateset = getStateSet(); if (stateset) cv->pushStateSet(stateset);
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it) { cv->pushStateSet(*it); cv->addDrawableAndDepth(this, &matrix, depth); cv->popStateSet(); }
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) { 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); } }
void TerrainDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const { for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it) { osg::StateSet* stateset = *it; stateset->compileGLObjects(*renderInfo.getState()); }
osg::Geometry::compileGLObjects(renderInfo); }
}