Merge pull request #12565 from samcake/workload

Workload: Adding view setup job and more debugging tool
This commit is contained in:
Andrew Meadows 2018-03-06 13:23:17 -08:00 committed by GitHub
commit ad81fd54f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 594 additions and 127 deletions

View file

@ -4261,14 +4261,7 @@ void Application::idle() {
}
{
// TEMP HACK: one view with static radiuses
float r0 = 10.0f;
float r1 = 20.0f;
float r2 = 30.0f;
workload::Space::View view(_viewFrustum.getPosition(), r0, r1, r2);
std::vector<workload::Space::View> views;
views.push_back(view);
getEntities()->getWorkloadSpace()->setViews(views);
_gameWorkload.updateViews(_viewFrustum);
_gameWorkload._engine->run();
}
{

View file

@ -9,6 +9,7 @@
//
#include "GameWorkload.h"
#include "GameWorkloadRenderer.h"
#include <ViewFrustum.h>
GameWorkloadContext::GameWorkloadContext(const workload::SpacePointer& space, const render::ScenePointer& scene) : WorkloadContext(space), _scene(scene) {
}
@ -36,5 +37,9 @@ void GameWorkload::shutdown() {
_engine.reset();
}
void GameWorkload::updateViews(const ViewFrustum& frustum) {
workload::Views views;
views.emplace_back(workload::View::evalFromFrustum(frustum));
_engine->feedInput(views);
}

View file

@ -31,6 +31,8 @@ public:
void startup(const workload::SpacePointer& space, const render::ScenePointer& scene);
void shutdown();
void updateViews(const ViewFrustum& frustum);
workload::EnginePointer _engine;
};

View file

@ -16,11 +16,14 @@
#include <GeometryCache.h>
#include "render-utils/drawWorkloadProxy_vert.h"
#include "render-utils/drawWorkloadView_vert.h"
#include "render-utils/drawWorkloadProxy_frag.h"
void GameSpaceToRender::configure(const Config& config) {
_showAllProxies = config.showAllProxies;
_freezeViews = config.freezeViews;
_showAllProxies = config.showProxies;
_showAllViews = config.showViews;
}
void GameSpaceToRender::run(const workload::WorkloadContextPointer& runContext, Outputs& outputs) {
@ -33,7 +36,11 @@ void GameSpaceToRender::run(const workload::WorkloadContextPointer& runContext,
return;
}
auto visible = _showAllProxies;
auto visible = _showAllProxies || _showAllViews;
auto showProxies = _showAllProxies;
auto showViews = _showAllViews;
auto freezeViews = _freezeViews;
render::Transaction transaction;
auto scene = gameWorkloadContext->_scene;
@ -51,22 +58,30 @@ void GameSpaceToRender::run(const workload::WorkloadContextPointer& runContext,
std::vector<workload::Space::Proxy> proxies(space->getNumAllocatedProxies());
space->copyProxyValues(proxies.data(), (uint32_t)proxies.size());
workload::Views views(space->getNumViews());
if (!freezeViews) {
space->copyViews(views);
}
// Valid space, let's display its content
if (!render::Item::isValidID(_spaceRenderItemID)) {
_spaceRenderItemID = scene->allocateID();
auto renderItem = std::make_shared<GameWorkloadRenderItem>();
renderItem->editBound().setBox(glm::vec3(-100.0f), 200.0f);
renderItem->setVisible(visible);
renderItem->setAllProxies(proxies);
transaction.resetItem(_spaceRenderItemID, std::make_shared<GameWorkloadRenderItem::Payload>(renderItem));
} else {
transaction.updateItem<GameWorkloadRenderItem>(_spaceRenderItemID, [visible, proxies](GameWorkloadRenderItem& item) {
item.setVisible(visible);
item.setAllProxies(proxies);
});
}
transaction.updateItem<GameWorkloadRenderItem>(_spaceRenderItemID, [visible, showProxies, proxies, freezeViews, showViews, views](GameWorkloadRenderItem& item) {
item.setVisible(visible);
item.showProxies(showProxies);
item.setAllProxies(proxies);
item.showViews(showViews);
if (!freezeViews) {
item.setAllViews(views);
}
});
scene->enqueueTransaction(transaction);
}
@ -109,6 +124,15 @@ void GameWorkloadRenderItem::setVisible(bool isVisible) {
}
}
void GameWorkloadRenderItem::showProxies(bool show) {
_showProxies = show;
}
void GameWorkloadRenderItem::showViews(bool show) {
_showViews = show;
}
void GameWorkloadRenderItem::setAllProxies(const std::vector<workload::Space::Proxy>& proxies) {
_myOwnProxies = proxies;
static const uint32_t sizeOfProxy = sizeof(workload::Space::Proxy);
@ -120,7 +144,18 @@ void GameWorkloadRenderItem::setAllProxies(const std::vector<workload::Space::Pr
_numAllProxies = (uint32_t) proxies.size();
}
const gpu::PipelinePointer GameWorkloadRenderItem::getPipeline() {
void GameWorkloadRenderItem::setAllViews(const workload::Views& views) {
_myOwnViews = views;
static const uint32_t sizeOfView = sizeof(workload::View);
if (!_allViewsBuffer) {
_allViewsBuffer = std::make_shared<gpu::Buffer>(sizeOfView);
}
_allViewsBuffer->setData(views.size() * sizeOfView, (const gpu::Byte*) views.data());
_numAllViews = (uint32_t)views.size();
}
const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
if (!_drawAllProxiesPipeline) {
auto vs = drawWorkloadProxy_vert::getShader();
auto ps = drawWorkloadProxy_frag::getShader();
@ -143,27 +178,56 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getPipeline() {
return _drawAllProxiesPipeline;
}
const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
if (!_drawAllViewsPipeline) {
auto vs = drawWorkloadView_vert::getShader();
auto ps = drawWorkloadProxy_frag::getShader();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("workloadViewsBuffer", 1));
gpu::Shader::makeProgram(*program, slotBindings);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
/* state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);*/
PrepareStencil::testMaskDrawShape(*state);
state->setCullMode(gpu::State::CULL_NONE);
_drawAllViewsPipeline = gpu::Pipeline::create(program, state);
}
return _drawAllViewsPipeline;
}
void GameWorkloadRenderItem::render(RenderArgs* args) {
gpu::Batch& batch = *(args->_batch);
// Setup projection
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
batch.setModelTransform(Transform());
// Bind program
batch.setPipeline(getPipeline());
batch.setResourceBuffer(0, _allProxiesBuffer);
batch.setResourceBuffer(1, _allViewsBuffer);
static const int NUM_VERTICES_PER_QUAD = 3;
batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_QUAD * _numAllProxies, 0);
// Show Proxies
if (_showProxies) {
batch.setPipeline(getProxiesPipeline());
static const int NUM_VERTICES_PER_PROXY = 3;
batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_PROXY * _numAllProxies, 0);
}
// Show Views
if (_showViews) {
batch.setPipeline(getViewsPipeline());
static const int NUM_VERTICES_PER_VIEW = 27;
batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_VIEW * _numAllViews, 0);
}
batch.setResourceBuffer(0, nullptr);
batch.setResourceBuffer(1, nullptr);
batch.setResourceBuffer(11, nullptr);
}

View file

@ -14,10 +14,14 @@
class GameSpaceToRenderConfig : public workload::Job::Config {
Q_OBJECT
Q_PROPERTY(bool showAllProxies MEMBER showAllProxies NOTIFY dirty)
Q_PROPERTY(bool freezeViews MEMBER freezeViews NOTIFY dirty)
Q_PROPERTY(bool showProxies MEMBER showProxies NOTIFY dirty)
Q_PROPERTY(bool showViews MEMBER showViews NOTIFY dirty)
public:
bool showAllProxies{ false };
bool freezeViews{ false };
bool showProxies{ false };
bool showViews{ false };
signals:
void dirty();
@ -37,7 +41,9 @@ public:
protected:
render::ItemID _spaceRenderItemID{ render::Item::INVALID_ITEM_ID };
bool _freezeViews{ false };
bool _showAllProxies{ false };
bool _showAllViews{ false };
};
@ -50,12 +56,15 @@ public:
~GameWorkloadRenderItem() {}
void render(RenderArgs* args);
render::Item::Bound& editBound() { _needUpdate = true; return _bound; }
render::Item::Bound& editBound() { return _bound; }
const render::Item::Bound& getBound() { return _bound; }
void setVisible(bool visible);
void showProxies(bool show);
void showViews(bool show);
void setAllProxies(const std::vector<workload::Space::Proxy>& proxies);
void setAllViews(const workload::Views& views);
render::ItemKey getKey() const;
@ -66,12 +75,19 @@ protected:
gpu::BufferPointer _allProxiesBuffer;
uint32_t _numAllProxies{ 0 };
workload::Views _myOwnViews;
gpu::BufferPointer _allViewsBuffer;
uint32_t _numAllViews{ 0 };
gpu::PipelinePointer _drawAllProxiesPipeline;
const gpu::PipelinePointer getPipeline();
const gpu::PipelinePointer getProxiesPipeline();
gpu::PipelinePointer _drawAllViewsPipeline;
const gpu::PipelinePointer getViewsPipeline();
render::ItemKey _key;
bool _needUpdate{ true };
bool _isVisible{ true };
bool _showProxies{ true };
bool _showViews{ true };
};
namespace render {

View file

@ -14,10 +14,10 @@
<@include gpu/Paint.slh@>
in vec4 varColor;
in vec2 varTexcoord;
in vec3 varTexcoord;
void main(void) {
float r = sqrt(dot(varTexcoord.xy,varTexcoord.xy));
float r = sqrt(dot(varTexcoord.xyz,varTexcoord.xyz));
float a = paintStripe(r * varColor.w, 0.0, 1.0 / varColor.w, 0.05 / varColor.w);
if (a <= 0.1 || r > 1.1) {
discard;

View file

@ -48,7 +48,7 @@ WorkloadProxy getWorkloadProxy(int i) {
out vec4 varColor;
out vec2 varTexcoord;
out vec3 varTexcoord;
void main(void) {
const vec4 UNIT_SPRITE[3] = vec4[3](
@ -80,7 +80,7 @@ void main(void) {
// vec3 dirY = normalize(cross(dirZ, vec3(1.0, 0.0, 0.0)));
vec4 pos = vec4(proxyPosEye.xyz + proxy.sphere.w * ( dirX * spriteVert.x + dirY * spriteVert.y /* + dirZ * spriteVert.z*/), 1.0);
varTexcoord = spriteVert.xy;
varTexcoord = spriteVert.xyz;
<$transformEyeToClipPos(cam, pos, gl_Position)$>
// Convert region to color

View file

@ -0,0 +1,121 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// drawItemBounds.slv
// vertex shader
//
// Created by Sam Gateau on 6/29/2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include gpu/Color.slh@>
<$declareColorWheel()$>
uniform vec4 inColor;
struct WorkloadView {
vec4 direction_far;
vec4 fov;
vec4 origin;
vec4 regions[3];
};
#if defined(GPU_GL410)
uniform samplerBuffer workloadViewsBuffer;
WorkloadView getWorkloadView(int i) {
int offset = 2 * i;
WorkloadView view;
view.origin = texelFetch(workloadViewsBuffer, offset);
view.radiuses = texelFetch(workloadViewsBuffer, offset + 1);
return view;
}
#else
layout(std140) buffer workloadViewsBuffer {
WorkloadView _views[];
};
WorkloadView getWorkloadView(int i) {
WorkloadView view = _views[i];
return view;
}
#endif
out vec4 varColor;
out vec3 varTexcoord;
const int NUM_VERTICES_PER_VIEW = 27;
const int NUM_REGIONS_PER_VIEW = 3;
const int NUM_VERTICES_PER_VIEW_REGION = NUM_VERTICES_PER_VIEW / NUM_REGIONS_PER_VIEW;
void main(void) {
const vec4 UNIT_SPRITE[NUM_VERTICES_PER_VIEW_REGION] = vec4[NUM_VERTICES_PER_VIEW_REGION](
vec4(-1.0, -1.0, 0.0, 1.0),
vec4(3.0, -1.0, 0.0, 1.0),
vec4(-1.0, 3.0, 0.0, 1.0),
vec4(-1.0, 0.0, -1.0, 1.0),
vec4(3.0, 0.0, -1.0, 1.0),
vec4(-1.0, 0.0, 3.0, 1.0),
vec4(0.0, -1.0, -1.0, 1.0),
vec4(0.0, 3.0, -1.0, 1.0),
vec4(0.0, -1.0, 3.0, 1.0)
);
const int UNIT_SPRITE_INDICES[NUM_VERTICES_PER_VIEW_REGION] = int[NUM_VERTICES_PER_VIEW_REGION](
0, 1, 2, 3, 4, 5, 6, 7, 8
);
int viewID = gl_VertexID / NUM_VERTICES_PER_VIEW;
int viewVertexID = gl_VertexID - viewID * NUM_VERTICES_PER_VIEW;
int regionID = viewVertexID / NUM_VERTICES_PER_VIEW_REGION;
int regionVertexID = viewVertexID - regionID * NUM_VERTICES_PER_VIEW_REGION;
int vertexID = regionVertexID;
vec4 spriteVert = UNIT_SPRITE[UNIT_SPRITE_INDICES[vertexID]];
WorkloadView view = getWorkloadView(viewID);
vec4 region = view.regions[regionID];
vec4 proxyPosWorld = vec4(region.xyz, 1.0);
// standard transform, bring proxy in view space
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
vec4 proxyPosEye;
<$transformModelToEyePos(cam, obj, proxyPosWorld, proxyPosEye)$>
// Define the billboarded space
vec3 dirZ = vec3(0.0, 0.0, 1.0);
vec3 dirX = vec3(1.0, 0.0, 0.0);
vec3 dirY = vec3(0.0, 1.0, 0.0);
/*normalize(cross(vec3(0.0, 1.0, 0.0), dirZ));
if (dot(proxyPosEye.xyz, proxyPosEye.xyz) > 0.01) {
dirZ = -normalize(proxyPosEye.xyz);
}
vec3 dirX = normalize(cross(vec3(0.0, 1.0, 0.0), dirZ));
vec3 dirY = normalize(cross(dirZ, dirX));
*/
float regionRadius = region.w;
vec3 originSpaceVert = dirY * (-0.02) + regionRadius * ( dirX * spriteVert.x + dirY * spriteVert.y + dirZ * spriteVert.z);
vec4 pos = vec4(proxyPosEye.xyz + originSpaceVert, 1.0);
varTexcoord = spriteVert.xyz;
<$transformEyeToClipPos(cam, pos, gl_Position)$>
// Convert region to color
varColor = vec4(colorWheel(float(regionID) / 4.0), regionRadius);
}

View file

@ -78,6 +78,7 @@ public:
virtual const Varying getInput() const { return Varying(); }
virtual const Varying getOutput() const { return Varying(); }
virtual Varying& editInput() = 0;
virtual QConfigPointer& getConfiguration() { return _config; }
virtual void applyConfiguration() = 0;
@ -141,6 +142,7 @@ public:
const Varying getInput() const override { return _input; }
const Varying getOutput() const override { return _output; }
Varying& editInput() override { return _input; }
template <class... A>
Model(const Varying& input, QConfigPointer config, A&&... args) :
@ -177,6 +179,10 @@ public:
const Varying getInput() const { return _concept->getInput(); }
const Varying getOutput() const { return _concept->getOutput(); }
template <class I> void feedInput(const I& in) { _concept->editInput().template edit<I>() = in; }
QConfigPointer& getConfiguration() const { return _concept->getConfiguration(); }
void applyConfiguration() { return _concept->applyConfiguration(); }
@ -240,6 +246,8 @@ public:
const Varying getInput() const override { return _input; }
const Varying getOutput() const override { return _output; }
Varying& editInput() override { return _input; }
typename Jobs::iterator editJob(std::string name) {
typename Jobs::iterator jobIt;
for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) {

View file

@ -23,10 +23,10 @@ void ClassificationTracker::run(const WorkloadContextPointer& context, Outputs&
if (space) {
Changes changes;
space->categorizeAndGetChanges(changes);
outputs.resize(workload::Space::NUM_TRANSITIONS);
outputs.resize(workload::Region::NUM_TRANSITIONS);
for (uint32_t i = 0; i < changes.size(); ++i) {
int32_t j = Space::computeTransitionIndex(changes[i].prevRegion, changes[i].region);
assert(j >= 0 && j < workload::Space::NUM_TRANSITIONS);
int32_t j = Region::computeTransitionIndex(changes[i].prevRegion, changes[i].region);
assert(j >= 0 && j < workload::Region::NUM_TRANSITIONS);
outputs[j].push_back(changes[i].proxyId);
}
}

View file

@ -16,23 +16,45 @@
#include <iostream>
#include "ViewTask.h"
#include "ClassificationTracker.h"
namespace workload {
class DebugCout {
public:
using Inputs = SortedChanges;
using JobModel = workload::Job::ModelI<DebugCout, Inputs>;
DebugCout() {}
void run(const workload::WorkloadContextPointer& renderContext, const Inputs& inputs) {
qDebug() << "Some message from " << inputs.size();
int i = 0;
for (auto& b: inputs) {
qDebug() << " Bucket Number" << i << " size is " << b.size();
i++;
}
}
protected:
};
WorkloadContext::WorkloadContext(const SpacePointer& space) : task::JobContext(trace_workload()), _space(space) {}
using EngineModel = Task::Model<class EngineBuilder>;
class EngineBuilder {
public:
using JobModel = Task::Model<EngineModel>;
void build(EngineModel& model, const Varying& in, Varying& out) {
auto classifications = model.addJob<ClassificationTracker>("classificationTracker");
using Inputs = Views;
using JobModel = Task::ModelI<EngineBuilder, Inputs>;
void build(JobModel& model, const Varying& in, Varying& out) {
model.addJob<SetupViews>("setupViews", in);
const auto classifications = model.addJob<ClassificationTracker>("classificationTracker");
// model.addJob<DebugCout>("debug", classifications);
}
};
Engine::Engine(const WorkloadContextPointer& context) : Task("Engine", EngineModel::create()),
Engine::Engine(const WorkloadContextPointer& context) : Task("Engine", EngineBuilder::JobModel::create()),
_context(context) {
}
} // namespace workload

View file

@ -0,0 +1,74 @@
//
// Region.h
// libraries/workload/src/workload
//
// Created by Sam Gateau 2018.03.05
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_workload_Region_h
#define hifi_workload_Region_h
namespace workload {
class Region {
public:
using Type = uint8_t;
enum Name : uint8_t {
R1 = 0,
R2,
R3,
UNKNOWN,
INVALID,
};
static const uint8_t NUM_CLASSIFICATIONS = 4;
static const uint8_t NUM_TRANSITIONS = NUM_CLASSIFICATIONS * (NUM_CLASSIFICATIONS - 1);
static const uint8_t NUM_VIEW_REGIONS = (NUM_CLASSIFICATIONS - 1);
static uint8_t computeTransitionIndex(uint8_t prevIndex, uint8_t newIndex);
};
inline uint8_t Region::computeTransitionIndex(uint8_t prevIndex, uint8_t newIndex) {
// given prevIndex and newIndex compute an index into the transition list,
// where the lists between unchanged indices don't exist (signaled by index = -1).
//
// Given an NxN array
// let p = i + N * j
//
// then k = -1 when i == j
// = p - (1 + p/(N+1)) when i != j
//
// i 0 1 2 3
// j +-------+-------+-------+-------+
// |p = 0 | 1 | 2 | 3 |
// 0 | | | | |
// |k = -1 | 0 | 1 | 2 |
// +-------+-------+-------+-------+
// | 4 | 5 | 6 | 7 |
// 1 | | | | |
// | 3 | -1 | 4 | 5 |
// +-------+-------+-------+-------+
// | 8 | 9 | 10 | 11 |
// 2 | | | | |
// | 6 | 7 | -1 | 8 |
// +-------+-------+-------+-------+
// | 12 | 13 | 14 | 15 |
// 3 | | | | |
// | 9 | 10 | 11 | -1 |
// +-------+-------+-------+-------+
uint8_t p = prevIndex + Region::NUM_CLASSIFICATIONS * newIndex;
if (0 == (p % (Region::NUM_CLASSIFICATIONS + 1))) {
return -1;
}
return p - (1 + p / (Region::NUM_CLASSIFICATIONS + 1));
}
} // namespace workload
#endif // hifi_workload_Region_h

View file

@ -33,8 +33,8 @@ int32_t Space::createProxy(const Space::Sphere& newSphere) {
int32_t index = _freeIndices.back();
_freeIndices.pop_back();
_proxies[index].sphere = newSphere;
_proxies[index].region = Space::REGION_UNKNOWN;
_proxies[index].prevRegion = Space::REGION_UNKNOWN;
_proxies[index].region = Region::UNKNOWN;
_proxies[index].prevRegion = Region::UNKNOWN;
return index;
}
}
@ -54,24 +54,39 @@ void Space::updateProxies(const std::vector<ProxyUpdate>& changedProxies) {
}
}
void Space::setViews(const std::vector<Space::View>& views) {
void Space::setViews(const Views& views) {
_views = views;
}
void Space::copyViews(std::vector<View>& copy) const {
copy = _views;
}
// TODO?: move this to an algorithm/job?
void Space::categorizeAndGetChanges(std::vector<Space::Change>& changes) {
uint32_t numProxies = (uint32_t)_proxies.size();
uint32_t numViews = (uint32_t)_views.size();
for (uint32_t i = 0; i < numProxies; ++i) {
Proxy& proxy = _proxies[i];
if (proxy.region < Space::REGION_INVALID) {
uint8_t region = Space::REGION_UNKNOWN;
if (proxy.region < Region::INVALID) {
uint8_t region = Region::UNKNOWN;
for (uint32_t j = 0; j < numViews; ++j) {
float distance2 = glm::distance2(_views[j].center, glm::vec3(_proxies[i].sphere));
for (uint8_t c = 0; c < region; ++c) {
float touchDistance = _views[j].radiuses[c] + _proxies[i].sphere.w;
if (distance2 < touchDistance * touchDistance) {
region = c;
auto& view = _views[j];
glm::vec3 distance2(glm::distance2(proxy.sphere, view.regions[0]), glm::distance2(proxy.sphere, view.regions[1]), glm::distance2(proxy.sphere, view.regions[2]));
glm::vec3 regionRadii2(view.regions[0].w + proxy.sphere.w, view.regions[1].w + proxy.sphere.w, view.regions[2].w + proxy.sphere.w);
regionRadii2 *= regionRadii2;
auto touchTests = glm::lessThanEqual(distance2, regionRadii2);
if (glm::any(touchTests)) {
if (touchTests.x) {
region = Region::R1;
break;
} else if (touchTests.y) {
region = Region::R2;
break;
} else {
region = Region::R3;
break;
}
}
@ -100,13 +115,13 @@ void Space::deleteProxy(int32_t proxyId) {
}
}
} else {
_proxies[proxyId].region = Space::REGION_INVALID;
_proxies[proxyId].region = Region::INVALID;
_freeIndices.push_back(proxyId);
}
}
}
uint32_t Space::copyProxyValues(Proxy* proxies, uint32_t numDestProxies) {
uint32_t Space::copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const {
auto numCopied = std::min(numDestProxies, (uint32_t)_proxies.size());
memcpy(proxies, _proxies.data(), numCopied * sizeof(Proxy));

View file

@ -19,22 +19,13 @@
#include <vector>
#include <glm/glm.hpp>
#include "View.h"
namespace workload {
class Space {
public:
static const int32_t NUM_CLASSIFICATIONS = 4;
static const int32_t NUM_TRANSITIONS = NUM_CLASSIFICATIONS * (NUM_CLASSIFICATIONS - 1);
static int32_t computeTransitionIndex(int32_t prevIndex, int32_t newIndex);
static const uint8_t REGION_NEAR = 0;
static const uint8_t REGION_MIDDLE = 1;
static const uint8_t REGION_FAR = 2;
static const uint8_t REGION_UNKNOWN = 3;
static const uint8_t REGION_INVALID = 4;
using Sphere = glm::vec4; // <x,y,z> = center, w = radius
using ProxyUpdate = std::pair<int32_t, Sphere>;
@ -43,23 +34,12 @@ public:
Proxy() : sphere(0.0f) {}
Proxy(const Sphere& s) : sphere(s) {}
Sphere sphere;
uint8_t region { REGION_UNKNOWN };
uint8_t prevRegion { REGION_UNKNOWN };
uint8_t region { Region::UNKNOWN };
uint8_t prevRegion { Region::UNKNOWN };
uint16_t _padding;
uint32_t _paddings[3];
};
class View {
public:
View(const glm::vec3& pos, float nearRadius, float midRadius, float farRadius) : center(pos) {
radiuses[REGION_NEAR] = nearRadius;
radiuses[REGION_MIDDLE] = midRadius;
radiuses[REGION_FAR] = farRadius;
}
glm::vec3 center;
float radiuses[NUM_CLASSIFICATIONS - 1];
};
class Change {
public:
Change(int32_t i, uint32_t c, uint32_t p) : proxyId(i), region(c), prevRegion(p) {}
@ -76,56 +56,25 @@ public:
void updateProxies(const std::vector<ProxyUpdate>& changedProxies);
void setViews(const std::vector<View>& views);
uint32_t getNumViews() const { return (uint32_t)(_views.size()); }
void copyViews(std::vector<View>& copy) const;
uint32_t getNumObjects() const { return (uint32_t)(_proxies.size() - _freeIndices.size()); }
uint32_t getNumAllocatedProxies() const { return (uint32_t)(_proxies.size()); }
void categorizeAndGetChanges(std::vector<Change>& changes);
uint32_t copyProxyValues(Proxy* proxies, uint32_t numDestProxies);
uint32_t copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const;
private:
void deleteProxy(int32_t proxyId);
void updateProxy(int32_t proxyId, const Sphere& sphere);
std::vector<Proxy> _proxies;
std::vector<View> _views;
Views _views;
std::vector<int32_t> _freeIndices;
};
inline int32_t Space::computeTransitionIndex(int32_t prevIndex, int32_t newIndex) {
// given prevIndex and newIndex compute an index into the transition list,
// where the lists between unchanged indices don't exist (signaled by index = -1).
//
// Given an NxN array
// let p = i + N * j
//
// then k = -1 when i == j
// = p - (1 + p/(N+1)) when i != j
//
// i 0 1 2 3
// j +-------+-------+-------+-------+
// |p = 0 | 1 | 2 | 3 |
// 0 | | | | |
// |k = -1 | 0 | 1 | 2 |
// +-------+-------+-------+-------+
// | 4 | 5 | 6 | 7 |
// 1 | | | | |
// | 3 | -1 | 4 | 5 |
// +-------+-------+-------+-------+
// | 8 | 9 | 10 | 11 |
// 2 | | | | |
// | 6 | 7 | -1 | 8 |
// +-------+-------+-------+-------+
// | 12 | 13 | 14 | 15 |
// 3 | | | | |
// | 9 | 10 | 11 | -1 |
// +-------+-------+-------+-------+
int32_t p = prevIndex + Space::NUM_CLASSIFICATIONS * newIndex;
if (0 == (p % (Space::NUM_CLASSIFICATIONS + 1))) {
return -1;
}
return p - (1 + p / (Space::NUM_CLASSIFICATIONS + 1));
}
using SpacePointer = std::shared_ptr<Space>;
using Changes = std::vector<Space::Change>;
using SortedChanges = std::vector<std::vector<int32_t>>;

View file

@ -0,0 +1,48 @@
//
// View.cpp
// libraries/workload/src/workload
//
// Created by Sam Gateau 2018.03.05
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "View.h"
#include <ViewFrustum.h>
using namespace workload;
void View::setFov(float angleRad) {
float halfAngle = angleRad * 0.5f;
fov_halfAngle_tan_cos_sin.x = halfAngle;
fov_halfAngle_tan_cos_sin.y = tanf(halfAngle);
fov_halfAngle_tan_cos_sin.z = cosf(halfAngle);
fov_halfAngle_tan_cos_sin.w = sinf(halfAngle);
}
View View::evalFromFrustum(const ViewFrustum& frustum) {
View view;
view.origin = frustum.getPosition();
view.direction = frustum.getDirection();
view.setFov(frustum.getFieldOfView());
return view;
}
Sphere View::evalRegionSphere(const View& view, float originRadius, float maxDistance) {
float radius = (maxDistance + originRadius) / 2.0f;
float center = radius - originRadius;
return Sphere(view.origin + view.direction * center, radius);
}
void View::updateRegions(View& view) {
float refFar = 10.0f;
float refClose = 2.0f;
for (int i = 0; i < Region::NUM_VIEW_REGIONS; i++) {
float weight = i + 1.0f;
view.regions[i] = evalRegionSphere(view, refClose * weight, refFar * weight);
refFar *= 2.0f;
}
}

View file

@ -0,0 +1,66 @@
//
// View.h
// libraries/workload/src/workload
//
// Created by Sam Gateau 2018.03.05
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_workload_View_h
#define hifi_workload_View_h
#include <memory>
#include <vector>
#include <glm/glm.hpp>
#include "Region.h"
class ViewFrustum;
namespace workload {
using Sphere = glm::vec4;
class View {
public:
View() = default;
View(const View& view) = default;
// View attributes:
// direction
glm::vec3 direction{ 0.0f, 0.0f, -1.0f };
// Max radius
float maxRadius{ FLT_MAX };
// Fov stores the half field of view angle, and tan/cos/sin ready to go, default is fov of 90deg
glm::vec4 fov_halfAngle_tan_cos_sin { (float) M_PI_4, 1.0f, (float) (M_SQRT2 * 0.5), (float) (M_SQRT2 * 0.5) };
// Origin position
glm::vec3 origin{ 0.0f };
// Origin radius
float originRadius{ 0.5f };
// N regions spheres
Sphere regions[Region::NUM_VIEW_REGIONS];
// Set fov properties from angle
void setFov(float angleRad);
static View evalFromFrustum(const ViewFrustum& frustum);
static Sphere evalRegionSphere(const View& view, float originRadius, float maxDistance);
static void updateRegions(View& view);
};
using Views = std::vector<View>;
} // namespace workload
#endif // hifi_workload_View_h

View file

@ -0,0 +1,28 @@
//
// ViewTask.cpp
// libraries/workload/src/workload
//
// Created by Sam Gateau 2018.03.05
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ViewTask.h"
using namespace workload;
void SetupViews::configure(const Config& config) {
}
void SetupViews::run(const WorkloadContextPointer& renderContext, const Input& inputs) {
Views views = inputs;
for (auto& v : views) {
View::updateRegions(v);
}
renderContext->_space->setViews(views);
}

View file

@ -0,0 +1,35 @@
//
// ViewTask.h
// libraries/workload/src/workload
//
// Created by Sam Gateau 2018.03.05
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_workload_ViewTask_h
#define hifi_workload_ViewTask_h
#include "Engine.h"
namespace workload {
class SetupViewsConfig : public Job::Config{
Q_OBJECT
public:
SetupViewsConfig() : Job::Config(true) {}
};
class SetupViews {
public:
using Config = SetupViewsConfig;
using Input = Views;
using JobModel = Job::ModelI<SetupViews, Input, Config>;
void configure(const Config& config);
void run(const workload::WorkloadContextPointer& renderContext, const Input& inputs);
};
} // namespace workload
#endif // hifi_workload_ViewTask_h

View file

@ -21,6 +21,7 @@ Rectangle {
anchors.margins: hifi.dimensions.contentMargin.x
color: hifi.colors.baseGray;
property var setupViews: Workload.getConfig("setupViews")
property var spaceToRender: Workload.getConfig("SpaceToRender")
Column {
@ -30,11 +31,31 @@ Rectangle {
anchors.margins: hifi.dimensions.contentMargin.x
//padding: hifi.dimensions.contentMargin.x
HifiControls.Label {
text: "Workload"
}
HifiControls.CheckBox {
boxSize: 20
text: "Show All Proxies"
checked: workload.spaceToRender["showAllProxies"]
onCheckedChanged: { workload.spaceToRender["showAllProxies"] = checked }
text: "Freeze Views"
checked: workload.spaceToRender["freezeViews"]
onCheckedChanged: { workload.spaceToRender["freezeViews"] = checked, workload.setupViews.enabled = !checked; }
}
Separator {}
HifiControls.Label {
text: "Display"
}
HifiControls.CheckBox {
boxSize: 20
text: "Show Proxies"
checked: workload.spaceToRender["showProxies"]
onCheckedChanged: { workload.spaceToRender["showProxies"] = checked }
}
HifiControls.CheckBox {
boxSize: 20
text: "Show Views"
checked: workload.spaceToRender["showViews"]
onCheckedChanged: { workload.spaceToRender["showViews"] = checked }
}
Separator {}
}
}