mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-29 22:22:54 +02: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._wrapModeU = Sampler::WRAP_BORDER;
|
||||||
samplerDesc._wrapModeV = Sampler::WRAP_BORDER;
|
samplerDesc._wrapModeV = Sampler::WRAP_BORDER;
|
||||||
samplerDesc._filter = Sampler::FILTER_MIN_MAG_LINEAR;
|
samplerDesc._filter = Sampler::FILTER_MIN_MAG_LINEAR;
|
||||||
samplerDesc._comparisonFunc = LESS_EQUAL;
|
samplerDesc._comparisonFunc = LESS;
|
||||||
|
|
||||||
depthTexture->setSampler(Sampler(samplerDesc));
|
depthTexture->setSampler(Sampler(samplerDesc));
|
||||||
framebuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
framebuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
||||||
|
|
|
@ -64,8 +64,14 @@ float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeSc
|
||||||
return voxelSizeScale / powf(2.0f, renderLevel);
|
return voxelSizeScale / powf(2.0f, renderLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) {
|
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) {
|
||||||
const float maxScale = (float)TREE_SCALE;
|
const float maxScale = (float)TREE_SCALE;
|
||||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
|
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
|
||||||
return atan(maxScale / visibleDistanceAtMaxScale);
|
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 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
|
// 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
|
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 setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup");
|
||||||
|
const auto queryResolution = setupOutput.getN<RenderShadowSetup::Outputs>(2);
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
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 shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowTree", fetchInput);
|
||||||
const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying();
|
const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying();
|
||||||
const auto shadowItems = task.addJob<FetchSpatialSelection>("FetchShadowSelection", selectionInputs);
|
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.edit0() = args->_renderMode;
|
||||||
output.edit1() = args->_sizeScale;
|
output.edit1() = args->_sizeScale;
|
||||||
|
output.edit2() = glm::ivec2(0, 0);
|
||||||
|
|
||||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||||
if (globalShadow) {
|
if (globalShadow) {
|
||||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
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;
|
unsigned int cascadeIndex;
|
||||||
_coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition());
|
|
||||||
_coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation());
|
|
||||||
|
|
||||||
// Adjust each cascade frustum
|
// Adjust each cascade frustum
|
||||||
for (cascadeIndex = 0; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
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,
|
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
|
||||||
bias._constant, bias._slope);
|
bias._constant, bias._slope);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now adjust coarse frustum bounds
|
// Now adjust coarse frustum bounds
|
||||||
auto left = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight());
|
auto frustumPosition = firstCascadeFrustum->getPosition();
|
||||||
auto right = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight());
|
auto farTopLeft = firstCascadeFrustum->getFarTopLeft() - frustumPosition;
|
||||||
auto top = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp());
|
auto farBottomRight = firstCascadeFrustum->getFarBottomRight() - frustumPosition;
|
||||||
auto bottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp());
|
|
||||||
|
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 near = firstCascadeFrustum->getNearClip();
|
||||||
auto far = firstCascadeFrustum->getFarClip();
|
auto far = firstCascadeFrustum->getFarClip();
|
||||||
|
|
||||||
for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
||||||
auto& cascadeFrustum = globalShadow->getCascade(cascadeIndex).getFrustum();
|
auto& cascadeFrustum = globalShadow->getCascade(cascadeIndex).getFrustum();
|
||||||
auto cascadeLeft = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getRight());
|
|
||||||
auto cascadeRight = glm::dot(cascadeFrustum->getFarTopRight(), cascadeFrustum->getRight());
|
farTopLeft = cascadeFrustum->getFarTopLeft() - frustumPosition;
|
||||||
auto cascadeTop = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getUp());
|
farBottomRight = cascadeFrustum->getFarBottomRight() - frustumPosition;
|
||||||
auto cascadeBottom = glm::dot(cascadeFrustum->getFarBottomRight(), cascadeFrustum->getUp());
|
|
||||||
|
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 cascadeNear = cascadeFrustum->getNearClip();
|
||||||
auto cascadeFar = cascadeFrustum->getFarClip();
|
auto cascadeFar = cascadeFrustum->getFarClip();
|
||||||
left = glm::min(left, cascadeLeft);
|
left = glm::min(left, cascadeLeft);
|
||||||
|
@ -319,6 +331,9 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
||||||
near = glm::min(near, cascadeNear);
|
near = glm::min(near, cascadeNear);
|
||||||
far = glm::max(far, cascadeFar);
|
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->setProjection(glm::ortho<float>(left, right, bottom, top, near, far));
|
||||||
_coarseShadowFrustum->calculate();
|
_coarseShadowFrustum->calculate();
|
||||||
|
|
||||||
|
@ -326,10 +341,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
||||||
args->pushViewFrustum(*_coarseShadowFrustum);
|
args->pushViewFrustum(*_coarseShadowFrustum);
|
||||||
|
|
||||||
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
|
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
|
// We want for the octree query enough resolution to catch the details in the lowest cascade. So compute
|
||||||
args->_sizeScale = 1e16f;
|
// 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 constantBias1{ 0.15f };
|
||||||
float constantBias2{ 0.15f };
|
float constantBias2{ 0.15f };
|
||||||
float constantBias3{ 0.15f };
|
float constantBias3{ 0.15f };
|
||||||
float slopeBias0{ 0.55f };
|
float slopeBias0{ 0.6f };
|
||||||
float slopeBias1{ 0.55f };
|
float slopeBias1{ 0.6f };
|
||||||
float slopeBias2{ 0.55f };
|
float slopeBias2{ 0.6f };
|
||||||
float slopeBias3{ 0.55f };
|
float slopeBias3{ 0.6f };
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dirty();
|
void dirty();
|
||||||
|
@ -82,7 +82,7 @@ signals:
|
||||||
|
|
||||||
class RenderShadowSetup {
|
class RenderShadowSetup {
|
||||||
public:
|
public:
|
||||||
using Outputs = render::VaryingSet2<RenderArgs::RenderMode, float>;
|
using Outputs = render::VaryingSet3<RenderArgs::RenderMode, float, glm::ivec2>;
|
||||||
using Config = RenderShadowSetupConfig;
|
using Config = RenderShadowSetupConfig;
|
||||||
using JobModel = render::Job::ModelO<RenderShadowSetup, Outputs, Config>;
|
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[2]) +
|
||||||
fetchShadow(cascadeIndex, shadowTexcoord.xyz + offsets.points[3])
|
fetchShadow(cascadeIndex, shadowTexcoord.xyz + offsets.points[3])
|
||||||
);
|
);
|
||||||
|
|
||||||
return shadowAttenuation;
|
return shadowAttenuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float oneMinusNdotL) {
|
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;
|
float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * oneMinusNdotL;
|
||||||
return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias);
|
return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isShadowCascadeProjectedOnPixel(vec4 cascadeTexCoords) {
|
bool isShadowCascadeProjectedOnPixel(vec4 cascadeTexCoords) {
|
||||||
bvec2 greaterThanZero = greaterThanEqual(cascadeTexCoords.xy, vec2(0));
|
bvec2 greaterThanZero = greaterThan(cascadeTexCoords.xy, vec2(0));
|
||||||
bvec2 lessThanOne = lessThanEqual(cascadeTexCoords.xy, vec2(1));
|
bvec2 lessThanOne = lessThan(cascadeTexCoords.xy, vec2(1));
|
||||||
return all(greaterThanZero) && all(lessThanOne);
|
return all(greaterThanZero) && all(lessThanOne);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <OctreeUtils.h>
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <OctreeUtils.h>
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ struct Test {
|
||||||
_renderDetails(renderDetails) {
|
_renderDetails(renderDetails) {
|
||||||
// FIXME: Keep this code here even though we don't use it yet
|
// FIXME: Keep this code here even though we don't use it yet
|
||||||
/*_eyePos = _args->getViewFrustum().getPosition();
|
/*_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
|
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
|
angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree
|
||||||
auto tanAlpha = tan(angle);
|
auto tanAlpha = tan(angle);
|
||||||
|
@ -130,7 +130,8 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu
|
||||||
// start fresh
|
// start fresh
|
||||||
outSelection.clear();
|
outSelection.clear();
|
||||||
|
|
||||||
auto& filter = inputs;
|
auto& filter = inputs.get0();
|
||||||
|
auto frustumResolution = inputs.get1();
|
||||||
|
|
||||||
if (!filter.selectsNothing()) {
|
if (!filter.selectsNothing()) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
|
@ -149,8 +150,19 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Octree selection!
|
// Octree selection!
|
||||||
float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
float threshold = 0.0f;
|
||||||
scene->getSpatialTree().selectCellItems(outSelection, filter, queryFrustum, angle);
|
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
|
// Now get the bound, and
|
||||||
// filter individually against the _filter
|
// filter individually against the _filter
|
||||||
|
|
||||||
// inside & fit items: filter only, culling is disabled
|
// inside & fit items: filter only
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("insideFitItems");
|
PerformanceTimer perfTimer("insideFitItems");
|
||||||
for (auto id : inSelection.insideItems) {
|
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");
|
PerformanceTimer perfTimer("insideSmallItems");
|
||||||
for (auto id : inSelection.insideSubcellItems) {
|
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");
|
PerformanceTimer perfTimer("partialFitItems");
|
||||||
for (auto id : inSelection.partialItems) {
|
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");
|
PerformanceTimer perfTimer("partialSmallItems");
|
||||||
for (auto id : inSelection.partialSubcellItems) {
|
for (auto id : inSelection.partialSubcellItems) {
|
||||||
|
|
|
@ -53,9 +53,10 @@ namespace render {
|
||||||
bool _justFrozeFrustum{ false };
|
bool _justFrozeFrustum{ false };
|
||||||
ViewFrustum _frozenFrustum;
|
ViewFrustum _frozenFrustum;
|
||||||
float _lodAngle;
|
float _lodAngle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Config = FetchSpatialTreeConfig;
|
using Config = FetchSpatialTreeConfig;
|
||||||
using Inputs = ItemFilter;
|
using Inputs = render::VaryingSet2<ItemFilter, glm::ivec2>;
|
||||||
using JobModel = Job::ModelIO<FetchSpatialTree, Inputs, ItemSpatialTree::ItemSelection, Config>;
|
using JobModel = Job::ModelIO<FetchSpatialTree, Inputs, ItemSpatialTree::ItemSelection, Config>;
|
||||||
|
|
||||||
FetchSpatialTree() {}
|
FetchSpatialTree() {}
|
||||||
|
|
|
@ -148,7 +148,7 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS
|
||||||
}
|
}
|
||||||
// Draw the LOD Reticle
|
// Draw the LOD Reticle
|
||||||
{
|
{
|
||||||
float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
float angle = glm::degrees(getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
|
||||||
Transform crosshairModel;
|
Transform crosshairModel;
|
||||||
crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1000.0));
|
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
|
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:
|
// CPU jobs:
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
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 spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", fetchInput);
|
||||||
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, render::Varying(filter)).asVarying();
|
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, render::Varying(filter)).asVarying();
|
||||||
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
|
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
|
||||||
|
|
|
@ -12,9 +12,26 @@
|
||||||
|
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace render;
|
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[] = {
|
const float Octree::INV_DEPTH_DIM[] = {
|
||||||
1.0f,
|
1.0f,
|
||||||
|
@ -520,10 +537,9 @@ int Octree::selectTraverse(Index cellID, CellSelection& selection, const Frustum
|
||||||
|
|
||||||
// Test for lod
|
// Test for lod
|
||||||
auto cellLocation = cell.getlocation();
|
auto cellLocation = cell.getlocation();
|
||||||
float lod = selector.testSolidAngle(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
float test = selector.testThreshold(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
||||||
if (lod < 0.0f) {
|
if (test < 0.0f) {
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select this cell partially in frustum
|
// Select this cell partially in frustum
|
||||||
|
@ -548,8 +564,8 @@ int Octree::selectBranch(Index cellID, CellSelection& selection, const FrustumS
|
||||||
auto cell = getConcreteCell(cellID);
|
auto cell = getConcreteCell(cellID);
|
||||||
|
|
||||||
auto cellLocation = cell.getlocation();
|
auto cellLocation = cell.getlocation();
|
||||||
float lod = selector.testSolidAngle(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
float test = selector.testThreshold(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth));
|
||||||
if (lod < 0.0f) {
|
if (test < 0.0f) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,10 +596,10 @@ int Octree::selectCellBrick(Index cellID, CellSelection& selection, bool inside)
|
||||||
return (int) selection.size() - numSelectedsIn;
|
return (int) selection.size() - numSelectedsIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float threshold) const {
|
||||||
int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float lodAngle) const {
|
|
||||||
auto worldPlanes = frustum.getPlanes();
|
auto worldPlanes = frustum.getPlanes();
|
||||||
FrustumSelector selector;
|
if (frustum.isPerspective()) {
|
||||||
|
PerspectiveSelector selector;
|
||||||
for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) {
|
for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) {
|
||||||
::Plane octPlane;
|
::Plane octPlane;
|
||||||
octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH));
|
octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH));
|
||||||
|
@ -591,13 +607,29 @@ int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& fr
|
||||||
}
|
}
|
||||||
|
|
||||||
selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH);
|
selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH);
|
||||||
selector.setAngle(glm::radians(lodAngle));
|
selector.setAngle(threshold);
|
||||||
|
|
||||||
return Octree::select(selection, selector);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ItemSpatialTree::selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, float lodAngle) const {
|
int ItemSpatialTree::selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum,
|
||||||
selectCells(selection.cellSelection, frustum, lodAngle);
|
float threshold) const {
|
||||||
|
selectCells(selection.cellSelection, frustum, threshold);
|
||||||
|
|
||||||
// Just grab the items in every selected bricks
|
// Just grab the items in every selected bricks
|
||||||
for (auto brickId : selection.cellSelection.insideBricks) {
|
for (auto brickId : selection.cellSelection.insideBricks) {
|
||||||
|
|
|
@ -312,23 +312,27 @@ namespace render {
|
||||||
class FrustumSelector {
|
class FrustumSelector {
|
||||||
public:
|
public:
|
||||||
Coord4f frustum[6];
|
Coord4f frustum[6];
|
||||||
|
|
||||||
|
virtual ~FrustumSelector() {}
|
||||||
|
virtual float testThreshold(const Coord3f& point, float size) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PerspectiveSelector : public FrustumSelector {
|
||||||
|
public:
|
||||||
Coord3f eyePos;
|
Coord3f eyePos;
|
||||||
float angle;
|
float angle;
|
||||||
float squareTanAlpha;
|
float squareTanAlpha;
|
||||||
|
|
||||||
const float MAX_LOD_ANGLE = glm::radians(45.0f);
|
void setAngle(float a);
|
||||||
const float MIN_LOD_ANGLE = glm::radians(1.0f / 60.0f);
|
float testThreshold(const Coord3f& point, float size) const override;
|
||||||
|
};
|
||||||
|
|
||||||
void setAngle(float a) {
|
class OrthographicSelector : public FrustumSelector {
|
||||||
angle = std::max(MIN_LOD_ANGLE, std::min(MAX_LOD_ANGLE, a));
|
public:
|
||||||
auto tanAlpha = tan(angle);
|
float squareMinSize;
|
||||||
squareTanAlpha = (float)(tanAlpha * tanAlpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
float testSolidAngle(const Coord3f& point, float size) const {
|
void setSize(float a) { squareMinSize = a * a; }
|
||||||
auto eyeToPoint = point - eyePos;
|
float testThreshold(const Coord3f& point, float size) const override;
|
||||||
return (size * size / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int select(CellSelection& selection, const FrustumSelector& selector) const;
|
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);
|
Index resetItem(Index oldCell, const ItemKey& oldKey, const AABox& bound, const ItemID& item, ItemKey& newKey);
|
||||||
|
|
||||||
// Selection and traverse
|
// 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 {
|
class ItemSelection {
|
||||||
public:
|
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]];
|
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
|
// setters for lens attributes
|
||||||
void setProjection(const glm::mat4 & projection);
|
void setProjection(const glm::mat4 & projection);
|
||||||
void setFocalLength(float focalLength) { _focalLength = focalLength; }
|
void setFocalLength(float focalLength) { _focalLength = focalLength; }
|
||||||
|
bool isPerspective() const;
|
||||||
|
|
||||||
// getters for lens attributes
|
// getters for lens attributes
|
||||||
const glm::mat4& getProjection() const { return _projection; }
|
const glm::mat4& getProjection() const { return _projection; }
|
||||||
|
|
Loading…
Reference in a new issue