mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Orthographic octree selection seems to be working
This commit is contained in:
parent
d422545c78
commit
3804917cf4
15 changed files with 152 additions and 77 deletions
|
@ -62,7 +62,7 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) {
|
|||
samplerDesc._wrapModeU = Sampler::WRAP_BORDER;
|
||||
samplerDesc._wrapModeV = Sampler::WRAP_BORDER;
|
||||
samplerDesc._filter = Sampler::FILTER_MIN_MAG_LINEAR;
|
||||
samplerDesc._comparisonFunc = LESS_EQUAL;
|
||||
samplerDesc._comparisonFunc = LESS;
|
||||
|
||||
depthTexture->setSampler(Sampler(samplerDesc));
|
||||
framebuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
||||
|
|
|
@ -64,8 +64,14 @@ float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeSc
|
|||
return voxelSizeScale / powf(2.0f, renderLevel);
|
||||
}
|
||||
|
||||
float getAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) {
|
||||
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) {
|
||||
const float maxScale = (float)TREE_SCALE;
|
||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
|
||||
return atan(maxScale / visibleDistanceAtMaxScale);
|
||||
}
|
||||
|
||||
float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust) {
|
||||
// Smallest visible element is 1cm
|
||||
const float smallestSize = 0.01f;
|
||||
return (smallestSize * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) / boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ float calculateRenderAccuracy(const glm::vec3& position,
|
|||
|
||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
|
||||
|
||||
float getAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust);
|
||||
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust);
|
||||
float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust);
|
||||
|
||||
// MIN_ELEMENT_ANGULAR_DIAMETER = angular diameter of 1x1x1m cube at 400m = sqrt(3) / 400 = 0.0043301 radians ~= 0.25 degrees
|
||||
const float MIN_ELEMENT_ANGULAR_DIAMETER = 0.0043301f; // radians
|
||||
|
|
|
@ -214,9 +214,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
}
|
||||
|
||||
const auto setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup");
|
||||
const auto queryResolution = setupOutput.getN<RenderShadowSetup::Outputs>(2);
|
||||
// Fetch and cull the items from the scene
|
||||
static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||
const auto fetchInput = render::Varying(shadowCasterFilter);
|
||||
const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying();
|
||||
const auto shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowTree", fetchInput);
|
||||
const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying();
|
||||
const auto shadowItems = task.addJob<FetchSpatialSelection>("FetchShadowSelection", selectionInputs);
|
||||
|
@ -281,14 +282,15 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
|
||||
output.edit0() = args->_renderMode;
|
||||
output.edit1() = args->_sizeScale;
|
||||
output.edit2() = glm::ivec2(0, 0);
|
||||
|
||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||
if (globalShadow) {
|
||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
auto& firstCascadeFrustum = globalShadow->getCascade(0).getFrustum();
|
||||
|
||||
auto& firstCascade = globalShadow->getCascade(0);
|
||||
auto& firstCascadeFrustum = firstCascade.getFrustum();
|
||||
unsigned int cascadeIndex;
|
||||
_coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition());
|
||||
_coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation());
|
||||
|
||||
// Adjust each cascade frustum
|
||||
for (cascadeIndex = 0; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
||||
|
@ -297,19 +299,29 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
|
||||
bias._constant, bias._slope);
|
||||
}
|
||||
|
||||
// Now adjust coarse frustum bounds
|
||||
auto left = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight());
|
||||
auto right = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight());
|
||||
auto top = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp());
|
||||
auto bottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp());
|
||||
auto frustumPosition = firstCascadeFrustum->getPosition();
|
||||
auto farTopLeft = firstCascadeFrustum->getFarTopLeft() - frustumPosition;
|
||||
auto farBottomRight = firstCascadeFrustum->getFarBottomRight() - frustumPosition;
|
||||
|
||||
auto left = glm::dot(farTopLeft, firstCascadeFrustum->getRight());
|
||||
auto right = glm::dot(farBottomRight, firstCascadeFrustum->getRight());
|
||||
auto top = glm::dot(farTopLeft, firstCascadeFrustum->getUp());
|
||||
auto bottom = glm::dot(farBottomRight, firstCascadeFrustum->getUp());
|
||||
auto near = firstCascadeFrustum->getNearClip();
|
||||
auto far = firstCascadeFrustum->getFarClip();
|
||||
|
||||
for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
||||
auto& cascadeFrustum = globalShadow->getCascade(cascadeIndex).getFrustum();
|
||||
auto cascadeLeft = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getRight());
|
||||
auto cascadeRight = glm::dot(cascadeFrustum->getFarTopRight(), cascadeFrustum->getRight());
|
||||
auto cascadeTop = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getUp());
|
||||
auto cascadeBottom = glm::dot(cascadeFrustum->getFarBottomRight(), cascadeFrustum->getUp());
|
||||
|
||||
farTopLeft = cascadeFrustum->getFarTopLeft() - frustumPosition;
|
||||
farBottomRight = cascadeFrustum->getFarBottomRight() - frustumPosition;
|
||||
|
||||
auto cascadeLeft = glm::dot(farTopLeft, cascadeFrustum->getRight());
|
||||
auto cascadeRight = glm::dot(farBottomRight, cascadeFrustum->getRight());
|
||||
auto cascadeTop = glm::dot(farTopLeft, cascadeFrustum->getUp());
|
||||
auto cascadeBottom = glm::dot(farBottomRight, cascadeFrustum->getUp());
|
||||
auto cascadeNear = cascadeFrustum->getNearClip();
|
||||
auto cascadeFar = cascadeFrustum->getFarClip();
|
||||
left = glm::min(left, cascadeLeft);
|
||||
|
@ -319,6 +331,9 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
near = glm::min(near, cascadeNear);
|
||||
far = glm::max(far, cascadeFar);
|
||||
}
|
||||
|
||||
_coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition());
|
||||
_coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation());
|
||||
_coarseShadowFrustum->setProjection(glm::ortho<float>(left, right, bottom, top, near, far));
|
||||
_coarseShadowFrustum->calculate();
|
||||
|
||||
|
@ -326,10 +341,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
args->pushViewFrustum(*_coarseShadowFrustum);
|
||||
|
||||
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
|
||||
if (lightStage->getCurrentKeyLight()->getType() == graphics::Light::SUN) {
|
||||
// Set to ridiculously high amount to prevent solid angle culling in octree selection
|
||||
args->_sizeScale = 1e16f;
|
||||
}
|
||||
|
||||
// We want for the octree query enough resolution to catch the details in the lowest cascade. So compute
|
||||
// the desired resolution for the first cascade frustum and extrapolate it to the coarse frustum.
|
||||
glm::ivec2 queryResolution = firstCascade.framebuffer->getSize();
|
||||
queryResolution.x = int(queryResolution.x * _coarseShadowFrustum->getWidth() / firstCascadeFrustum->getWidth());
|
||||
queryResolution.y = int(queryResolution.y * _coarseShadowFrustum->getHeight() / firstCascadeFrustum->getHeight());
|
||||
output.edit2() = queryResolution;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,10 +71,10 @@ public:
|
|||
float constantBias1{ 0.15f };
|
||||
float constantBias2{ 0.15f };
|
||||
float constantBias3{ 0.15f };
|
||||
float slopeBias0{ 0.55f };
|
||||
float slopeBias1{ 0.55f };
|
||||
float slopeBias2{ 0.55f };
|
||||
float slopeBias3{ 0.55f };
|
||||
float slopeBias0{ 0.6f };
|
||||
float slopeBias1{ 0.6f };
|
||||
float slopeBias2{ 0.6f };
|
||||
float slopeBias3{ 0.6f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
@ -82,7 +82,7 @@ signals:
|
|||
|
||||
class RenderShadowSetup {
|
||||
public:
|
||||
using Outputs = render::VaryingSet2<RenderArgs::RenderMode, float>;
|
||||
using Outputs = render::VaryingSet3<RenderArgs::RenderMode, float, glm::ivec2>;
|
||||
using Config = RenderShadowSetupConfig;
|
||||
using JobModel = render::Job::ModelO<RenderShadowSetup, Outputs, Config>;
|
||||
|
||||
|
|
|
@ -79,15 +79,10 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve
|
|||
fetchShadow(cascadeIndex, shadowTexcoord.xyz + offsets.points[2]) +
|
||||
fetchShadow(cascadeIndex, shadowTexcoord.xyz + offsets.points[3])
|
||||
);
|
||||
|
||||
return shadowAttenuation;
|
||||
}
|
||||
|
||||
float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float oneMinusNdotL) {
|
||||
if (!isShadowCascadeProjectedOnPixel(shadowTexcoord)) {
|
||||
// If a point is not in the map, do not attenuate
|
||||
return 1.0;
|
||||
}
|
||||
float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * oneMinusNdotL;
|
||||
return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias);
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) {
|
|||
}
|
||||
|
||||
bool isShadowCascadeProjectedOnPixel(vec4 cascadeTexCoords) {
|
||||
bvec2 greaterThanZero = greaterThanEqual(cascadeTexCoords.xy, vec2(0));
|
||||
bvec2 lessThanOne = lessThanEqual(cascadeTexCoords.xy, vec2(1));
|
||||
bvec2 greaterThanZero = greaterThan(cascadeTexCoords.xy, vec2(0));
|
||||
bvec2 lessThanOne = lessThan(cascadeTexCoords.xy, vec2(1));
|
||||
return all(greaterThanZero) && all(lessThanOne);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
#include <OctreeUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OctreeUtils.h>
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct Test {
|
|||
_renderDetails(renderDetails) {
|
||||
// FIXME: Keep this code here even though we don't use it yet
|
||||
/*_eyePos = _args->getViewFrustum().getPosition();
|
||||
float a = glm::degrees(Octree::getAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust));
|
||||
float a = glm::degrees(Octree::getPerspectiveAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust));
|
||||
auto angle = std::min(glm::radians(45.0f), a); // no worse than 45 degrees
|
||||
angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree
|
||||
auto tanAlpha = tan(angle);
|
||||
|
@ -130,7 +130,8 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu
|
|||
// start fresh
|
||||
outSelection.clear();
|
||||
|
||||
auto& filter = inputs;
|
||||
auto& filter = inputs.get0();
|
||||
auto frustumResolution = inputs.get1();
|
||||
|
||||
if (!filter.selectsNothing()) {
|
||||
assert(renderContext->args);
|
||||
|
@ -149,8 +150,19 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu
|
|||
}
|
||||
|
||||
// Octree selection!
|
||||
float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
||||
scene->getSpatialTree().selectCellItems(outSelection, filter, queryFrustum, angle);
|
||||
float threshold = 0.0f;
|
||||
if (queryFrustum.isPerspective()) {
|
||||
threshold = getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust);
|
||||
if (frustumResolution.y > 0) {
|
||||
threshold = glm::max(queryFrustum.getFieldOfView() / frustumResolution.y, threshold);
|
||||
}
|
||||
} else {
|
||||
threshold = getOrthographicAccuracySize(args->_sizeScale, args->_boundaryLevelAdjust);
|
||||
glm::vec2 frustumSize = glm::vec2(queryFrustum.getWidth(), queryFrustum.getHeight());
|
||||
const auto pixelResolution = frustumResolution.x > 0 ? frustumResolution : glm::ivec2(2048, 2048);
|
||||
threshold = glm::max(threshold, glm::min(frustumSize.x / pixelResolution.x, frustumSize.y / pixelResolution.y));
|
||||
}
|
||||
scene->getSpatialTree().selectCellItems(outSelection, filter, queryFrustum, threshold);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +383,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
// Now get the bound, and
|
||||
// filter individually against the _filter
|
||||
|
||||
// inside & fit items: filter only, culling is disabled
|
||||
// inside & fit items: filter only
|
||||
{
|
||||
PerformanceTimer perfTimer("insideFitItems");
|
||||
for (auto id : inSelection.insideItems) {
|
||||
|
@ -383,7 +395,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
}
|
||||
}
|
||||
|
||||
// inside & subcell items: filter only, culling is disabled
|
||||
// inside & subcell items: filter only
|
||||
{
|
||||
PerformanceTimer perfTimer("insideSmallItems");
|
||||
for (auto id : inSelection.insideSubcellItems) {
|
||||
|
@ -395,7 +407,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
}
|
||||
}
|
||||
|
||||
// partial & fit items: filter only, culling is disabled
|
||||
// partial & fit items: filter only
|
||||
{
|
||||
PerformanceTimer perfTimer("partialFitItems");
|
||||
for (auto id : inSelection.partialItems) {
|
||||
|
@ -407,7 +419,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
}
|
||||
}
|
||||
|
||||
// partial & subcell items: filter only, culling is disabled
|
||||
// partial & subcell items: filter only
|
||||
{
|
||||
PerformanceTimer perfTimer("partialSmallItems");
|
||||
for (auto id : inSelection.partialSubcellItems) {
|
||||
|
|
|
@ -53,9 +53,10 @@ namespace render {
|
|||
bool _justFrozeFrustum{ false };
|
||||
ViewFrustum _frozenFrustum;
|
||||
float _lodAngle;
|
||||
|
||||
public:
|
||||
using Config = FetchSpatialTreeConfig;
|
||||
using Inputs = ItemFilter;
|
||||
using Inputs = render::VaryingSet2<ItemFilter, glm::ivec2>;
|
||||
using JobModel = Job::ModelIO<FetchSpatialTree, Inputs, ItemSpatialTree::ItemSelection, Config>;
|
||||
|
||||
FetchSpatialTree() {}
|
||||
|
|
|
@ -148,7 +148,7 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS
|
|||
}
|
||||
// Draw the LOD Reticle
|
||||
{
|
||||
float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
||||
float angle = glm::degrees(getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
||||
Transform crosshairModel;
|
||||
crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1000.0));
|
||||
crosshairModel.setScale(1000.0f * tanf(glm::radians(angle))); // Scaling at the actual tan of the lod angle => Multiplied by TWO
|
||||
|
|
|
@ -23,7 +23,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
|
|||
// CPU jobs:
|
||||
// Fetch and cull the items from the scene
|
||||
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
||||
const auto fetchInput = render::Varying(filter);
|
||||
const auto fetchInput = FetchSpatialTree::Inputs(filter, glm::ivec2(0,0)).asVarying();
|
||||
const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", fetchInput);
|
||||
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, render::Varying(filter)).asVarying();
|
||||
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
|
||||
|
|
|
@ -12,9 +12,26 @@
|
|||
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
|
||||
using namespace render;
|
||||
|
||||
void Octree::PerspectiveSelector::setAngle(float a) {
|
||||
const float MAX_LOD_ANGLE = glm::radians(45.0f);
|
||||
const float MIN_LOD_ANGLE = glm::radians(1.0f / 60.0f);
|
||||
|
||||
angle = std::max(MIN_LOD_ANGLE, std::min(MAX_LOD_ANGLE, a));
|
||||
auto tanAlpha = tan(angle);
|
||||
squareTanAlpha = (float)(tanAlpha * tanAlpha);
|
||||
}
|
||||
|
||||
float Octree::PerspectiveSelector::testThreshold(const Coord3f& point, float size) const {
|
||||
auto eyeToPoint = point - eyePos;
|
||||
return (size * size / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha;
|
||||
}
|
||||
|
||||
float Octree::OrthographicSelector::testThreshold(const Coord3f& point, float size) const {
|
||||
return (size * size) - squareMinSize;
|
||||
}
|
||||
|
||||
|
||||
const float Octree::INV_DEPTH_DIM[] = {
|
||||
1.0f,
|
||||
|
@ -520,10 +537,9 @@ int Octree::selectTraverse(Index cellID, CellSelection& selection, const Frustum
|
|||
|
||||
// Test for lod
|
||||
auto cellLocation = cell.getlocation();
|
||||
float lod = selector.testSolidAngle(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
||||
if (lod < 0.0f) {
|
||||
float test = selector.testThreshold(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
||||
if (test < 0.0f) {
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Select this cell partially in frustum
|
||||
|
@ -543,13 +559,13 @@ int Octree::selectTraverse(Index cellID, CellSelection& selection, const Frustum
|
|||
}
|
||||
|
||||
|
||||
int Octree::selectBranch(Index cellID, CellSelection& selection, const FrustumSelector& selector) const {
|
||||
int Octree::selectBranch(Index cellID, CellSelection& selection, const FrustumSelector& selector) const {
|
||||
int numSelectedsIn = (int) selection.size();
|
||||
auto cell = getConcreteCell(cellID);
|
||||
|
||||
auto cellLocation = cell.getlocation();
|
||||
float lod = selector.testSolidAngle(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
||||
if (lod < 0.0f) {
|
||||
float test = selector.testThreshold(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
||||
if (test < 0.0f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -580,24 +596,40 @@ int Octree::selectCellBrick(Index cellID, CellSelection& selection, bool inside)
|
|||
return (int) selection.size() - numSelectedsIn;
|
||||
}
|
||||
|
||||
|
||||
int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float lodAngle) const {
|
||||
int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float threshold) const {
|
||||
auto worldPlanes = frustum.getPlanes();
|
||||
FrustumSelector selector;
|
||||
for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) {
|
||||
::Plane octPlane;
|
||||
octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH));
|
||||
selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient());
|
||||
if (frustum.isPerspective()) {
|
||||
PerspectiveSelector selector;
|
||||
for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) {
|
||||
::Plane octPlane;
|
||||
octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH));
|
||||
selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient());
|
||||
}
|
||||
|
||||
selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH);
|
||||
selector.setAngle(threshold);
|
||||
|
||||
return Octree::select(selection, selector);
|
||||
} else {
|
||||
OrthographicSelector selector;
|
||||
for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) {
|
||||
::Plane octPlane;
|
||||
octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH));
|
||||
selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient());
|
||||
}
|
||||
|
||||
// Divide the threshold (which is in world distance units) by the dimension of the octree
|
||||
// as all further computations will be done in normalized octree units
|
||||
threshold *= getInvCellWidth(ROOT_DEPTH);
|
||||
selector.setSize(threshold);
|
||||
|
||||
return Octree::select(selection, selector);
|
||||
}
|
||||
|
||||
selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH);
|
||||
selector.setAngle(glm::radians(lodAngle));
|
||||
|
||||
return Octree::select(selection, selector);
|
||||
}
|
||||
|
||||
int ItemSpatialTree::selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, float lodAngle) const {
|
||||
selectCells(selection.cellSelection, frustum, lodAngle);
|
||||
int ItemSpatialTree::selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum,
|
||||
float threshold) const {
|
||||
selectCells(selection.cellSelection, frustum, threshold);
|
||||
|
||||
// Just grab the items in every selected bricks
|
||||
for (auto brickId : selection.cellSelection.insideBricks) {
|
||||
|
|
|
@ -312,23 +312,27 @@ namespace render {
|
|||
class FrustumSelector {
|
||||
public:
|
||||
Coord4f frustum[6];
|
||||
|
||||
virtual ~FrustumSelector() {}
|
||||
virtual float testThreshold(const Coord3f& point, float size) const = 0;
|
||||
};
|
||||
|
||||
class PerspectiveSelector : public FrustumSelector {
|
||||
public:
|
||||
Coord3f eyePos;
|
||||
float angle;
|
||||
float squareTanAlpha;
|
||||
|
||||
const float MAX_LOD_ANGLE = glm::radians(45.0f);
|
||||
const float MIN_LOD_ANGLE = glm::radians(1.0f / 60.0f);
|
||||
void setAngle(float a);
|
||||
float testThreshold(const Coord3f& point, float size) const override;
|
||||
};
|
||||
|
||||
void setAngle(float a) {
|
||||
angle = std::max(MIN_LOD_ANGLE, std::min(MAX_LOD_ANGLE, a));
|
||||
auto tanAlpha = tan(angle);
|
||||
squareTanAlpha = (float)(tanAlpha * tanAlpha);
|
||||
}
|
||||
class OrthographicSelector : public FrustumSelector {
|
||||
public:
|
||||
float squareMinSize;
|
||||
|
||||
float testSolidAngle(const Coord3f& point, float size) const {
|
||||
auto eyeToPoint = point - eyePos;
|
||||
return (size * size / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha;
|
||||
}
|
||||
void setSize(float a) { squareMinSize = a * a; }
|
||||
float testThreshold(const Coord3f& point, float size) const override;
|
||||
};
|
||||
|
||||
int select(CellSelection& selection, const FrustumSelector& selector) const;
|
||||
|
@ -443,7 +447,7 @@ namespace render {
|
|||
Index resetItem(Index oldCell, const ItemKey& oldKey, const AABox& bound, const ItemID& item, ItemKey& newKey);
|
||||
|
||||
// Selection and traverse
|
||||
int selectCells(CellSelection& selection, const ViewFrustum& frustum, float lodAngle) const;
|
||||
int selectCells(CellSelection& selection, const ViewFrustum& frustum, float threshold) const;
|
||||
|
||||
class ItemSelection {
|
||||
public:
|
||||
|
@ -469,7 +473,8 @@ namespace render {
|
|||
}
|
||||
};
|
||||
|
||||
int selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, float lodAngle) const;
|
||||
int selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum,
|
||||
float threshold) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -847,3 +847,7 @@ void ViewFrustum::tesselateSides(const glm::vec3 points[8], Triangle triangles[8
|
|||
triangle.v2 = points[vertexIndices[2]];
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewFrustum::isPerspective() const {
|
||||
return _projection[3][2] != 0.0f && _projection[2][3] != 0.0f && _projection[3][3] == 0.0f;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
// setters for lens attributes
|
||||
void setProjection(const glm::mat4 & projection);
|
||||
void setFocalLength(float focalLength) { _focalLength = focalLength; }
|
||||
bool isPerspective() const;
|
||||
|
||||
// getters for lens attributes
|
||||
const glm::mat4& getProjection() const { return _projection; }
|
||||
|
|
Loading…
Reference in a new issue